pax_global_header00006660000000000000000000000064135370575320014524gustar00rootroot0000000000000052 comment=1c6ad44ebb4161bb93f5afbd3bf6ae7318dc2f23 mir-core-1.0.2/000077500000000000000000000000001353705753200132415ustar00rootroot00000000000000mir-core-1.0.2/.gitignore000066400000000000000000000003321353705753200152270ustar00rootroot00000000000000*.a *.log *.lst *.o *.pdf *.s *.exe *.sublime-project *.sublime-workspace .dub .generated .vscode __* dub.selections.json web .DS_* docs *.html docs.json out/ build/ files *.lib mir-core-test-library bench_ldexp_frexp mir-core-1.0.2/.travis.yml000066400000000000000000000024321353705753200153530ustar00rootroot00000000000000language: d sudo: required packages: - pkg-config d: - gdc - ldc - ldc-beta - dmd-nightly - dmd-beta - dmd branches: only: - master env: - ARCH="x86_64" matrix: include: - {os: linux, d: ldc-beta, env: ARCH="x86", addons: {apt: {packages: [[gcc-multilib]]}}} - {os: linux, d: ldc, env: ARCH="x86", addons: {apt: {packages: [[gcc-multilib]]}}} - {os: linux, d: dmd-beta, env: ARCH="x86", addons: {apt: {packages: [[gcc-multilib]]}}} - {os: linux, d: dmd, env: ARCH="x86", addons: {apt: {packages: [[gcc-multilib]]}}} allow_failures: - {d: dmd-nightly} - {d: ldc-beta} - {d: gdc} install: - curl -L "https://github.com/ninja-build/ninja/releases/download/v1.7.2/ninja-linux.zip" -o ninja-linux.zip - sudo unzip ninja-linux.zip -d /usr/local/bin - sudo chmod 755 /usr/local/bin/ninja - sudo add-apt-repository -y ppa:deadsnakes/ppa - sudo apt-get -y update - sudo apt-get -y install python3.6 - curl https://bootstrap.pypa.io/get-pip.py | sudo python3.6 - sudo pip3 install meson script: - dub test --arch "$ARCH" --build=unittest-cov - ./test_examples.sh - meson build -D with_test=true && cd build && ninja -j4 && ninja -j4 test -v && cd .. # TODO: 32bit meson test after_success: - bash <(curl -s https://codecov.io/bash) mir-core-1.0.2/LICENSE000066400000000000000000000024721353705753200142530ustar00rootroot00000000000000Boost Software License - Version 1.0 - August 17th, 2003 Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. mir-core-1.0.2/README.md000066400000000000000000000002751353705753200145240ustar00rootroot00000000000000Mir Core ============== Base software building blocks and conventions. #### Code Constraints 1. generic code only 2. no runtime dependency (betterC compatible) 3. no complex algorithms mir-core-1.0.2/bench_ldexp_frexp.d000066400000000000000000000035371353705753200170750ustar00rootroot00000000000000/+ dub.sdl: dependency "mir-core" path="./" +/ import std.stdio; import std.meta; import std.datetime.stopwatch; enum size_t length = 256; void main() { test!float; test!double; test!real; } void test(T)() { static __gshared T[length] x, y; static __gshared int[length] z; static __gshared int exp_common; foreach(i; 0 .. length) { x[i] = i + 1 / T(i); y[i] = i - 100; } auto res = benchmark!( (){ foreach(i; 0 .. length) y[i] = x[i] * z[i]; }, (){ import mir.math; foreach(i; 0 .. length) y[i] = ldexp(x[i], z[i]); }, (){ import std.math; foreach(i; 0 .. length) y[i] = ldexp(x[i], z[i]); }, (){ import core.stdc.tgmath; foreach(i; 0 .. length) y[i] = ldexp(x[i], z[i]); }, (){ import mir.math; foreach(i; 0 .. length) y[i] = frexp(x[i], exp_common); }, (){ import std.math; foreach(i; 0 .. length) y[i] = frexp(x[i], exp_common); }, (){ import core.stdc.tgmath; foreach(i; 0 .. length) y[i] = frexp(x[i], &exp_common); }, )(100_000); writeln("---------------------------"); writeln("++++ ", T.stringof, " ++++"); writeln("ldexp (Phobos time / Mir time) = ", double(res[2].total!"usecs") / res[1].total!"usecs"); writeln("ldexp ( stdc time / Mir time) = ", double(res[3].total!"usecs") / res[1].total!"usecs"); writeln("frexp (Phobos time / Mir time) = ", double(res[5].total!"usecs") / res[4].total!"usecs"); writeln("frexp ( stdc time / Mir time) = ", double(res[6].total!"usecs") / res[4].total!"usecs"); } mir-core-1.0.2/dub.sdl000066400000000000000000000004551353705753200145230ustar00rootroot00000000000000name "mir-core" description "Base software building blocks and conventions" authors "Phobos Team (see information per file)" "Ilya Yaroshenko" copyright "See information per file." license "BSL-1.0" buildType "unittest" { buildOptions "unittests" "debugMode" "debugInfo" versions "mir_test" } mir-core-1.0.2/meson.build000066400000000000000000000026411353705753200154060ustar00rootroot00000000000000project('mir-core', 'd', version : '0.3.0', license: 'BSL-1.0') mir_core_dir = include_directories('source/') mir_core_src = [ 'source/mir/bitmanip.d', 'source/mir/bitop.d', 'source/mir/checkedint.d', 'source/mir/conv.d', 'source/mir/functional.d', 'source/mir/internal/memory.d', 'source/mir/internal/utility.d', 'source/mir/math/common.d', 'source/mir/math/constant.d', 'source/mir/math/ieee.d', 'source/mir/math/package.d', 'source/mir/primitives.d', 'source/mir/qualifier.d', 'source/mir/utility.d', ] mir_core_lib = library(meson.project_name(), mir_core_src, include_directories: mir_core_dir, install: true, version: meson.project_version(), ) mir_core_dep = declare_dependency( link_with: [mir_core_lib], include_directories: mir_core_dir, ) install_subdir('source/', strip_directory : true, install_dir: 'include/d/' + meson.project_name(), ) import('pkgconfig').generate(mir_core_lib, description: 'Mir Core - Base software building blocks and conventions.', subdirs: 'd/' + meson.project_name(), ) if get_option('with_test') mir_core_test_exe = executable(meson.project_name() + '-test', mir_core_src, include_directories: mir_core_dir, d_unittest: true, d_module_versions: ['mir_test'], link_args: '-main', ) test(meson.project_name() + '-test', mir_core_test_exe) endif mir-core-1.0.2/meson_options.txt000066400000000000000000000000651353705753200166770ustar00rootroot00000000000000option('with_test', type : 'boolean', value : false) mir-core-1.0.2/proposed-mir-architecture.gv000066400000000000000000000017631353705753200207060ustar00rootroot00000000000000digraph G { rankdir=BT; node [style=filled]; "mir-core" [color=lightblue] "mir" [color=lightblue] "mir-algorithm" [color=lightblue] "mir-image" [color=lightblue] "mir-runtime" [color=lightblue] "mir-color" [color=lightblue] "mir-core" [color=lightblue] "mir-core" -> "mir-runtime" "mir-core" -> "mir-color" "mir-core" -> "mir" "mir-image" -> "mir-cv" "mir-cpuid" -> "mir-cv" "mir-compute" -> "mir-cv" "mir" -> "mir-algorithm" "mir-algorithm" -> "mir-image" "mir-algorithm" -> "mir-model" "mir-runtime" -> "mir-algorithm" "mir-runtime" -> "mir-optim" "mir-core" -> "mir-cpuid" "mir-core" -> "mir-random" "cblas" -> "mir-blas" "lapack" -> "mir-lapack" "mir" -> "mir-blas" "mir-blas" -> "mir-lapack" "dcompute" -> "mir-compute" "mir-color" -> "mir-image" "mir" -> "mir-compute" "mir-lapack" -> "mir-optim" "mir-runtime" -> "mir-json" "mir-optim" -> "mir-model" "mir" -> "mir-sparse" "mir-runtime" -> "mir-sparse" "mir-sparse" -> "mir-model" } mir-core-1.0.2/proposed-mir-architecture.png000066400000000000000000003626151353705753200210640ustar00rootroot00000000000000PNG  IHDR7sRGBgAMA a pHYs%%IR$IDATx^ \UeqZ}JӲiӱͨr*m#˰&4ˉʴeXiZYXYTθ*(rs_+;Ϲ{Ϲ< Fxq~Gxq~Gxq~GxBΝ;e۶mRRR"EEERXX(7oϗ7ʆ $77W֯_/ٲvZYf^ZVZ%+V˗˲edҥxb,Yb-̴Yru,>֭[ggNN7򬿹i&oٲz<ŲuV)++3ny;v2 4pM: 4[p̛7S5|+PԐQD !5,ԐP۷ˮ]+B\ 4Qr~i222p)4 Zh5PGBu䠎l$ 44ҩ750uG蹱tN5:2B?4; 4|J( *JGI@֠QФ4LPI% 4lr  XӦ4zmDVuΝnF):r:=HNZd5-[F .EF)++FYQ|!PϷFl1%(.Bz QS/f .@=m޼|T(@ZihaYbcCQ{*kENϘOGtМ)--5[$B?Hqq]V,XPT KCM6@۸q,]1 Z2#1;w\p b(%j͚5RRRbRP_~!bǎ~z\]V""rvlǀZ+Wd@Ɠt5 jBtz˗;(Zp噭8!2k׮u N(l2~AB E ڸq@)`5kȮ]'xNE{-Y>0&B?QT௰|J=~zj#*]EJxxzm %m%JC{jnL5@b;븰tRI xH^^cz5^$L0Is\'4*}0ܦjT.JwߟB?- @("ǐ#4~U+_~JAz35BGdff:5_$vnUTTd>9B?ؼycAQ"\YYY@h NSAQ"^۷o7 mݺ1Р("^999S@#p9 . /T%hUe2*AblcJm:Io$zDI ;HtwvM)Hl6Cjm>0 ??^[򻟰W,,zEYU?<^O w~nUknO_6-VSVwە?^2=~iSd؃1i_Xcn~/6"ɜ WWjw**8=M%_G˰oIx<)Bbz%Ho_W^}%ݾtI']/ }w(Ԗ"}$b˔!GCI̙ȰeU3(&tӀtu&0>LRFkN$\VΙ8)bdIQB?}'Ȁ ܴ*ƄQ2`Rp28B?-Beff: &8HR_ۜһcEy]KԹGǙ4Y".)J.GďRFKL\ב~~WX80tJQ)CȺ+N'Ϊ׹⶝'-J3:&HrUk["4hԞ&#{[AbtZ>Z%$q0oUt 'ϬX'+--5$-Z1D}(]5TFUo 3+=Ijm>mὒgZ[ʳMc-|6r_mAoy~UCĊ^/ep]8q`ڈ؊ۄKD ' Fr ,p 3=E?B?+**r 4uRX^^m*H/vW¯KaUAa#UPP`>9B?ؼyc=JrUGU-kD]nP~NӹQzNc^Z)2vpDva]i%_mz 3+nα2`Ip2WW0isfWK,_z빹֬Yc>5B?v 9(%KȮ]'A1aEQ󤨨|R-~m6YxcAQ\7n4Bi:o>&B?*--K: JEm߾]-[PT(ԦM̧F֭[PT%%%xZ`c@BQTk׮5[=!"۶m˗;%P<pFd… Ey֬Yc]8#Reee\|բ"UYrcBQn 7[1B?e?xbkz]v-@)..իW;.RtRF~!j֭f}f Eʬ-[PTkѢEn:z 0`FØ :5՘kJ2AG6m`R+fM{TTT$ׯK:;+3++ uX<P/۷o7ʪU?8.t4_NN47B?4Jaadgg3 0_SN9Ev*wy<2j(:uFرl % `m z$,,̱?x宻^xA>C短kA&uVk4\b5B)`jhM6!j?\=OuCc=&GucH_^xU˛5kzfm{oug{Fg_T_|u{GզM4tի{Sz̭@/r)Pmս{ws/pqUz|_}i ^ꠃB/̙342̿~Wso-o]weZCKLLL©N87x!@=z\pŸT>}==S1~5DGGW{=sΑ;wȑ#%""^~7˷~k4=^zi{ի=GX'Md-;v.]8&Z|YSTF!~S{hB?4JO}g1|ѣY+_\54kTVRR"ÇN:z2k,B?4 G]) Ks1m6s/Xg)**2k<9s+&ɦՙoswHZZY̙3e}^uskw(..?OWY;4YyE{VPP r'گe^dΜ9f PB?4O?tTgu{;5\c]r'[SƍeȐ!Ҿ}{5{$==ݬ(3r!!oYbY@0`~fiVZ%'x%ryϧ>{@S[h^ڬ@p#@@{v5qDt~7/wg?Nh^ϗxou3Ⱥu'B?D~~r-VТf̘aZ駟էN9s/hnsΕOg8ceРAc і-[&]v:uT)ȫoti޽㎓^xAB?4ʯ*g}\|ŲvZ}?<5/H;}/]weg⋲i&F>}p Vr 7Hiii )F6ٳg˝wiw'x˲eDCAK]R\\l[Pooڵk'?i_Ӏ뮳HywL+A-X@:wlg},[̴@)SHtt_tE2vX @#YfifݺuB駟ʕW^iQQQ2~x @!@5:騣B={/tM4Itbo]v|ᇦGJ}];۷Y '׉/tM8 |ۂɦCСCbf)j{S|TmBթ@h.~}ofB?6l /hםnXao{=3v[oe^{B?ɯj]Ϸ}r@#|OR4'O7={~g}ơ7Ϭ&~eٳՉ̙3M `֬Yrm۫~oC%!!A,Ybx M4{R}!M6M:{{>e˖5^@boSOp {C`0e#߲|r\_;߇nM|'|"#'xBV\i z &p{D`G_noGu<䓲zjM\Ln}n{>KuOKVVY~.+111VgL ܊dܸqrEG->]֬hI~.xb 3hөS':%%%f-۹sϡyfDB|,~zYnײzjYr՟*>kYhUe}/zES[_O[~>2;B?R۷o@S8=8yh͟?:hՠPNXva9\4 : .E F~Z:(stikfU-IC2} ikxoE4h>7ׂ ~! ׬Ych[n_~qzťzƗ!rNxn/=h35=NϐORSSe:ofh=)'#8O>~R{L4ܿ9CUDD #t$ 4QzNTKQѓ58e .~rzV]z@Wu:Q1߶;}Y3$HC~ɁhuY2jԨZGiPFA;pS__'I)FhB?p=CJ4ngu @K{饗jhz zȞ"Yϖz˚HN4di99I}S4_E-@ РJ9(Q+=Q@smwNf)дI>}d>kt Q:kNNu@G-X֮]k](@j\~zik.ݻ}7hozSO4ITOy222 B?hfMN#L P?~&~$ux k#]OqlJO%ޒ4ӡ=^GB wěú4uֆ 7̔?:n߾u*,rssVJb7O.A š_+f8'geeO=~PEii?8~Eq6>ؼehB?"߹XshڸqtBU0՘b{M>УGhB?K:ƥdXDIule۶mxѝӎZ .d }v裏@tc߷TմAՍЯ>(-ńgX!,C+)v-ZI߽DXJZ_$([U\j[x +?0K/'J޾௼"&>opt~Nm)7J"LXy:ԜdI,\"z&J@/uu ם,FʀfyJM3%ɥ[n5[^[n9sL x~𪒒߳TI#]+OH9VzK8_ CSeޜ~' }|aTy/;eTv1A_>iu9 R&Kԙ~k]Ly6Zã$~LjE|=D}U v~}lc[¯+lߩĮUdtGW-U:^kU~~Gƍw쮨(=k$P³0.FbՕ>:6VFV;S,E]Xq!^$v1m=b%~T\4c:+ :vЙwPYť$arJIbW<&7VaaٲМSNqa&h~𪂂߳ިog.T. UQ$6vD~tIUVy֡Jb³.wdŬJGJ|0#FZ}5N)8ђ8r>%[7jUci$ҺlJMZ{֯_o>5;p+D;r5>H祗`xSe:LJ86<ƺ Y~~~B3dd@wʟSv%gmڴlYh. ,C9:omqT˞*Yñ_#Eux =Lh~lȔ?=Y4C?~j_ӽ^իWO ~~`yv쮨ZޜH,a?jSg&5gwH.է̌Tk Y^ΜB^e˖O ~~`fW{w̶.rss͖6eQ_Y 4B?xAXMDϾImaܗmyWCZo.]j>5=];S }ZI6ˬ UF3@xwgy,JOVu=rc1U9߮-=C?{_ kժUSyyy;vWCc3|u ްlYh*/} o@"W8FAWc~@9|M׸6p+CoA5UotǶQo?mDv?.[- M8N,?,7ʍ_*mDl}Eʠi̛6H"uʏ$)}rBƍͧp?B?0ocwEy6 %:|JbkFacݾDudF9Zp٪zs&Y B?xŋ׺͛9RbͬF%;>:j_~}4«\ Ttܹx!KbHj ܆ThT ^5gXq?Eݝ(㧧IZZL3Hv[%nsޕTskeee- so3ǖa2|B?xw뷇 jwZ+:&HrնzTJbGKi2G/TnOxMsXվ#_X7r0e IݿStkONN+e %vhd:*#Ku0,i~mzvY9, IR|a]8uIT#<]TnMg3 b 8裏7 􃗹z֣j 4Ixa:׿=ݯ]eƠI i~mSd@gVenɾ߸Fկe|ȊXIdcz$v12ZW$o7 7vW~nq+ZbfcJWXʫϫ^kԖ-[̧B?wҫ\#*uTngm~N6E=#¥10ʁd&ú;rt[eeef@ o1+;w4-@#l5NoZg#ڪUnkOY/d8R:Ric͙]%*2%1NN23#=HRRF}2$.qixQc^kZtAU^qGOQuכ- 7ݻw7K 鉫q)wytLUqqAUoZ`裏>|,܅`͎s)w_^"B?p൩-(wו^{^|EpB?u9֥S~SzaAii,\qOQN<`~Y ɪUR(B/پ}DC5(((pSS1;@`RRRRl\Ziɒل~{KLuFԂ-Ԇ N.M n~FnTIf¾-QRoCշ,`/_x0@QZzG4^㎳:0Yri܏jՎ)*jٲe~~eeexP@v陏hE#Nuf5Fm~=Y xBb)k`F n:*C{Rjv%َ)ʭ%f+4P^^A|5|)((0<;O?,JGd6$Synٲl@#F(..Lǃ *8JY`ץK;5kY xB*z{RaߦMV B? ʻ`ٸqyP׿-ZdZ@T(**NuMQUzr>5!@ bt@`qՁh"GqlذLgEZzmjZ|9x t%K8Ni䴜jЖD?}gqY B?%77N}$Րe֭f@M`׮]V'_}-"QQQrI'xBLy3f؁W_m3=TJ!I?@Vϟ/_~2`[P}^{ٝug}xB5E̻ @7n}{=@"nǎT8Njٲe#۶m3['~`ݺu?Krr+/7po#<ĨOmVky+++˺8^ dh;wJAAYƚ;`T쎊@U6mdܹ9m)}dܸq֌W ..J}J;?Lڵku t馛R RZZj5Y'kC((zrlk ##cS>: ء>CFuCUl۶ͺ&YgxQSAoezU~~uj*kd`c^ f=O?Ա`0=xɱκӳզcǎޗڽqT߾}R~@pѾ lbd~ =1Y/3SXjS_G K.ִNm(}njȩai!hR}GCcy[oY3B?04${3ΰ(;:MEN?zFNq(A=ө. VB=34(ԃA}{ڮ^Y<?_;5)ST{oZ:-M_{#S /Py=--Eӟ$|n0PT>N:swW{[Gul ':58IHP@l}gkhr!V f~Bt{饗|;wcǚ5v+dj}ӧ.]P73Zn]6s+22>>5kY @ڵՓ<ؐz7̽ S?O<>hKe„ f~JZ{|fwuUz:œ[k}sii/ZpGz #4NJ/al̙cU}unݺ{PB?!C5}^ yĉf]{6Bo:s:L;4:sOuc,蠃fP3B?5tP{oݴ{sKԆ@ӹ(m۶젏?جQ7~}`<۪6:}6ճuU][}Bܹs"h .JOJ޾}Y#ꩧ2=SN h ߪUۥhZ5}ofn 6~Nff<E}z=?ܬp_}W`˿8{]r%ju 9>.;RuA1 d^$XJz bn &~Nw._~Y hN'5iَۿ9]tdgg[=aw\4`@]hO?;U0_[w|ξzk ?#K/T͛g@U~>vڵk+̟֭?ߴP~n;묳R@!߾.(LX7|dddV pSu:{W~wqgu/2hPK+$//ϴ߻k]{f)@!P_SLu{5W u [=f)@#Pz)8GקMM:Sۦn~Zӭ9}.vu&sn#8~_Sw{'ks4=`p>F{RM@}L0G׷{1s/"5~v,[̴@6mxW&/]Ԭ駟MC*T~cTs>s$++˴N;>6Y54-B?'VСW_}ekӦ3ƴ@뮳T:(y'dŊf All5~isOOuy2c nj @ PW7n c۶m2`u;d~wG} ^ڬ())|NPY=e}?Z>Vc+ j+߾?vloΝ;[sw5-@p d&M$W^y}Ҷm[8p]֬񽗡e}^kV6olZ֏?hiE P|u֙%h eee3دw-9996B?7qDҥԎg𽧄~fϞmM[щ'ȔZ}1_lhN~ŷO'k38ú4u~fre(zqa0//Ϭ󽷄~5 .z>`OL @`N7e~Яgz?4رcb׿K/uD=&ݎ;䡇_GyĚ: P5}Q@K (};_әt:?lZo!`cƌ /> ԩRXXh@ׄ~uxEEEInniho>.o-@~-#33Ӛ=A߃C9D^{5xzٵk=Z;<@D֝`IIY v1Xhs=>&KNN6K$B?Co={+VԉNW8j(9:Kx پ}Y .>>z grZݟ'1bi/xZZY ~Я͚5˾NJ/fEDD}g曲sNB_ h3fiZ瞓;P3?#P_HOOmZmeܹX駟6K@!_~q[޽eÆ h9~@Yz5k*O@([rر ZoY  L8Q:t`o_e!b2`iݺݑp5g}fЯO 1iR^@ P)33Sza=Sh~~@[x_8{ӽ{w:A5Sl\p"g}cuB{ :T=(/h>~@?nR^F PֵkW}>z-4 B?~OG?,k4Z{uJ~@;wVSnjZ"pB?B~miժ \qo$v@NdСyf>~ޠ#^{^~2rH#?/۷/r0aY6B?O>^{RTTdZ@]̛7>i֮]kZ*B?Bڌ5J<@k%;;۴f8p{v@n䣏>2k/8Gu^r)aZ@m+x?<<, モN;N>l駟L Ph+VȓO>iͧ-~Y.~C@\pys"`1v@!C]ZJzk[iժ dɒ%cGadԩf 8;vȃ>hΝ;M+ygW^i@B?BxcTP~@=,X@y9C/T?YB_p8q{{WH^^iz.v#(~/qyfӂPEԁh_Vll|f 4sJm۶nZ]]v}Y*#(~hiӦIm/ݴ N>}{mؿ~0k/mڴɚLOƍgZ=;vf)TG P|~E'ixB?ٳ{|;Z_fB_۵k3k/֭[ˀ$33Ӭ6~M<ꨣm@?2߱֍7h@q m3!x!$L4IufiFyYzY@]Axs9vpaԩSM ޢ!@C߱ /Z믿^VZeZL_~P X#}|j:Ȃ`0[?Y;,WU/~CC5kl릯z몯ocY'zNSz5#2kVa =V|$_vQu/T*+mH@ zY Eۭi-uPϩjx`- mڴir1X`B:zfguoo>=X[nGw@s# ^ݲ {P3Vn[dC1?_'?n@!|:OG-Zȱn+WZm۶ͼpnڷ~駟 ttئMøL;%\"G_Z_pѩ!YE:FTK/6ʂٺUN;Fa@"7Q|W:PՑL }_unO)!/_eAyze~uV%h~ަ>fm9erFrt @ ¿/vɓM 4=B?tGN#R[S5r|I[ dcNWghZ~SL27Kښ|81BX^ҳ7I֖^ٔgٲeڝiAݮ][]ΥӻYƚnǎfkBsIJJNnO?zVj+>tzW^7䕔ʼ- !EV3WIB+0KMM; 8d@hn~@|:c׊+()999׌fΜ)ӟUW]e\- R )ntB@WiNY_$3VQ6JfRNƍO<,G8ӓW\oGQ* 򤬌Wcyg}Y qeWPP hD]hB?Y_M~Y1@NߜͲiv@2dwyf) B?`bYv-Q-R:Nu[mۚ%pׄ~;w.̙@ӡߺ?B?wصKdI~L_PTS$k Sh9w]}f)B?@dƍtR8jҌA_)>u߷~YܣC? _Tsւ a@Ey֨+0+ 뮳{,EPjڿƥ(eݺu\۟EY@e2/w|81|,q,lt"##NAjJKK E6rceeeY"^u}f)ZR~6l \Uz%5/s-A E-ˑDN%h>O^tEf RB[Q!QsaW*B_f BV/P!""^~e^}\:ɩyRPP`>-hN:Wzf J@B? B{."%<zޯtф"PRj>!B4zX{キ̚5˴v?R%.Ai\-1up5,XC2gWy'x_|}tAf ѡ_vv ~v5x_$t!x%Zn$Яnw B?xIIIcEo>Mh8ipWPPSTʻsE vɔ%َ!EQǬS s=k,@/ёJN}[T_pԲȩ ؿ~OSTۡ'n~1(zln>9 7`R~ V۩_j" *,,4*?n^_R4TB[:nnoK!$~%eTĜڠtw&5I6w~%욛&SF mGVODI-I$ ~6yw,6gv'$unugNOJT;M¥ewr/?WjbJmN;ݯq-_iSd؃1a=0 ?)J_#~Z_}EZ=.Ceʐ{[o5Ȑ~OMל,tо\?h*Ղ ym r%䂡sжB^yFi[kY8~[wO5y^rvhy*m+C>.Q&x_b)\hݗ?w^c'1KWTk[xDMX;9e)/.\Ἶjn_l'0K +rrr1SO) #*niI?7UAdL+]R'$J|t w dB1$y>s=HRju>y3Wǎ(SҪκme]?{ 'Vi2exĜ_:YDtcqk-;ZzT!Pz){XhYhP藛븱RʿȺ!SXXWI&IwGITޒ/Z£eط_% }_7yΣ|<8N^XO$q@˿S&Kԙ~_޾/:U%gJ$%\٫u_ו߿.,*o$^gcJ[:vϪ9Sd *w=_c/I UzDLdM(gnO`GW?Kw8nSߐ 4?~Wɨ.r/D VXB?~];_kh9 'v\/vwHfθwٗ;<ߧJȓ唘{5F붧<,2ft_9źs$nr*q?~_7{j2v9;Yn,7:zΑGraM[|z;aoY ^d>-wW$fІV2s qYm=4U/wqי񒜾SFKl~ZE?!)}s$+#M?q?m;~)Ή`YH%uTon! *o՜dI,RԑQoSߏJ2oSm) ڹsd!P~mRWB?M~k\`/7ﶣRqN+~+g"sj!M[l/9"5qR~_30/c4@wXDZBzF ﶿ'W}=?[?#CXު~˵Cˈ*]2 h{Z%5ļF#ve>AJwp8e^1|>-ox7tTZf2OŠ %GB~$3wjnԫͩ3PZ5~$Z k6_%K鯶L~\qoHziJJ_}i2Yor-3j}}{Uk _#%~lm# S4.]ɦMRGB?~ӆpt[vO/y;oэ]qµza\+|p~lx$LϷče:Ԝ-RqCvZmBݺ#|S/C( E'#|}5W;ğ#_dAZvhWn;WǴöQuVZzt[nx¿+Va*# `g*xٳ+C~ʹ@"l߾ݱ?;:2-Oc=:f uMwLn$_jvGTf$/F9諚y WKIkPI FP:~o0>y\r-f 2uՠoŎ?tDEfloS!6"vj5"F~Iu*/ +ACp0 xՏ^)D~kCَSnfN_m[=~>ڟ{GMV]uܔ,FْWM4j߾=~",&-ثmV@pݦЯ5)|S`W{}#XUދyY$pAֆ ̧ M!:/e}1KPW 4p]_MlUvMЯ~ToֈЯl~ZEx_1D5YWm5> }׍Xmӌ4yEN7c "W_+>,@/(,,tN5]Wk_g~:!QzDw7oH+z +=6_q}ˎe?ʚi.~wO3EUVf "ttM{Uv?Nw_u^Z}&K~m8czOBY{)yNUqT!x\Nn'g<]z~oy'Di+{^ӯ_ڵY ^PZZ؟rcW~]_1*IOJT6DID<@MJ}JG\j(bda;\1=Ygemm۶5K' N+B5C3++|BEW? :(B?CIr}dkiu2kӪ+ZAs7JegZ% Z:o-=?_<}. zkw\y7 +ϟا /m.L"z&i0kss}Ż[=8~e񒔺{}`wqk)h|֭R\N:$k;رY4(u]_ VC(4yJ!=gϴ|&agx?%~yPf/Wt(+_{W^3o.,NN=5Ȑ'c+~+BBT;6KכO/++{5K +,YاrcW1LJ y//~}3GJ5N[kj:<6_¼jEz󈨸]ŵsNBs_bmCwY4(iCw}! CyI%:~Y_aUϵXZܯִ9Lb}WU+~%%%/BvpEW^o+][j~;~3KX?Zj}"M#V?.7r^7{(Ll@h"W N}Zި >!ƴs~bKv.קcH\qMLbeLeg˫^UVOlmC_~Y' '뷇Ϟʗ[Et|[5wvLmutߧSWe%qBII2H ?7Lb@S叫Sy[D*RMaי/KO}%:9T|;°Uv;0sFGN"r/uu㺅.)PAW˼z]=~W|g_sC?ᶾ=_WkW?UݶoC++L 8j&̐'o+oWnߞk0Z_%C|}Kgi](@ܯ@?x;w5-۷owF!'YQ~vSp@u+c~U°ɉ{d)V҅Tܬ#GH#Яh$<M猗ަӽ;QOOT2f5UhD*}{-xlb>Uhnb\f jpi& ͕2e.CSdorޒT2ma#%NFk{Aͺ2/$q#Rl9Sduf:/ ޣvI$1> V㬘kEHҦ>t;_+GtN{tՠ ?)Z%HQX5 k#be$񜟟o>@p#;wgV tE>Ψ>;Yn+W^W QkX!ztZ^%T\gVmt<}}5nԽ1C~<nPI2f_>!Pr;՟{O_v3/fI{^?#t_NN"=?=/9rE+VzZ15BvZː*Szfh>5Jt!X5|7B$++˱o5}coOu蓜$s$]3o^ٴUdnZ$w'w/-EJ)2Mx#e>`?G=9JrbLbA!/= RK.5&ҷ ,~*##qw_W*FgYT- :V׭dx9u_': 8hB$t6KD)l*]$IT;]˾{}qWݩW~~;:RU}_/Fz W*fnfǐÕeZ:oe~#䪔޶WcZk{ G7V=?~'/ig-k+qk}_е:FP9DК;juCRiC?gyqrHV'w.-L W_}e'}Ѳh" ;oZmJ}׭uRFK_..$Rnt._ߨ=}v$$}V8=^WI$sźmΌ1f`̷$]E0iSd؃1aW-'JUuBm --77~c§Q͛7|%L~PApդZ#'aMѩ5jr $-N5Zes-?Fm>Sдv~ UґpL7ʣ>jB5*S֭sP.(B&kךO.1Bf!QJӣ:א[KϏۼ^_/ϕvO ygӝ;w6KE+Wt뢼Q~_/;wO@*4KO$G.OM:| -=?ZľpnܫW/^!Ƃ (w_s>#2C]@B?*uh*V\z0DPEPT+!5;g$yK.ո*((0x-b};8$44S045B_` ZYPb>dʕrGG}i mdҥ}bj_lb>𒈈km~J/b  Eyt{u~zsLYPT0Ռ$+Rf͚%?#䧟~2- C0YvcEJp{\?n& |?8Zn٢5<Ǡ~_ϔ([}־]OUV@]!5̸k>2oIC?;;~(ͥm~~ْ(B\&/Ζ囸~V/cΓ;w@}!22d.dKn&r@QKWq5Ra(Wz&)^fln裏?J~fzBŋ(륃>Fi3gY%ы_rAXͥgul޼l"k>::ꋥrs 9E̖ ={4K EБLu=_ tqK(^rǎf GzǬ}txx5z94kNrcv v~k]Q/Y/pk|A~Ν;Z￿kN=\^z?.?^kkΖ[ʚ5k(+Oq1%111_.%%%fijOԉpQTsֺu#BQXCQ./⍅Rkb\`w=3f)%O>}<А:ꨣSO/Xj䡇AɈ#>ӧ˯GQ-UVBI@(ٰaaZ,!NFjM;>~Ze2/w|$1|s%sgG^''tY7j(B?xk/߿c_ETTЦ'"w^`|d;륗^2KkB?|r,E5t{jSB>klk TMY-/R |?j۶m+i.[ >ܳX'fee1"rJ)((0[#P}{, . |z 8~)fڵ!qqNW2+:6Ր:OVNN_:vh}ui=#ӦM3h?7l  lxt=!nj㸎l4}jU~u-..4y]ug藛ӗykwqlzA_}]^.~+4p,T, 6l߲ Ǭ͊\|Icus/Iߗ_wlkk'XA $#PVXsn۱S^~e`ӿO}B?ʎdK-&6X_zVni˚1OplO}x|#߯ʓ9k9kem)R)^V)9?֨=@p{5\cZモzJ."{'olܸܢr-,]aX۲e[#uЕ+Wij…v:Jo͚5~zk)eKJJO?|2tPN:CP3ΰݻBt믿B0r闩gIDBNDl, wNEԳNt_ξO\u=]_hޏޟޯ޿{wǣ@@mМtWeklAݲ"YPʼ-~__ $?͗6y*ϺsNG5&/&/ΖϗƔ+*Y7Z#47lEw"Td=k]Vz[w \'Rh'.w}YR&g϶ҥ5(/:}ȑ#?xn߾ 4(~U UMhi^ ޴/7##{5V-1cTϷ>F/J۬9߿gGA{_{mmzجY_:LkxrW^yqE]KYC϶^+.~?W_kV: {u 'HϞ=eĈ֌`۰Svm?[C}~hz_=җ>cx뮻L;t֭owy2x`;wG^ѹsg+L;TUc}sẽQGe}n;04ii_k%%%YS=cC=5;zi@0*mu#=)@޽{駟n;xĉXBH[}>[\s^mm_Y^~ TҪ8L.jp_ 8Ь3S}1V:53۵kW~ޱaINN~}N9׿%cƌԫyo nW?{ggSqBZB+ED0FDHD"YL[KI]&&ɾ<{=gsfޙ{s>=9˻?→]a^_M!~$K6[v 7)bu{ﵝђījf͚TB!NF?p):utI*Vh0t->L/|˗/(O - *TܡF ѣB h#ܹsV3g>u 7tMo+ !v}nǎu*!A_8w̞=[>ծf˖l[kV:w,ӧO'N+ !᭷(ciCJB {̘1:^Vd?BHx@ G  ғO>ժUWym6y衇̴{O.\&'Oʣ>j>}#B~va^llԬYSPRT_{+ !. \Jjժ 6>+n6lr%љ3gBHx@ GdmxJB@;zjꪫgҥ}]&AvܩB2k]wݥ#\}!B_pA=A6_|f/M4#GʦMU`ѢEdJ4pv̭ #>ݠ/.v[ )SF !4pFT`A߿=^s5l2}4'J99siӦ#b֬Yr7rx9D!X6n(}4nX+fs y+СCU1BH2]+W.(.]W>L1/ǏW8h/ zʕg޽e*BH(i۶m ծ][߼y͛W?^N`7+xٲem5BL2E +4n8}%!4pp_8vb͚5rW+7+i={裄`Я_?̕/_^:B hG̙#ݺugyFn๢bŊGU,\B@k֣VZUMN *UӧO#0<޵kWzhV1xkǎ B h#ƪU.JƀO3?BH `*gB!~idN:rmGyD-L"ݻw!vSNf6+޾}S ֱcBƒ~Io,XשF??޽ٲe3+5o)RDM!~$ߒj̙W+R>c[ $4k̬36lS !F]O_֭#FțoiNpoeڵ*B8zW =v<đ#GojDz-{9Zhtrέ> Ԥ7hvX B /h#g}UO<g󩧞RqU!nݺfB"B!QGiݺ<;1+W./B/^"8O>Do߮2ᇝ~af׮]!ePB*2Dqý:%ĘhС(!4p;op_b|WO\BTP/zS !+FIF?.]O?,_/+WV1f͚%gΜWB 6 QG,XP6oެ| vb:54#&MR VXSV#0et*!4plٲ*O&zo3\qwyUWIϞ=B/ܹS/n\ H!Qo…ҧOU m<{L{=_U/BRZ5Ug`0. %v~#UTQ JSй!pF?nz*OCX\tiiҤ cXbUVO>D喏Bo뮻NMS q.ӈu̅F4h۶HBHC4+Wx|ѣ(!M^̲ʙ3gB!8 Hcnj{7TL56a9x𠾊BG.]TsW˸qt*!Υ~*Oc7k(/Ν+W^y@Bth#Fl$w4rpwY`AHXaPG!$r1;o.cƌf͚oޫ"EII۸qB2#W\!#FЩ8x3gN}Zf̘!;wz\n[nQz- .WBH聱F?U0dyVZ:%/F> \ 1!HѧOy/}bɓ'QBŸpED!B~ j<::Zn6~ =ԩS*Bpi,VرN%y\RE^uj@peb۷N%B4,X|&Mt 1pw P˗/G O0FxU﯏Bt!~[lQz-)V {$SkQo-/_Gq۷W')~t]}eB!F?i={}Tpwy 7B ҄qyoTB(XF'NȴiӤCR\9ڵk_|!K,WBs={c{WҥK!quɣatj tЌUXU@!$ H$w ٲeÇ⎷X2 fR񏐿 ( SLG!D~P ~-Rk֬)9s4W5ЩS'>}:uJ_E!<Q?^!9CŋgZ{MFPW_}UB1яD"իWW~̙:Xn֯_\~G%K XB!ȈoƍJF{1/͚51cƨ fi9T=XR%.0%رc6p^tjpύI&+VЩB h#Hll/IwwOaR2h +ʮ]B!X'O>#fܹsKݺuetR}!DV\rL2ʈB8pʿ哽{ApߥKB!H$XN!I&*6"!Nk׮fSN%B1ڌ~1޻woQ!W_`N "$6o,yUe%!o߾:%x߿zm„b ~$9t>N!+ q-ZPz뭷t*!2Fmۺu9R7n,E53 wyGƎ,s]wH"7]xG 64@',:B74HW8S/裏z#[l?#ؓ_~YW}:BIXd̘1C:wlzrze OB!~zCX8O>8pႾBHz7#|\dŊ!m۶*>:%8D.3_TB!VG"#W=t ww' aL\uU_#BHrRܸqj!]?jJ~ٷoBH 9v옔)SFջ9r䐄}Ph޼y:5DS/M6:BHJG"ԩSHz@ ør7JH(Y`(P@nM~W}BIbܹҽ{wRڽvНwi BӧRJ͚5bw^{5g6mSODnvB҆F?l߾]E^Ν;V}BWFHf3yd̲  BXv;@XTzuLQ1#*d`gϞbOM6F?Q 4hN%4HkQnva  Sy*[,BHsQ4iST)0Ttiu Ē8F?B|W^Q0uM< vM5 0@X%4Hr*O6M~OOG9ԏ9B$-Z${5jq .\X6l(|lذA_2u4BHh|۪.+UUBȑ#U^{̙3:5pDrL!7h#LvTOt pټysn֭[+ ?kN% lݺU5nXu6(gΜ /(#… c~Z:w+BFS %JPy!MDz^(}BH$?x$ϦOբOh0ɋL!$9{̜9SM?f`\rj1ԩS`&~zgB!VXQ3!~өB|F?ɬYF hx=]@Qvm %1Z,ՓI9x/_O G!_UZje 65kV^Ʀe?F?BwWm۶UW^)!~ߞ+W."g̘S ! ~$yU2eN!>1YMw$=`GbTʖ-rK!ǫ-0}CТE Տؿ"F?Bsuש:7ߔ˗/#>ƍujƉ(_ )BF?4o\x gtIE\\vm*y2}t}BӀNM.\Xrȡ-?+2~h#1oB! 9sFygԩ+WNB{Ʉ ȑ#b~bO,XV?^!$[K,b c{wkܸN!/4H'!!Ao]b̘1>wܩė_~Treٴi>B!X6p@#wf]avݺu˗+q4B}A}뭷RJri}бl2'&߿v^s5 !su ,ӈі3gN$|*o@Փs#B&3 K,i߆J.-|L:UN#-[c=u]'~>B!$3ٱc5J޾Ulr k׮'/_W3G!qc˗/p@*}4hSOX֭^|B84M7ݤºut 5py 7w{GHd3Gh#gryU]#GcXF{NB!F?BTYhժN!v>ׯϕW^);wH lz`dw+p !$x,\Pz%>\f aMfݻw+"G!n|MUg͚U͛9*iF4oԶm[J!$=:tH~Wէ/^YBrԪUK'K.W_1#~>MDݎq$_V믿)vF\'Xh#$ #~at 30ݧ0C={ԩB0i ٲe3UGQ1c&N(GW`S!$@؈+B OHU}wyGOX0@ӄB~$ѵkWUz-B\ŊwK}BHZ?~\&M$BB%o޼.\XfϞBq3fȇ~zFʞ=͇ʕ+$F?B _͛ 1{!@*_^G`ËBHp04wܡSϻK}o>CȄ kUߢTRtR}Bشi >\^}Uɗ//^5?ˡC$31~$$$H9T+G /Xz=߄o%'!a fi#$Mdu q}d|ǫJw΁[&Il}Al[#`1 bcGQOP|'j4 =wяBŸUV8+… !?: _:uK`B .`F?BUe+2drtIl[ׯܹSF%5B #111_]^߉F?B 6o, Tujٳ!gĉfJ7͝;WbŊpBH14=ܣSvI]vfҢE J!ł >*U5\c֋Ѓ>(mڴ)SӧĎߌF?Bv%EQV}vɣSF7xC?\B `F?B9qY.;Sv٣G  64S !$9p׼ysx٨ 믿^ݻ? oH!D%J6L2 #**J嫽{qU?~`"LGHƄٳu  СCgΜ5jɀB _0w_o6@;7|SF-wWa|O!$GQ 0QyOS|Fw}W=xΝu !D&.]sɩSTgѣra5IV۷OٳgP@̐;v-[n-[(aY~[N֬Y#WVq;#}ڵý]Dqo$ʣw^Sj7E  hy*Plf_DF^69F<@wY@yB2~ۘ3$48X*lٲ) !$6ET}輢#m tJ!Agct{{ ThB k׮mN~W*49/OGO)d08ܴM H 0D CҽG;̛?0Q(#z%7z軠Ik I B @(:(;v4n\0b(G]ےC:d#{P#PIt q*إvsFӦ/ai3ej'J[Z/4#HqrӲY9uJ Ew`2 F*Os# |!C(^U< -[T;0M2a,@y?fO#Q0*c"T0 L`\) bzaB0DbHw/ ͛WA]l,C~AAm  L2΂ T>BHqqO!v+^Ƀa@X F\C& JtC Vs\aoʅ_;)(+\2 purqsrs}Lc2.Ҳ&0ы>V8N`ϧ~**T0q`}YŋIz(aH0d0q)A0J`Q$w)b/`s eG2GcHdzz?[Uy 3̻|m6Pbt8矫~7t !4 ocVpșB :cXA/'`0aN!;ðClS|1ɌXwTx q p#*."v>s^_ALp YV}*m_ #)0:m_J,{Cw}r9fȏR(g(B#%Pa \IAybY㹠92E,l@݀bA0l9sTB$ }i0<x_obǨ8WX7sթ\ 6\7Y5dT .0VpW@WBߤm۶:dg/\R; ; ;~rה {Pi]{<~F=/P nLB!B?UѧX?U 4|?.]v?SM|e $ ѷ}]^"W.,^䱰*PSw`}Ho;o޼di U}A߀;έ<4Yf)8ߗ_~N::B:Yl'5cDP 8رc͉@.\,N5Od҆Gdt9C3{!nB\n T &  |C+oe$ -ؑư Ю/yDTs(!yB![4"pWU9T0"\GM7]wݥ)t?7;+wV fm/KGOsqD>N8O脡9ņ:)::Zyъ &?2]acuV^M`@.Xfױ9)\b2؇B|8 Mc۸UcBQ!t1#$|xT?;HꜾpQU[feh(j=tB:'–?^-B9SCE0|Э*ח^MnY-w ,@E,^mo %qF>(Tܶ 9r|ba!cC P*4uTg衇-[oT~pQ5al)*‚Gad&#Qib=%I_> Ha• ~-\#~J?\B"#.WsS$Sª3ŷ75jP}AEȄu{, E% mW?.Grr3#طc\&Mȏ?>`<_Q۹/{(%Н5ǎ0/jnݺ)a{> ~`:)GQ: ؏XoyuJxryYL}^l<|R]dl#_%쀷j)jĈ8]y -KMʲp c{(o]L}Jx zOs0\~vU1u]~;wV֮];B$]}eUST$ nm*m.V 7\$d> :,GN@pA]%8Ic,.(Lj`OW.bwv?Zx!v;j_~:7lm$f…Ճ-YDB" ? Š&ƫW^y껠 9/Kv4TPXaڃ'%3@\ۍ7Z}台P*A4( mw'%l.Hl1"rN8K/QF߰SBH<}~ R:|tuޓg, EWuL ;"uʕ+- E9AD/2-pEJwhBDaX_>}N [U)p>루 ZBCǎUiӦ:Yl?vZ4DPJsDь$0~!L8p@ׯ_o(ʉ$$P׬Yc>(* vL7l`T aqNƼwܡS|ǖFe˪5jN!8 .]FV.EQ/L?OOF+a=R9onXi[vLglyv~ΐw_^[nEm~jRҹsgBq"Ǐ@).ʹ:)ne97 )Æ'- F}F`f=ܝ9/pn?M(}v]zZ3EUvg49CXh7[w.F\aB ZUek-.%E4q_0`W)2e^i 3ߜ*vbC_0t}v*ٳDzݡ+c8pORu aueg٩<]v}W\iyv~ΑډFѯ]v!\m_ۢ, Ӈơ|H줄kKz%BRhw=SeЎS.TKX{"Q\"s}RtP|RJtw玖u`I\ 8ץ༧+-[w&K6%nY5fgʐDhi~,q.Mz?Qn=Y,Nwpk~&n+y)gת2`XdAĴ3yJUGf*"M5Erofzږs?'Kwk~>27w Q ooF秦sݻ1R\S,$?p}Z㺿J%]EfA)^M^kqPϊE$/ewErv)>Tyɍ~#]iJH_,5v(iNY$/+cW-zHn:zص|gNn1sf8ְ%$NO$)ߔ|R$ٱC;Ԕ{M宴&FK8{߮ej ~sY:tHs{t?(F%J U&ݻI ^e9!NF&- -~(-mSy5%u4$鲞sĿU=ߥ?0~kU~VRxv ~wxvвmsol)7pyiM*prOM,{F*\Z[)UVUYo\\|~2=vَ:xšW͛(C\mDF;/տq-%WY:Նk-u>W痊'Z[mR F?OS<}-\PGȍ~_@Gq.paUq:NAQZ^0͈KzMmf6KTujlƴt5%%a[ib N]*j$dvo 7 pYVǦ8WG۠/@65-'m+DII`n<(ߋߊ&~X)ĎxՈ<ޫs4}hK9u%)FL7J.ݪ;׳k݌~Zi7\*-M)2&RZ;Ƿq80v*z[2b}Pʔ5S.;YN+J֖u:1F8+f]PEJvL_Oߞ3JTzY,F]5i0D-s#R4#m`)d{ Lc%uJ&Ng&&-ҙҠ^\0-Pn/+k]6.+>0׳/wiSI2}Y}i1=~CccL_,ե I616V𓸮\QS~"R44hn\r}>Kxi b>}ڲdbL&%K6VүVDECe=~ۄձ\9{fbJ} )ON%ts!{NO-qWO|WQ12oC&>Rb?9VbJOeC'bXݣcEe W#q\c9]1  o&I:zSUo91s7iP%iiؖRUgF@W.Tr%BG~suv=&Ə(1Jzܿ9e4F9Ee5ɍ~e$*1}/{¤e Di)m."nͿcomٲEcw/W-rïWt탧Jz.T;:V ׿0{ʇdq+vrP"Fbֆeq2a1uMTvM\ڕ%[ q ;>pzϹr)rW_}XbjK.!Ĺ]@y`3U[^+m\&xEJ׈ k] u^ӥ&hJXi94q!,5jT(ͳ!vi\+cuo?Ubm7IF7D覉e@TquN,P=̩KuF?WMM^>:.α/< '{9wx( fҸ玴e.5;J'¸6fZ~k'Ku,Ti/ͧ!mwFӯOm3v)j01=qKOTjF-k?KfJxZx]e_+bp/1.Һf}9\ǞPKCJ=i$t)ݳF2v>Vnd'S',eka:ڥ}m^1Я\uV855}=WAOiZ, WU,&QIb&ԪLD)- [RWoԇZ4]4-^Y$d)NN:>8izzkUӪ_>e˞S`GGccXyC$&%׳{"1 HVgцI9i[^MM.oҽˆ$.Z.v~uQW0Ԋ?'{ʡz%84%n+'/)na0RjےeH=cnƨ(żk,)gx3%nK/oZo;v찼G(* kACWp_o.Hw) wk9@{@~N('itn^H0Ƙ ;s!ӨvmAYƋI۟TVҹ8ؽ_Y֊I]gAڸђ/K>fj7)*I4ҽ򱒾ojm;mCyoI*CKH?z1SN; o ;!ιs,+MG˽=rɜPn{V.!Rl]2:V|1(t[ؗW$yg[+iWg4H)ΑaVV\j%ˁcٲe*)RDOZNLnDM,Lc`uWÛϮRsBSx鶒,>-H)ΑT3e|$X dӑSᢠ|4`to_K:cemw4Ipgg{y4R/6~Z)Ly&iL!su甬j(Ui)0~cVg줨RшL+1'cJL9#{s9Ի3-/'Pj*-\tZy3w.z _F; arR˧&ʐn17XMb-bӻ>… %y)#FGyDe!CB k&nr q!gIC=-H)ΑTK~)_g\{^zIqp R{g}<\?WDrgʈm+cVmptn3~a#_CRO@ERLKIrRvfkY # -bexZ緩lN`ALcVeblI.Ej C[] ѽg6ڶ. ߈*- b= f޳W3{hG!sE^OZV/$p8j]ƌ{=p+C\=эuT'fhe׭[W͛믗m۶TBA{ӱJA4Hsʝߵfȼ6=yo߮K6 Ve˖:%8xr?\hߪr#0߶6~3x.)DWJOjKWZ6IF \*E\Cu)coѠf`ꋒ&r떢y<_ǡ=c* AzOu̿H{vk%ұDcԾ}N,]T塇zHiYNliIkS xqyR~..*֖JH; a#+COOʩsrxg"t>}ڲRfWIKeH~)>Vm[-'1ՠSvi- ҘJ-?Q8i[A<+d>kAa\*޻"Ro5*xdbv!YvbսQNnoŻc{Bwo?a7|S!NĉcFjհ[oG\gtq ZXYt6+H5nq' !Y؞OK~nx cO7BT t6H`ɓ'G+ɚ','A5.S7o7gT#F-JOE#6xsHF8H7%i\?wAeݺumeC8߇>PJm2xfߵgstwgkCwk?>Yݣ#U\n Me-^|vǣc0[=[}=ir3K&2X^/eNZ 6J~O]ӥ^4orZ\^fF?l ǏG(*v҈f[7c]\?n\]>kY\m[Wa1v^^p|{cƌQ7)'$F9sՒ;  />M7W3Q*[F%#nV?/-MAk@Yq/q2qD7޻#&ݶ~VZ {2;Gno :xVƶԫKII?wZ ۪]|1q3~|mM"떖|tvڥK4 $11iӦp٥is_ZF:Vsa3]tZJgnk(K]jtmSIApd3_w7fź]V:Kk%]xLU穉]xw-%բHQ;t zgz{*{NIJFLB#a3:(F9Vl߱}5ҚlKF{a2GV &_귙S^!c(]1FC& }D_4ŋ:찰Oc+-Фz18w0Q]y|&ҶaD4VodDN$^%W⑏xWYihE6mҹ)t>|A1Bb{C:N8v)W<:fR]A*X{T?0EKۡ^q/ŏ'm땗Bzet~ s~߼@%r2cymB3U40T7-&t${OeHWIߋz7t\ vw%K|S\9\zD%YFo%Kߵp{[iҙ]9jO {6J%][r,{g/|%\O6`Km)]LSeЎSd.ly*{LR>*4: cJiL4sMJ2nOabTb ~YLNYw6nhyVq10F*?n'\cHMN؆I|%*uW7տ Ȑ/1 F:sw\獵ƍ& ̺#Tޝ'Oc?Ν;gyvQxߊVs&+j)RqT+>HlTVՎD쨣Gk9byT0UI妲t3\ښy0>ފE[2_|ͩfŵd]u!I H#ZaFڵz7|Nn>}zܹs۶Mp7}emgq^/_be8 ._'(^;.^+#']KF%Wpҽ|j(n.?'<%M;U_8 !pVNN)(dt304Y&SgPʕ+uJt߻ᆱ  !̙3M_4e֯_o5/ܹsuJp9zLް @9\sK;ZIW/V<Z눮 v[Ee'- hl٢KX0e$'B; h 8sQTUV-q2w%cqIDATC:S|?*E_ z;wÉ|駟9(@9Y c%ܚA*<4!] `UUDQv<v#Z?Jga|יNЬ ~QdDzR5,~ڵku -W#GꔌFɓ';B}ckUJQF:9vsn,ZHUaߩ;]} JΓul@ -+_.B*$uI%:s7xWq%yP@9M[d@ɥ'a+ZTjEsyC)S丣4eT8jݡ;CYO*aq] 7VCeǶ sH%~yTp'N8=4رcsQKT,)MˊEer wG&N;#7FtRtI8]wֹ&ƪoںuk2CL:UB"q 'UIl/U8khΝt楗^Ry:!!Ad.4PҺ6ueT)lCi7TXi}c޽{-)l=qb;0rl5T@F j8XPq$QYG)b{|[+®=Ҳm<}"/;~?ytj`4hѢ:`%UKQT)qj•/BS2]'t(krsV_Į],+,^ZN:ssa?*Rnݺ(… .:ՈoF[ EGGiFFhӦN!D*8KQ/x;s.$T,X@y:VqE9R엝ë>߷oeEQSIQ*Y(;Ez^ ¡]Ez>*rv1fÝsP\\N b?OQ&y⧜$oU}Ν;с׿{ʱ)5ԞB*Xk'*? T7㓣3FLrJn?hi(*}n$9"{OF#_;ƵkZ!Rw݅b0 J"]\z7ѣG׶,A7/^\=ԩSu !T[UWmѣeĈ2h իxjG;Sfͪޔ4g]H(2eM6) M-E-GOEfڷoe;IQڼyZER `8ON]@ \p#Ey'w|OsX/^_^~СCujoٲeArJ0" SM+RzuhѢ+W.kL]Fuת$`-" )dߩϞ*a$ڲ_Sɞ=.PZ.=ԬYS}˗g}df(CO$`,ܥDA@Won)*ڸq(=r5#(7tRLRJc }߄R&iV#\P-s1\L aSKjާv:%.@N%p֬YV`+v,x}ٲe3vՂ /;xb]uJxr%z,sT72PˑR֋RjRly)R!wr+LV+I9|YT^>̙3o٪ `80a巡(+at1`BbP#,~Gx1.\bHs1E#0Y͝,Dߩ`Y7k,@XMF!F@tva\A#axPTfG_'0@[dKz8~ v7Qs/ɞgeՁ׎C2aKC EI#5-@_~@N(|>&z#7Ȫɨ4hWqq%`h9ˬ=X Y{Q8q\LzU-N#..N*tj4_.]:B-Y VZ5*a%vdԨ3l0ɚ5ċ?+'yb/7n̙3uJdryt,}DogitP(nAo1q:Q "W\qE:6B؆Vm5e_\Eݔ'|ҲIz9'NIg!9Zc7]b_0?vٲeTbh\:n"dfC&]wGy2;T;̙@ ˗) t>'˴ HeL0$r@=bN8޾}dujz{_$ {u4|piӦ1*}ǏCީU*V*遻O0>sr7_,|RjU2,r Tp:>9𭬾!廰P=\|wD %(F?(ŃUTIB 4 c%#:\ҲK`+ v!F,5ϟ__%jrGRD s{1޽,YD_Ac(jʅK[O˚'kPbaLiqH=&T$cKI&IեhƌHL-ƌ#o˗O|AcB?NF\|;W2ΥKdVۣ?ʱůb Z^[zu/U&C]:ds/ɡd۱ӲqYz@&ciʼ=Geݡ9vB9 ڌ_~9Yp `s]~D(h"t;+1 V0q ܸ[;vQfMTar +^;&2_cYe1r>`l;~x5 <*V?D`@aQ2&spvX|Wkzg?u0>Jb˛7zPm_$;w'0a36 bõc {c*:a%/Nwk %s4w/ 7M4lٲ%9rH Ԏi~w~5jSH09sᢊ׶)Y6k~Ao٩ez(ɉىv0M裏J>}`r?RJY~$v2N|駖w+L0b@˖-UP=..Njh8 b/a\p{PPJ0f@ [YF [b*TȲ",pI =L#?a,cyZ "hu- y ]c J>U,YRBI~K.UwmB!B9A  hQF'i;۵k'o&>ald:ט8A-xW\qǀ $fz;7nK~*RmVM2]:$9ql:rJV8.=~PfnQCW^j@Vg.LAoc e}:}^t =ukIHHPٳg8v-uܹI0dAT2-Lz{@}:|@ c &2/Yp:,a!/we>Xؑ9k֬j9 RՖ 0qr>`b1,x,e`CuƘX}Ht40eʔ+ҲlN:_u"!Ȍ1z8[E9.Ёv1w4􁾤w4[N ܣGq{ڴifEݡ&F?ý+:BHz f0XC %wVGGGUW]%g϶<^&0X2p TUT1;pK(*[ @=Ԯ][ bw^\HFGN*Wp=eYuo׎CxFIFϩzmC/`A{жIv=32b5&}oVM{甄E01L~b"> ׯ?<gLd ̛7O0wp܇g%YNexocq%&T1x"&k[`QpʼnP"*{ SWĜdļDJ].@SF@ u}f/$KI((j cVwzT v F?2& !d.BL^L4S)h V4ܘBz!UÅ:~)>*}cB uv2UgS=RtVfM nfH_3O~uBƯceSjW'eݡu%eҽG%ae@[2*m= l0.NߴOܦlثbNXG&߫ 9pc]upx]2RFK \륗e>'57oɳIF<,0n>δ@\e:v(>V Z16GB &WgGcΝ;q|0q]?D? v̾,YDzꥌ;FX}oF$=މwC/xPQP/_.]wz* xE{yte:BJ2hBa4&ʃ{2>]&Q0OG{hU{hMШG#"w@~7(,m1_gEF;2:3quhݺuuj P B c-^X;Q+s7]h Ca;X_}1O?S31vEO|H/եK}o`{ooq`nԩSaÆr7'{ooT"vfSO=SIv 7/+Wv`Rիq=-gX;ł7BB\o6B!SV-U>쳶'7yd%J)Br,pK nx ɕ+G>+&7Vp.s$Vb0^v 뮌.1Z{.b{a5VF*pu٢E ۓO1^z8`̃.gΜ/XO2vJ >C菰pBXJ.m?FwyG=(VB W4i>JH .޽{^{m|Ij駟5uLbZl{*30Fe˖I6m$**[eϞ]6m*qqqOEzdp{>G#GJ pyl۶{ P,&j/\yy[p%8ӧOjJ=z!gժUlg'{4yd}=1b}CEgP/ݻwW;iܿίZ8M =o.x ƌ#Ν[`wtٳyB}?j_fYzh3'`Y nvܩ&$0YFK_ra;T)VN!$/_ޣ$Ġ"Q.k]e˦#v6|1^C5WٗjժY޻KI2Wy*@_{\}RN7n>?w֊+kʓO>v5o\sؼ%4tP}!@tx2sZ0t !p/%lBb%,TX1Y*ZBB yԄI'|zd駟V{7oެ϶7Xrm%{+zr}=ٵk彻 nHH ڵkGY?ƮZ^`&$p 6hkU Ah ,ΗB!$m&Mn\o> 9 &Q&.!v  .ptK_|QRLL I㯷Q+_?7o>^ ; 4ȌWhQٸq>b $uRz=%OXd&`裏u0`c_$]wGҬY  6~i՞B ~\y啪΅+UV#%FC !a„ f﫰۽!vdǎ2fiڴ瞏]?,N:%sV18"$4h,7xC-!ٳgeڴi;$5մ9UhN<3!e95If7={zʕK|M1c>DZ="' IK.ɀ.uwӧ#G3?]]5/B=zN!$t`}ʆ]bd:uF]kזÇ˦M)cccCUZ;9q/_.jժy+Lcw \oGEzkqB_Polْu7!}ԻGn 2lիz9M4)B"W^y##!Nȑ#믿*W_G۵_LveN.!e˖Ue_ٻwj,tp&ADq߇Iu g)oVBa@5 Ȍ5GHZu1Xq[o%W\q'?(!@b 3mӧ!F^zIJB)͛_!`;_yXp jd\n>?` U<4$ؽ.?6V@ .]HB<C\GrW%K* =sW";wθ҇iذar1}6!i3qD|䏸y!C0!CwZÕ nt !H}ʗ/TREڴinl߾]C3ĨrʕS>}oԪUK]O\{„ܣ.;u&$،+FC0ެWٳGRx2ƍS;gTPA1ء c3g_"̪UTRfހA8q !$ٸqG?x>dwQeB֬YcVnٳ}VýA%ě/Lje; ȑ#ܝn\➗;vh?J땻FB ?!,,zw =S o8p.&MP؍K|HBRܹsr 7x/5j(k$A{ܥMV !Z ,]GHH C:T ê^B!♡7L4jH e@˚5>V\&]O ag}& .g'JOb^~eo6m*۶mөI<8}@3o< nyZyѢE^XլYSչ{b&긡p.f͚%۷x?ҹsgY|>cUe?"O?$yUyw ɄB?,O=>cup'CF޽{A=!DXMڊa:cRErQS&~WjUu.>I֭[+T;˒o;#`CSo ʯZ(^(rxNB wc=^y-y)${߲e>J!$̞=[-3݊+H#CF+B!$(`$ v3<%FnrψG *֮][>Ξ=+3ķ~[.\ Ι1c2-ZԼ ԥÇƳ >sy'=wܡ+``K@XF|ƮB!7xlaĈh!^^"&!6mڨF BU4h  0;vlRM&gΜWb/vܩ +ȳ :#$&M5c^SK׮]Wxp2^Zg}g=Wܹ‚)S3 Fя`W!xsEa}x2r-eٳGB!"|jׯS!ŋ*VfT M+CyQe :;VȧO,|m;u${gD66=zTP%BYhj#J(S!Q}Q9r3VA#BBͱc$[l*oN8Q6 0Wb#N-:.XYx>۞D#^-z1;}ri}6!Ȼ4Ep)"k֬*` ]|YA!$ =cpf}tБKElB!ĝ'O6kK.TBHF3UΜ9СCrEr^֭[ԩS#ޭ p}93ٰa}=vAwroNsyɗ/ʇpCKHJA(`ӤIT,pW]hXeb }Ep Pӻ}>ҷo_Ӗ'4ESkf= B xF[fMկ$)n8x͚5)BH=j'ѱcGU^ybڵk*ZjM7dvC Q;Z 6#GTy/wju&!޸eʕXdr߆EFjqW;3;>H#lٲңGb"a~\vb7fo={*BbXP!}fgHѯM6eg:BIF R~m+7":w%8֭[6@gϮ/_\A!F?cB!sN!֭[O_O>D|I .&7WlBO<n$qCɓI(kVnV/mܸ}{n}E 3QJD̾-ZȌ3?4'XȚ+W.mN:B(h7}]ɚ5k+;wM63HzH/**J}={B!$sΩv+"z([r߿_fUD5bnnoˆc!5\\#=~_ѢE3e_~E7o.{Ye;nF?_kfɣ ǏgY^ >6bubZJ%QiڴٟĆA,?qe;y_N!Bh/.]S!Weo)QFI cWٳӧUu+r۷ӧUIw%U<;{9:t({49¨+mA /n֯pGkP&.Շj֬N!BwOh/0QD ,mȐ!:%AlH5n0; P83bF" _%1߀[t>B}E47o^s{d7w\RJ_249%F({EwńN"yȑ/C/3II>P #!X;)@矫eݻU_WF?{uǰa8O|J“>}UW]3b9b'IETo.\ج[ UPܕoҥKyG<~n{I ~+ĨVvBnӦ3U[;v(>d&2KaA!D]y啪`P^Bڵkut=8sL,P3?8q>J!Wl"+u*/@Fg3I(Hѯt#" !p6c…:(^xU̜9S3COՎY|*Ha858z½' .6lP #, m۶3xǷ !F?{seꫯT|Y|kFՁXD!7po:uȵ^k+.U&$$3IIoWA !z@BH`ABzuS>9HӤC! ;?3gȑC}ϒ%Kʎ;1 ,:ר[w?ډM ,4|RJuaٲe B!is9_70uC oՇX~^mZ!޽j7ZnS!b߾}e˖T_IΝG5нޫ\bb o{̙S;S@7ÕkFW>!0uI^~e馛;Z72ڃ իW_!dlj'Ԉ1vBI3fH-цIbȐ!js6a@-[6B!URӠAUzS \wMqs@(P@5j$cǎÇI]Y V/vMbzn~W!`E8pńxWpas2eʨ2W̄A7n͛W}+BGG !Xŋ+/_^bccXAm۽{y)BH B&|Q`, eD?ca"XFAa-v#a*q7nEowm1{&3m4yw;#+T }2u5Y ϟ_ ٹs4ك-[(Fv}ɢEQB!,_\y^|p:ԙm3&o)S!1:tHBŅ Ve,'1ϥRJ.pj֬)vt3}t 8(Cm۶rlԃpZF 56ǿO}l޼Y TΝmc0yWWB/<2tL`A.0b͔)SM6CyM{M*EIFЁ81KwڥBOꫯh 'dʕ+'z+V3,N{NnFɚ58{&$ҡ/ٿĘҝw)sG !$9uL8QZl)Ŋ3J1Ox 3f 㝆)~? !_ݻj;7oS!GU ."[*#DڵML{&v \XdH;(7!!A!sru\d>Ӛ`я? OPN4I_AHdA_q%8pdϞ]s,Fbg3!$2AoV^y=j؀0>}Z_A~ꉌS!d;ڎ'|RB'|￯S"s1bKf1C~tI}'2$`jGK2eԮ PWa /\VbkN0yQ0Hogܻ(ym۶+ ohxꠍ7꣄y݁իEFP/7zhiÁB6Bۑ3gNB 4*g0lD`9rZ@ؕ#ӂ $Ԝd&ϟW?| $ & }/LLe/[Yn]eB@a7;ׯWs=\B=zpq<4tw!w 8qByС+Wά a+e}!Im3|:BIM:hJnRI8SIj _-kVjժɠAJyʕK$ï*7pzp HTͲw]2xŷo,L)\;~mߔYB~ٳm*{jaۥK~,^X-UGe˖O?qOo?"}:BIcRƍu !$ꫪ >\_پ}re /W_m0-#FPIk׮: Lk[kU?@LN{W^ N2(;y |ͪ.ׯlڴI_A}/0̙3Ĩ̈́n5J Uz!ѯE*a"!+X!PjԨSHzؼytW\q9j2Gg@ ө$ O?u]'cǎGHj`RgϞRlYn}QeZd>3sp炋*]5bw B~ԩc[ΝBq$CBOͷh"}!o_Æ UF%BCRHU86l  U2orx9}6 Hh$,[̌߇$eP`bйŊS;%C99F?oiӦM^nh]/}`g9&ֻu~!$,W 7G?#={rmLHK/LUB?+ӆO?)$P]VMNyOh;切$0XBJꪫ>`Gv!bvܹSD߂ *c]{8AZĸoʕ+&2{%!?r}e{Bc_|Qoo *$M6Uv.&o:ȤN!B|RJ :uN!ĘBY9 މ.\ $;Xh2l,ț77N%n=$kז!CƍU~*TPv֬Y:BVZ6$66VBœO>jeϤ| zSN`}&촺kԻt*IphO [Zx0e_-F2Ҍ~^ZQ4?3gΔzK .?{w]jԨa`2dXB_I3׷o_UZlS! k#Ǐ)`rwʕW^)N!vbǎjI*U< 0`$Ɍ}pGx&i [oU)܍3K_Cz&MրLҏG"臝|R;!$`W7|#͚5~جS}C ]yHo/ B!2j(ՎE >2wXH`g\~U vvޭό,0ю-[6$r9(nݺ# //G|믿^֭vFR(i <0t1b 뮓g}V۵kD*F4Z,0;'LBH`gꫯV&q&FYfB↑n BH`Ĵĸ^Nĉ2zhe1 j~'9}>;2+{OD60?#f>}>^ &( PjՔ\LE"{/ ~U$c#cE&F>˗eذa3gNܘdG?u>B2u ӥKj>TP!,YD_MHdD:BF@|1!goD6o,SZXU;݁{k;w1o6>VmƍH0e宩@P?sYz>3r1 ~ERpa r-jm xXN9s樝sG~GUKx?4L:0@!H>Sw'ƷgnꪫԳbRq!04rHiݺ2|f.ʔ)bg1B|oU˞=N!$s  !ΤN:-;vNI囐ݗ_~S|㒫<^tYX* vB[+W.s aw޲vZ}fes1#u7aL\G~[[~]$ױtyW~P΂]ew~}d Yl:rJg3ry9we2Р.FZj 9tݺuB B˖-ճ709s^v:W[ʏ ]OW^\=7&4W^{O3]M5b8'|re4WLpI`> .(>? oqBwGa>O;!~ѣG՘… `a*Uq'~8s;{A:+ێ6G蟠qYj+GB}6#O˭`[_ Fh7RiЌ]iU?j#36W}9@;4զM%{N]=nVӪtծSPw0яxgO< 1S֬Ys2m!i p`_ILyɭުn]Ɖ`Q UTțx6nA;`xC e֪Bna1$8gk׮mΫH"jwK⋃ɮ"PX7L"aH4h #ce#gFXaWyn>}n yx/W_U3C Reԩj!$< .&MAgΘ^M޻o(k=}=_gBVu0t^2 rd0ra +a b0@f5¤VØصi5E|qZh!~ ^P;f`D/ o$U&.XiB!U[o߾;hCI`>:hK/M a\_8~!BHIܞ}Rpa\qH̅jCKnѮ#ʳ@$#D°8W_ Х{wR,F̋1A,^%Gqnh܅Ei0 NtLHHqPap$a;v%'3[xxx1dpU 0^a%9VMXKK1GX$5p½Tž#2{~*eMXGrd u"I`W_}aб΋/gLcЬ򂝅&ds {F>)]{̙oW_}ԬYS ֓wv6Z'(!a$B >.Jڵ,[L_|rnKԓhӱǪ.'솄RV\s87˄D"͚5K  M6{ݼE[=)>dY`b3eCMrl%0D3d11dUV#U+La/&P~ah%xXʸ!ݤ4U7xK^lBtѮ;L0G&Pe6G^P7},d1{ WJ$Lɒ%$믿}P wު`GDB+L (#.TRe\Ƙ :d"D]q` \co XEXh75j6d˖Ͳh#$H>Rb.r7'#[NCHb2%iw0!Ix׃0!V \$YMPԍ{Մ$bq*E;L#03\"~b7Z}p\٭:p\^Hlz%W^yzpiWwIp1ؽ{w)]_ L,!}ҥ23:Y,9nGŝt&Mˍ7Q;C}]O)70-'E+44\ `n)Y`=B"t~GUY<: 1?]Q +anF]Ď x0T{[gqPVs4~5ai9wy,L@\)rpr^}#RCΝ;. kxX+߄D'$`,˽Q.+B^x1b[(pENwQg22vmC 9[kBHr04|UëBZS1|C4BeêNT"~N!@"%[N#'p7QVߗ OmذAу0b_kʥk!G.d'&!2ѳeٗ;DLRA#p͚5PbŤm۶1{ͪ8 G5je]ŋWvpSdqeEQ grF@BLX|/ңGiР3gN˺\cw{oe G jHryr$ ϐߐ7DvR^9yV{]*][}9ًh+yȐ!*F1!M6|V?f$ܼ_vw,@wW^yMTUӧ3,B,_0aIzZ~cҥK{o=j LwڌۗD3'o>(?c9CDģ(`AE@O ""pX(P@Aiz @ {22 IH_Kly~.°gW6W_wuߏ9եK7oȣ#10*KF/@ʖ5b@(߭e.Ӌ˗/Ngռ뮻J*fcP:Ϟ /9f̘a'(r~3;K/Ժ%riþ艴 !n׺~ {Sb)C9$dz+-CnGJ.pdO.?J?3"'e1R\煹馛*W,m۶I&E|qw~g0#as!pɜfO /۷osvj ya85_|^5>ssCpxw:uVB1z{ZӃJώҌΑC/L-ŶрȲ}?T?a, \HDK#7h袋$&&4|c \o7=p$2{g~9\E"^/~eҡC{ZjrSOJ6m*=~ĉft/;*Vhv .n cO7rpfCbZ[3ն҈"JGJ>'ÇeرҼy-~Jo~6l!豛eI(u)ia $DG[(@OxX7N}]SԻN:wJݺu_~Y.? W~@8ܼyI !tH k֬|qB7ߐ.7 R( ?leI߄4r~oʢEo^ 8ݑd[C^6zsmd>Bl>sK/P]t]H׮]塇2C_ve!6y+&M3<#}Z-[f:l@:^a;X=i-[؞B45#Mѡg#iϔC82uQkM /:{&%j]/ԑ^zIf͚e}#e.$ΌιP:ٌ͉BHnV/YydZp}iO>W_}Ubcc;+CozW6h;ߐ!CNYf-ѣ@H!C\v|{C\ٝLݸGYăN )m 9vlڴ8; +a#n.3Gfffo!m۶[W.w^H.8}. ̙cvg}uKЫR֮]k{A;֭ H{KٽoBܔk?KٞlHQ圐?s9/:o"qG"yr̗Jȉd;{ɒ%2yd:tOJӦMf͚R}ڳO{h?tuBE?=..κtRwzr ^:'ApON}Β_2'q_~F%ھ7R6ٕa}3ҋ]~ {zj9|F=3eV<)K^:G!ӧO#G^u>{Rn]XbH.{:s|:7ѧs Bw{nq4zRI+GOHEp3aaI=!nm)}옵F˶l)<_\Jq`)ҬLw!%yےPVhK:_|aԩ *I>smw[2E:p\MIY㳎'ؾ/åB2~gn^vw92oM!cAwam۶Yr ~Oݦ#5vS)l[OtXM6… eʔ)2bSlҥ<r=Hzwy!ź3ϔf͛370CjnQ,E?|`\:|I!hRRq0prJΰk بQ[~U8ϯ=gmWسgF4_aEi.!߮^OUVJ5K\22y)_>}ɉ^ d I &% ڽNTyv"q0 PlҊ=$N-# M6YߺinmgW97|srR|yGwuBCѤ$yfktd:IXOg9E-[X[s0U_I:t!#+uַveP+loޝ̴n E7?WY{>VS*U2$:aEv' 8~rjk}?{zHϗx1~aJ61B2q2\-j||㏛}7s\X\%ڴئ ES 1Q:R?-汞E\e=oqJhBe%8)!݁ %٬GuLđS99%u2࢟<<{\tzҿ}{HnuZ3G}Q rkG5?ݺunq;v؞('Keri|U?Y/i,r9a&VƯgҢ-rw{h:X~Mj{U.s ZF5V[ ?ke, Z ҲV9`g5$iCZ{T.Cq~U-WG?SF۴-k?԰7{+Re4|E= nmmΰ>%uMJn[]Xc76?9N?_BޫH*EQӥu<.̯=V)zYV 7b㳞$κlv}=y Mtx~:}v{uW昧Åx}OͿmz-+ZNgկ0fA/Hv-~t%9z>'r{<8e<___tiT|J#wMX-ùd:Z=jlqi6FQEO>8ԭ[׺Yt(AůWʝr3hi,ѭ.oYZɝ'KZڜ̍jk-1{d=  ӯ 3{7_wjff2`$ s<9Ņ|E9HW˦ 9I ^m;oh9#G%ՠ+|='ޢCbMge"nws-l{}Oߜux:ݞ ]anm_>넳}z."nu n\4\be_ȳW\:G<Dz-y7,Wآn#240E7$!!Bގ'iezs`OxӾzzu(G`eCKr ܓפy۵Q+:FL,w*HA,nK3)ϳLUkr<[]VNr^.W4EG9cͤEϠf^<zeCJ[+^c-Z^ɣnq@AkO9s)S[c͚5' ns=xfTpLY/eklN2 mm5xݾmܨ֕u$vbyz~7陜^jV_V|?|_3K es<Ǘ=㽙Ҷ 3[.ZSmҡ>D';Ipk|E=b X܋NljDҮ9yޗ t@cC24_Whd3_q5waE;Y@9ws=jmeiCA(E\Wul[n;~O W]u4^AKC8 ٰaw=wvTm򋷁ɦI~ 9y_MCypmW~ޖ_Ɋ Bӓ*/v V9U=xMy7G?UrZnçͲ.Zv;h*I鶿geﱈ݅y&s_6օME9O8RQC۫;SF<ŵ.\q~:ǠϹ'l"߲.Z(~|*kyxE?\1IaM!or|8` f7V%Q<ŵ.8W|/-NM~pMTE?ըQXou30v' n~I@q' s5Key"|c&y/}S Ⱥu-lqx]M^rP_OYr+颟5qξe۶mR֧۞;;N,B۰{W{O-y_Gµؖ8}xO~IfxRXn8?vkrQ q2!u.s"x6؉/%ȑ֖ XoŊ@9?[˞~mgoS$ߢ_~ 3'12$.ϓ[yt^eN؉9{z-T927I}-س0nk-'~EջQl>gZ{r$̊~Ncƍӹ)Գy{ J/K\\~jv ~"6T3ۥx(i7x=NϷ?xrܢml5|EId!ҶY4l{K-ܢ'Kd3YX8i>?)i'qf{T:w_{F/:W 3ϣ#m͕3kfR!xl tU=9!hbDޮ5L~Z\j#Ƈ3ƨs?_w=\pQY)m-u-"MmV{Ihyyd3&Ȁ΍bR,mGߞ-oynwٱ:1V&9jzcEkѣnO !>蘧zޜR) V,W/~MЀfJ+}pE?s~`qT~ks\G/b,O*4!]'.ўHo 3񀵕>%VS>9xW[ʞ^ hw ޡn" gqz4~cz [$d.T& rդ0"AܓƯN4y2=Jh+]7DKCdzR8[h,pqz6U{fxp4~ M[bm. *W4)u4 ۖ؎rNkH߯ku])Z- ˸B;{+l>V),N2799u::E]M޾aP< 1@+cA2Z?+15^Gb޾{7}'ނuE?g_0n'%M o-[g?R9@[,YC]E(Ͼ3,NU=o`jI/3MA+ee۞;6[ & mX s֑rZZyt^㘢;&H}EKA6sHti|c9Y93셃ăm]Lyk?\牗AImS$U{H9pk;i?{UnOh|ߟ-)mc r==uUF?_qIx5FjXz昬넠b{aCPX%ZS_93fuK9֮]k{@)[qsy۷5g%9e)NkNfQa :!ᔅ;SyRf8S{4' IJ.Sސn BJ7 X[%UE~͛[8Czz!۟رu焢_%11kC'鄄K&Oӆ$=233mHDͲlcBHd=yBP%^Ӄ?4.^غRRRlO !%Nވv8#J&ngK$(BFN-g;f}cgu$i}G[#))$R-<(W}Cѯak'13l ;!n #3m@{1/|sN[?)4!d2i]J T~+Ws=4~֭αw^ۓ BHE3ߪUl),#)k,.)pwkwoVޡlt޳mO qSr1j6wGf]O.M;gG7LP\V&ݾ !5PP(J觽|Ufgj,:/MlO.!nO:iOv7gƍ.y8%)ƭ?iH-N4qo q_mf}C{TgBN,z]԰aL磌rz{= <0>>رZÃpgI=!NΚdZg{#eC1=6#G^#82unٶuJ7nl u3\^#С=NHH}߄)~V%1qGtε25w$u)/"78?+W ڴL\`B J7uTS;묳dŊ֭E?B pݗyn:WϱYP[Ii#΍efYklxؗyD&]YabK֭[m~Dlm#RLߴ'.xJbccM'nq6hΝ' ?_F,'ݻ72:mN )˄pyٙaI痭rɉ vgʼmɶBHNt( V@(34iӦY:_FFl߾dHnƍm?Bm܌!Ȑ7m 4`{JyAOJ.37'ʡȜ(;&[l$ʾ}o-r^P=b9[)'490U&E?+_&M[Cchy5%&&F>/B"k֬Tk lG{6 Rҙa)E ş%pKs:7:o*̟?ߴ{rWw!>A_-KG$ڶ̎gnUu~,}WfEdR9O[E{ڵHDDs]ul3"RYv$%%Yk%̒ IJ'zc.n_gV| Emv~O7$I kf͚O?-/vE^;@j}8:g58#۶m3֑N{N$z\rյuͤ٣O)sl-)vʞȞn;eZS~9իu0$ I!|u^O K,Y&O,cǎCʻ+tZh?yeR+SRRq45"R|aL< )H:tX3f 7YI97ol;KJ'RKϩ wőu~D)⪃t Oe^Ӣ tĉ֭=}t.%kθqdذa2`y7{ /SO=%?hB.njժɥ^*w|'Vڛy˖- !E^ _Gi6LHa>s$}~}yiq;(GtDX7\\ၦOn{u"iժl*Sed !N41=ͅDʼ觴zn̐k\=J<$8CZ"oz%f JG58%JA c]JgI(R(.,萪uٝg%]v|W3:p8K&-IB:?l-vcNE?ux%<>|uիW۞R?6hjkMGAh۷/ Fݹs>GԡOm RLO,,*ݶֿ^C}4R~(&ӳ/Bӹ7Xv!G>iёWη Kz{2e=Kk"4E?엄4 }6n(?oaJRQcyRJ/]IHH-[H:ud=; KO;ٰaH"+6m2C1ܕ3~a8u pglw^rKO7;ۖ")+sÞ 'zNrAE0a駟ʃ>(gqFȹVASF g-<BqMru'B#zq۹@ w};P2eukdцme(Pr"Gף\$HNtPR-kp +ߝPVl{Pv6^gʆ}3-C1Q_ [>g^."536'\$G5?g/ZWHb ׯWSN 7%/Cf{iR٩gx@pTOyVl۶ͺ52ax:;"D뇮'zSX .믿>䤱093gCqf0ڵk}veE:zL8dv~n h#%91`iذN:fn)-}77푍FL,Ff(XtOF-5o<ѣx㍶zɻkB [o՜ӕl6;= >q2%oHH+c;,-ni&GfYj9QG":Kiݺ\z!/f>u}LA~O-Npo~~})hAS $::/H9r0[lK ]As޶tum" J;|B-A=*s)=pQ<'.tA{2W_m_E/,M111f(eΏ鑂7;h.Z-}֢WY\4URn.32^Co/a zam~$bE??_ݭ[d:nG O zbC="DWᵠ':6I#'ZdXn9{[oqx]N׿O}}௯K_6׏P_}\p'ڃ(7n<׿595j2B^\ ەn۹6vۤs忍8[o޶uy}Z{ӿHL{fC*y[֧@7-jx8gK̊O4 eySdoK1qwy>mx (m8-2KԩSC~ xgl=럮~lye֣A_ VD7x#wo8p()Z裏{ˇ;vңGYb9\YSzU{"OZZ9y=܀}MݺuP({.dG ڷvo}xG֏0'}vϤUVO:$[E7o"k~ʿK/YTK.={JZ4\pi短GsK5z"FEEJ*[lx`(UVyR|}0R\]S?P;w?\タo`ԨQq@SLwj]^|E3 >Û+Rz)6m3fDFr!vZ;hdƏ=L8Qg-C{uY!GDGG[F8S/癗~۷֭"Ujj?^~iVok\P@ڶm{SN+VXȤIކM|ի% }W!BݻZF޽tInѢ,a=ȴeO%&&F.첐 [%#~^=o[t7|v!SDD駟L(-[2l0k ]v<̅/A1Z߿4o\? 2P²tF߾}[va ӿCs.[nwӂM.yR:RJl2?۰aC3$~B ̅#/%%Z @i ۢ9s~M6Ȏ;&gϖRjՐFի[o%qqq>P/::O{w-`8O"Ç~Ν;ێ+$66ۧ({a]S7o{ǜ~XYF,M6 iѡtoO/$8Ͽ/|@JJJ/Rڶm+ժU kj֬)۷Z ӄ}ϫcǎDbŊX߿_&N(>o i  $8C_M7d- 71cFp-6n(jJ.첐o4\,XZ ELO}gyym4}wLcÉFUD̴7`}VAzj: ys:GksgH&M_B5"̙cz艍6ՍPRѣG:+ > E eoG$@ <ԩcSO==ѣqf}wTTfH-[XKp+yws… {d=zTf͚%/T^=ESvmx>|k (:Oi>9yu7;tLH7o0S|y3 qdϞ=P2x㍐PaxbD:g.]|y6nXRRR{MBB3Fڶm+ժU 'kvɄ $;;Z@袟zɤI{tݻW;СzؿFswJ|,Pjժ)Lt~88Ӷm|yr)ҧO9vu/7Xn :TZj%]vY>XZyD.~^auV^(]:6vm :+ ?%htN 8~o<:ygK.<h7$tFWٮĿן㏭{lh/?\bccC~N>dyO>[K@o 8x;311Ѻ={;C]o.3}~?Pl&,3gΔݻKڵ4ח=z;ݛ<9pL8Q^|E|Xŧ<ғgE|hoyY@[r|rY*TzJƎ+v9tBtgp]t/=ʎ;d̘1Ҷm[kռV_<@QQ;%KH6mNʞ|Ig=!55U[y̼-MӦMw55((~Χyvɷ`{UVz{?u5CjGZKW@ .'xw=j:t k֬o[oeroh;vI&% E?g ^"=O|Ef=-ͩ* 64ïORP2(҂ ĝs9K/p*> ug< իW[K@~<'diA}֬YҳgO;N 8Ҕ/_ +YK@WDsΕ%\"$''[gaf̘a.X47x˦Q"(9ϑ#G^o&Jί"⋶LK/O\P(ٳg˃>;?) l|r}^ Y:Q D(~/j2I'$ݻwl^'b˖-2vXygPDTZα'WLLttdFfL|)))7HZj\&MH>}|"E?<>l}a 홧l}>{Q+;'N yy%!'M$/ԫW/ěf>?P/_n- ტ_)Y~&믿^(III֣?y6裏ʈ#p!~O{(^HuV^Jc3}ȼy%(9ŋKuNYfYpa>}tM֭аYi8q"@e_Є޽{ᅲ]ʍ7[M|A䇢iO^zɵ^p Bze5kG@?eРAf/wH˖-?+WZK( JI1'P۷5j{C~?gɆ %ALvK. 8)eԨQ~RRRo1=暀^zK/}$EѯP]tN:| pvZOʕ+{Svmӣ믿ݻw[KNE?طo|H"o&oSN h48|pS@Wvp;K.^^xoϭ*`'==ZP(^9;"ы bccRJAnH;wAѯOfb<9+;vƾr]w';9{~[,X`- (i\_~?!0'H/ԯ_?`?+M6Xd-0(lΓp =:uVoQ=>Sٱc9(ܯ*\reA/>}+r뭷y>d?%ဢdݺuf@SN hx'dܸqo>t^ԡCʃ>蛋?ڈ͟?Zoرc[oeϞ=7ߘ\uUҶm[=z[KE?*m35hc=ftX<?Zj4j yꩧdر~k P˟5nط_`8O$=V5jiF*V[sKΝeĉd- 'n!wy;a R\R{=3k@#i&wu7._Zp?~y o믿/99VM*Ug1snݺZbb 裏䡇  odȑX@{]t1=- jqO?Dk 9(0`otDAhNwZīPB]!C/DPC:PիW7W;Ϙ1Z›6Ҽys9 ޴G^;pCͻoߞ@W_-O?=Z㭥 cƌG}T*V?kLSZK%#Ҋ~:<32ݻW{ڵ۵_~)۶mP͟?_}]/ilLcСCeʕR~.\(ݺuu =\{M;vXK#~TRż_,۷oJz)9hO-j1P8 E?J\\ڮErE4\xᅦ@s,^Z KjjAww^ȾN:ҥK7oPtR6lMk53̭]V>S[o5C.ϙ3 Qiϗ}\XwM45:tZǬYP:g~P{I?2j(ٿPp^}ٳ%--zpUVI=~!SO=9Q7md-_Onݺog8Oٵk9 ϵ^k.d߾}֒7~x >\ڶmk4׿L#lzeeeرce˖s^}ϛ©~zVy? 6l#GSiР_~GZKY(A>,7]z!\mifzeo=ϢEsRzG]JLL@:,^~wyq={dZ P @ux(iӦb4:o6BuCۤСC宻2뮻PZӡ;u.7h׮y:̂ ^3*x'\xˈ#dݺuR E?t/R:u$7tˮJo]<u*2D6!z>_tE1~ܸqa-pX|ګO_?y:esϙ9t_IAC(F:Ĕ^;Cl4Хhv*cƌ˗˱cǬggڶm{r7"~[V^m-7;]~c~!n3gٳg|7f38÷>f͚fiӦɁ%@aQJ^Wk#c=&^{|ɶ^m|Go߾?Ν;g4iĘJ*O?-SNҒ}TR3qoKII}4a,ڙ*Hyےe$(7푩wu۵Gu 2enq؜(䗭2{HŻ=eeY&Seރ)3$hɕun޷О Yz}\}{yYK@(#+W4ÃX:65iǠ#GKʑ#Ggg}={ZjbƍG}$۷o@QedS;d zZu{9Q&O09G ?oI;S15]veȾ#rE[9'u;묳γBzl\ :n-JE?AkzFqo4vhjժɿoիid8=N%cǎ͛_אWժUp~[l_Qo}`{Ԣ:wN4Z%I~ۑ*+ ;=Sg>@'O;Ϭ_k~=(NqqqK/UW]]k.y衇dfcPz(.i&8qr6^ipvZl,ZH:w,W^ye~K/neԨQo>kȢ]9)kLKش+hS(!Cf1=LSvO'JE1c"n__.mڴKBB$( ҆%Kg}&]t1CgiÛ]F!t7|,h?X6lhҹOs8;hz͊O-lOg)G2PVI0嫯2r)ۧ;n- fd…2b(w]wɥ^jp9G> qF͞= i|%tNXرV2JBZJ:`%s- Ȣ>%].]J΁8d3fM7dzR.XZ 8E? B߿駟JNI&ݶOsgH:u}ʔ)Sdֳ@ضm{rnV߿/NB)|m!>UV[oe~/״iS-_Z E? ¥?yQFm93nݺҪU+y?ˮ]g⣽usg.2y姟~]j/BP RrGs˃>(Æ 3w3w\:tiT׹*T`hu{ -:x`>}lذpիWaI'$s)^$&&ZK<-mHM(5߭e~ʒ~A|I)_|6T-`+ +ڮ];3|ѵb IOO F cǎ͛o9Nۡl٘.(]&KE;@+cƌvT^]ȴiСC֒ \QPlRRRdW_ɛo)[6oUXѶ1?:7,=4dDPa /ҐB~;)##Z6=(HeҺYkNϴր}v4hvm!77x "E?BW\iz瞓MUW]%rm7s\{ҲeKk5k[l%ۧԫWOc =죲:9Mnm["9[d˾)`j֬i|r]wI~Ly~A xZӂ>-5vzC-jO?-o5 Ai&3 6{li۶wy!TSNcf{mDn~ܴG֥IV vѶFxNn޼Z E?C|P:z!@u(PԮa48ߥ~f.]| &Me˖IrrWD"Q{Fխ[vq_|F\t@+Zg'߳:v]'4&%%YK䍢WKOO7ÚiOyZgאmpVCj7pyԍ{dރڔ}ȑ#B~kLO~;-iO yZžЗW[_kSd`tX~ޒd[!8o.ٵWg<GJIBB,]T&O,C W_}UZn-wy_RByҮ];pȑ2c Yrݻ6M)RqI9tZJE?ptYn2fywC-Փ.LN>dB`ptѫJ6l(>Kw}'-;vX+ΓM&K25Pڵk,Y ':x`y%66V7nl[*U$jՒ c6mk׮fXӏ?*駟l޼YgJu)iNzEZZks?qR$ak(v)˗/3g_|!W^y{宻uʕW^iztIO6ÖVREի'M6VZs=gz/ɓefR}}qԌ#Ei]h'ev|~KMMM6ɒ%KLP:t[ҥKy'MBf͚r饗YgR,L׿JŊzr뭷ʽ+[Ν;oaz4~gߚ-2Cj0--z(nX?sc$/Ň beffGWZ% ,)SȨQL=zHGf͚IjժfSO=նXh/˛aIpxM7>T:6>|tgzn۶ Qz1`ރB5P/[le˖ٳ믿aÆ;#ݻw7C>c3XN3_lz s9:VI&ҲeKcǎf{O>ꫯdԩfRk1>>^RRR$+݅ǎɔ m*89 wZk1@ efy?`rZ"h;-i1OzZ"슀Eg!^x}7C}Hll[k׮+6jSs1CjoD}owHvvKl *!G5(b:}j~3f"܈#dһwoy駟znfQ\~r)b[,{r%?O37(76!cbb䩧^xA^z%yץ_~2d3 %SqC6Mh p֭zjYd/ئs j>٧=z)]tg}VqQ$lРԮ][j .O?ݶXy,b2)Ҩf-^!jU2­ӴeL61Ϩ*Ҡ|Z+%wZI_~߫Izݤ2(4WEʛϿTmZڌ Y;F^n}gב1oI6$s>miy \skT}~{3wkE?P*<(fA=~gͰÇAI>}W^1CilѢ4jHׯoz(V\Y*T gu)X¶, 5NJgI혎۵4qI*uS=I3e_vR&o_үs#j_,) +HGK?oQmiQM4<2GvgUz[4exHϩe4U)}Y7s6|&zsU$m$m&PǬ-h(W[f[Dqdw pHz-"-MԸ7F:AF"YNƍlg-Z^Y췜BiSβEҩu_Lki5l}n(-W~繷 _g`&+wx5rHAŹ/:Z:A9,)<*. -HDL3C̲h\m(/)fiOy~J}߮ -\vtj]Ͻ>s+^cs=4hqfo5Z-~fsOqnsjDzdhFRf9[&~'fwzF E?jq;Rm(^)"̲S9bb Zy%z6J/38{18W=Ǟs30=K7h\mN~ {'^mmy/y<}AE)Ro:XFlwZp{\:c~oy^+BWsϜ}K P4mHM-82/-;0y <^oβh\mgZmőqdѯ Y.ڽd\BT\\Z/Fb-)SKlL#*Еr4za & HYTLZk?|~k 81@Xؕ~x3u:J??P<($%sɖ}E?6ee9 ,8)HZA2l,8%36'JFV~ l{жBHYG{8bŇK])NϴPE{^)lZ3E?֥`)Lٰ[(Y@VvBJ:ef&~ "$<,6-RY=Ed@ED#G҄B3SҭtPGy5HnMG5 P)#,ڙj[!(Yf]h d"!v8ZE?-Ɍ͉EBI>tZE??Rd=EB4s&δ kp~6[l>$2ێTٓi!B 2d",۽OegPG2}CFB~ٚ,S%#먵8E?BJ>tV1tI?m}A$:,+PtklMu)iv8F܉@1I:H y >~(ăetJз69MPa@ :*2de-E&O-Lɴ{dT3?>v&E?2/;(K'mW.AnM?ˎrH D~p1s0S$I܎Tqm+3ss,ٵW6=(GO*H$4=W%0Ůے0'pҺS[=E'RdCrdf>B:K]NQlwHV' {eË~ݞ"P4”oq3͜wZ ԡ1קDL< 7s .޵ -:{5Yf'Ɍ͉$o;SMC퍷³ʤ|Re?$;2d&:,{=#@E?(.Gp9~Q\rE?(.Gp9~Q\j"14 ]IENDB`mir-core-1.0.2/source/000077500000000000000000000000001353705753200145415ustar00rootroot00000000000000mir-core-1.0.2/source/mir/000077500000000000000000000000001353705753200153305ustar00rootroot00000000000000mir-core-1.0.2/source/mir/bitmanip.d000066400000000000000000000405701353705753200173060ustar00rootroot00000000000000/++ Bit-level manipulation facilities. $(SCRIPT inhibitQuickIndex = 1;) $(BOOKTABLE, $(TR $(TH Category) $(TH Functions)) $(TR $(TD Bit constructs) $(TD $(LREF bitfields) )) $(TR $(TD Tagging) $(TD $(LREF taggedClassRef) $(LREF taggedPointer) )) ) Copyright: Copyright Digital Mars 2007 - 2011. License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: $(HTTP digitalmars.com, Walter Bright), $(HTTP erdani.org, Andrei Alexandrescu), Amaury SECHET +/ module mir.bitmanip; import std.traits; private string normString()(string str) { // if (str.length && (str[$-1] == 'U' || str[$-1] == 'u')) str = str[0 .. $-1]; // if (str.length && (str[$-1] == 'L' || str[$-1] == 'l')) str = str[0 .. $-1]; return str; } private template createAccessors( string store, T, string name, size_t len, size_t offset) { static if (!name.length) { // No need to create any accessor enum result = ""; } else static if (len == 0) { // Fields of length 0 are always zero enum result = "enum "~T.stringof~" "~name~" = 0;\n"; } else { enum ulong maskAllElse = ((~0uL) >> (64 - len)) << offset, signBitCheck = 1uL << (len - 1); static if (T.min < 0) { enum long minVal = -(1uL << (len - 1)); enum long maxVal = (1uL << (len - 1)) - 1; alias UT = Unsigned!(T); enum UT extendSign = cast(UT)~((~0uL) >> (64 - len)); } else { enum ulong minVal = 0; enum ulong maxVal = (~0uL) >> (64 - len); enum extendSign = 0; } static if (is(T == bool)) { static assert(len == 1); enum result = // getter "@property bool " ~ name ~ "()() @safe pure nothrow @nogc const { return " ~"("~store~" & "~ maskAllElse.stringof ~") != 0;}\n" // setter ~"@property void " ~ name ~ "()(bool v) @safe pure nothrow @nogc { " ~"if (v) "~store~" |= "~ maskAllElse.stringof ~";" ~"else "~store~" &= cast(typeof("~store~"))(-1-cast(typeof("~store~"))"~ maskAllElse.stringof ~");}\n"; } else { // getter enum result = "@property "~T.stringof~" "~name~"()() @safe pure nothrow @nogc const { ulong result = " ~"(ulong("~store~") & " ~ maskAllElse.stringof ~ ") >>" ~ offset.stringof ~ ";" ~ (T.min < 0 ? "if (result >= " ~ signBitCheck.stringof ~ ") result |= " ~ extendSign.stringof ~ ";" : "") ~ " return cast("~T.stringof~") result;}\n" // setter ~"@property void "~name~"()("~T.stringof~" v) @safe pure nothrow @nogc { " ~"assert(v >= "~name~`_min, "Value is smaller than the minimum value of bitfield '`~name~`'"); ` ~"assert(v <= "~name~`_max, "Value is greater than the maximum value of bitfield '`~name~`'"); ` ~store~" = cast(typeof("~store~"))" ~" (("~store~" & (-1-cast(typeof("~store~"))"~ maskAllElse.stringof ~"))" ~" | ((cast(typeof("~store~")) v << "~ offset.stringof ~")" ~" & "~ maskAllElse.stringof ~"));}\n" // constants ~"enum "~T.stringof~" "~name~"_min = cast("~T.stringof~")" ~ (minVal == minVal.min && minVal.min < 0 ? "long.min" : minVal.stringof) ~"; " ~" enum "~T.stringof~" "~name~"_max = cast("~T.stringof~")" ~ maxVal.stringof ~"; "; } } } private template createStoreName(Ts...) { static if (Ts.length < 2) enum createStoreName = ""; else enum createStoreName = "_" ~ Ts[1] ~ createStoreName!(Ts[3 .. $]); } private template createStorageAndFields(Ts...) { enum Name = createStoreName!Ts; enum Size = sizeOfBitField!Ts; static if (Size == ubyte.sizeof * 8) alias StoreType = ubyte; else static if (Size == ushort.sizeof * 8) alias StoreType = ushort; else static if (Size == uint.sizeof * 8) alias StoreType = uint; else static if (Size == ulong.sizeof * 8) alias StoreType = ulong; else { static assert(false, "Field widths must sum to 8, 16, 32, or 64"); alias StoreType = ulong; // just to avoid another error msg } enum result = "private " ~ StoreType.stringof ~ " " ~ Name ~ ";" ~ createFields!(Name, 0, Ts).result; } private template createFields(string store, size_t offset, Ts...) { static if (Ts.length > 0) enum result = createAccessors!(store, Ts[0], Ts[1], Ts[2], offset).result ~ createFields!(store, offset + Ts[2], Ts[3 .. $]).result; else enum result = ""; } private ulong getBitsForAlign()(ulong a) { ulong bits = 0; while ((a & 0x01) == 0) { bits++; a >>= 1; } assert(a == 1, "alignment is not a power of 2"); return bits; } private template createReferenceAccessor(string store, T, ulong bits, string name) { enum storage = "private void* " ~ store ~ "_ptr;\n"; enum storage_accessor = "@property ref size_t " ~ store ~ "()() return @trusted pure nothrow @nogc const { " ~ "return *cast(size_t*) &" ~ store ~ "_ptr;}\n" ~ "@property void " ~ store ~ "()(size_t v) @trusted pure nothrow @nogc { " ~ "" ~ store ~ "_ptr = cast(void*) v;}\n"; enum mask = (1UL << bits) - 1; enum maskInv = ~mask; // getter enum ref_accessor = "@property "~T.stringof~" "~name~"()() @trusted pure nothrow @nogc const { auto result = " ~ "("~store~" & "~ maskInv.stringof ~"); " ~ "return cast("~T.stringof~") cast(void*) result;}\n" // setter ~"@property void "~name~"()("~T.stringof~" v) @trusted pure nothrow @nogc { " ~"assert(((cast(typeof("~store~")) cast(void*) v) & "~ mask.stringof ~`) == 0, "Value not properly aligned for '`~name~`'"); ` ~store~" = cast(typeof("~store~"))" ~" (("~store~" & (cast(typeof("~store~")) "~ mask.stringof ~"))" ~" | ((cast(typeof("~store~")) cast(void*) v) & (cast(typeof("~store~")) "~ maskInv.stringof ~")));}\n"; enum result = storage ~ storage_accessor ~ ref_accessor; } private template sizeOfBitField(T...) { static if (T.length < 2) enum sizeOfBitField = 0; else enum sizeOfBitField = T[2] + sizeOfBitField!(T[3 .. $]); } private template createTaggedReference(T, ulong a, string name, Ts...) { static assert( sizeOfBitField!Ts <= getBitsForAlign(a), "Fields must fit in the bits know to be zero because of alignment." ); enum StoreName = createStoreName!(T, name, 0, Ts); enum result = createReferenceAccessor!(StoreName, T, sizeOfBitField!Ts, name).result ~ createFields!(StoreName, 0, Ts, size_t, "", T.sizeof * 8 - sizeOfBitField!Ts).result; } /** Allows creating bit fields inside $(D_PARAM struct)s and $(D_PARAM class)es. Example: ---- struct A { int a; mixin(bitfields!( uint, "x", 2, int, "y", 3, uint, "z", 2, bool, "flag", 1)); } A obj; obj.x = 2; obj.z = obj.x; ---- The example above creates a bitfield pack of eight bits, which fit in one $(D_PARAM ubyte). The bitfields are allocated starting from the least significant bit, i.e. x occupies the two least significant bits of the bitfields storage. The sum of all bit lengths in one $(D_PARAM bitfield) instantiation must be exactly 8, 16, 32, or 64. If padding is needed, just allocate one bitfield with an empty name. Example: ---- struct A { mixin(bitfields!( bool, "flag1", 1, bool, "flag2", 1, uint, "", 6)); } ---- The type of a bit field can be any integral type or enumerated type. The most efficient type to store in bitfields is $(D_PARAM bool), followed by unsigned types, followed by signed types. */ template bitfields(T...) { enum { bitfields = createStorageAndFields!T.result } } /** This string mixin generator allows one to create tagged pointers inside $(D_PARAM struct)s and $(D_PARAM class)es. A tagged pointer uses the bits known to be zero in a normal pointer or class reference to store extra information. For example, a pointer to an integer must be 4-byte aligned, so there are 2 bits that are always known to be zero. One can store a 2-bit integer there. The example above creates a tagged pointer in the struct A. The pointer is of type $(D uint*) as specified by the first argument, and is named x, as specified by the second argument. Following arguments works the same way as $(D bitfield)'s. The bitfield must fit into the bits known to be zero because of the pointer alignment. */ template taggedPointer(T : T*, string name, Ts...) { enum taggedPointer = createTaggedReference!(T*, T.alignof, name, Ts).result; } /// @safe version(mir_test) unittest { struct A { int a; mixin(taggedPointer!( uint*, "x", bool, "b1", 1, bool, "b2", 1)); } A obj; obj.x = new uint; obj.b1 = true; obj.b2 = false; } /** This string mixin generator allows one to create tagged class reference inside $(D_PARAM struct)s and $(D_PARAM class)es. A tagged class reference uses the bits known to be zero in a normal class reference to store extra information. For example, a pointer to an integer must be 4-byte aligned, so there are 2 bits that are always known to be zero. One can store a 2-bit integer there. The example above creates a tagged reference to an Object in the struct A. This expects the same parameters as $(D taggedPointer), except the first argument which must be a class type instead of a pointer type. */ template taggedClassRef(T, string name, Ts...) if (is(T == class)) { enum taggedClassRef = createTaggedReference!(T, 8, name, Ts).result; } /// @safe version(mir_test) unittest { struct A { int a; mixin(taggedClassRef!( Object, "o", uint, "i", 2)); } A obj; obj.o = new Object(); obj.i = 3; } @safe pure nothrow @nogc version(mir_test) unittest { // Degenerate bitfields (#8474 / #11160) tests mixed with range tests struct Test1 { mixin(bitfields!(uint, "a", 32, uint, "b", 4, uint, "c", 4, uint, "d", 8, uint, "e", 16,)); static assert(Test1.b_min == 0); static assert(Test1.b_max == 15); } struct Test2 { mixin(bitfields!(bool, "a", 0, ulong, "b", 64)); static assert(Test2.b_min == ulong.min); static assert(Test2.b_max == ulong.max); } struct Test1b { mixin(bitfields!(bool, "a", 0, int, "b", 8)); } struct Test2b { mixin(bitfields!(int, "a", 32, int, "b", 4, int, "c", 4, int, "d", 8, int, "e", 16,)); static assert(Test2b.b_min == -8); static assert(Test2b.b_max == 7); } struct Test3b { mixin(bitfields!(bool, "a", 0, long, "b", 64)); static assert(Test3b.b_min == long.min); static assert(Test3b.b_max == long.max); } struct Test4b { mixin(bitfields!(long, "a", 32, int, "b", 32)); } // Sign extension tests Test2b t2b; Test4b t4b; t2b.b = -5; assert(t2b.b == -5); t2b.d = -5; assert(t2b.d == -5); t2b.e = -5; assert(t2b.e == -5); t4b.a = -5; assert(t4b.a == -5L); } @system version(mir_test) unittest { struct Test5 { mixin(taggedPointer!( int*, "a", uint, "b", 2)); } Test5 t5; t5.a = null; t5.b = 3; assert(t5.a is null); assert(t5.b == 3); int myint = 42; t5.a = &myint; assert(t5.a is &myint); assert(t5.b == 3); struct Test6 { mixin(taggedClassRef!( Object, "o", bool, "b", 1)); } Test6 t6; t6.o = null; t6.b = false; assert(t6.o is null); assert(t6.b == false); auto o = new Object(); t6.o = o; t6.b = true; assert(t6.o is o); assert(t6.b == true); } @safe version(mir_test) unittest { static assert(!__traits(compiles, taggedPointer!( int*, "a", uint, "b", 3))); static assert(!__traits(compiles, taggedClassRef!( Object, "a", uint, "b", 4))); struct S { mixin(taggedClassRef!( Object, "a", bool, "b", 1)); } const S s; void bar(S s) {} static assert(!__traits(compiles, bar(s))); } @safe version(mir_test) unittest { // Bug #6686 union S { ulong bits = ulong.max; mixin (bitfields!( ulong, "back", 31, ulong, "front", 33) ); } S num; num.bits = ulong.max; num.back = 1; assert(num.bits == 0xFFFF_FFFF_8000_0001uL); } @safe version(mir_test) unittest { // Bug #5942 struct S { mixin(bitfields!( int, "a" , 32, int, "b" , 32 )); } S data; data.b = 42; data.a = 1; assert(data.b == 42); } @safe version(mir_test) unittest { struct Test { mixin(bitfields!(bool, "a", 1, uint, "b", 3, short, "c", 4)); } @safe void test() pure nothrow { Test t; t.a = true; t.b = 5; t.c = 2; assert(t.a); assert(t.b == 5); assert(t.c == 2); } test(); } @safe version(mir_test) unittest { { static struct Integrals { bool checkExpectations(bool eb, int ei, short es) { return b == eb && i == ei && s == es; } mixin(bitfields!( bool, "b", 1, uint, "i", 3, short, "s", 4)); } Integrals i; assert(i.checkExpectations(false, 0, 0)); i.b = true; assert(i.checkExpectations(true, 0, 0)); i.i = 7; assert(i.checkExpectations(true, 7, 0)); i.s = -8; assert(i.checkExpectations(true, 7, -8)); i.s = 7; assert(i.checkExpectations(true, 7, 7)); } //Bug# 8876 { struct MoreIntegrals { bool checkExpectations(uint eu, ushort es, uint ei) { return u == eu && s == es && i == ei; } mixin(bitfields!( uint, "u", 24, short, "s", 16, int, "i", 24)); } MoreIntegrals i; assert(i.checkExpectations(0, 0, 0)); i.s = 20; assert(i.checkExpectations(0, 20, 0)); i.i = 72; assert(i.checkExpectations(0, 20, 72)); i.u = 8; assert(i.checkExpectations(8, 20, 72)); i.s = 7; assert(i.checkExpectations(8, 7, 72)); } enum A { True, False } enum B { One, Two, Three, Four } static struct Enums { bool checkExpectations(A ea, B eb) { return a == ea && b == eb; } mixin(bitfields!( A, "a", 1, B, "b", 2, uint, "", 5)); } Enums e; assert(e.checkExpectations(A.True, B.One)); e.a = A.False; assert(e.checkExpectations(A.False, B.One)); e.b = B.Three; assert(e.checkExpectations(A.False, B.Three)); static struct SingleMember { bool checkExpectations(bool eb) { return b == eb; } mixin(bitfields!( bool, "b", 1, uint, "", 7)); } SingleMember f; assert(f.checkExpectations(false)); f.b = true; assert(f.checkExpectations(true)); } // Issue 12477 @system version(mir_test) unittest { import std.algorithm.searching : canFind; import mir.bitmanip : bitfields; import core.exception : AssertError; static struct S { mixin(bitfields!( uint, "a", 6, int, "b", 2)); } S s; try { s.a = uint.max; assert(0); } catch (AssertError ae) { assert(ae.msg.canFind("Value is greater than the maximum value of bitfield 'a'"), ae.msg); } try { s.b = int.min; assert(0); } catch (AssertError ae) { assert(ae.msg.canFind("Value is smaller than the minimum value of bitfield 'b'"), ae.msg); } } mir-core-1.0.2/source/mir/bitop.d000066400000000000000000000223651353705753200166220ustar00rootroot00000000000000/++ This module contains a collection of bit-level operations. Authors: Ilya Yaroshenko, Phobos & LDC Authors (original Phobos unittests, docs, conventions). +/ module mir.bitop; version(LDC) import ldc.intrinsics; version(GNU) import gcc.builtins; import mir.math.common: fastmath; /// Right shift vallue for bit index to get element's index (5 for `uint`). enum uint bitElemShift(T : ubyte) = 3; /// ditto enum uint bitElemShift(T : byte) = 3; /// ditto enum uint bitElemShift(T : ushort) = 4; /// ditto enum uint bitElemShift(T : short) = 4; /// ditto enum uint bitElemShift(T : uint) = 5; /// ditto enum uint bitElemShift(T : int) = 5; /// ditto enum uint bitElemShift(T : ulong) = 6; /// ditto enum uint bitElemShift(T : long) = 6; static if (is(ucent)) /// ditto enum uint bitElemShift(T : ucent) = 7; /// ditto static if (is(cent)) enum uint bitElemShift(T : cent) = 7; /// Bit mask for bit index to get element's bit shift (31 for uint). enum uint bitShiftMask(T : ubyte) = 7; /// ditto enum uint bitShiftMask(T : byte) = 7; /// ditto enum uint bitShiftMask(T : ushort) = 15; /// ditto enum uint bitShiftMask(T : short) = 15; /// ditto enum uint bitShiftMask(T : uint) = 31; /// ditto enum uint bitShiftMask(T : int) = 31; /// ditto enum uint bitShiftMask(T : ulong) = 63; /// ditto enum uint bitShiftMask(T : long) = 63; static if (is(ucent)) /// ditto enum uint bitShiftMask(T : ucent) = 127; static if (is(cent)) /// ditto enum uint bitShiftMask(T : cent) = 127; // no effect on this function, but better for optimization of other @fastmath code that uses this @fastmath: /++ +/ T nTrailingBitsToCount(T)(in T value, in T popcnt) if (__traits(isUnsigned, T)) { import std.traits; import mir.internal.utility: Iota; alias S = Signed!(CommonType!(int, T)); S mask = S(-1) << T.sizeof * 4; foreach_reverse (s; Iota!(bitElemShift!T - 1)) {{ enum shift = 1 << s; if (S(popcnt) > S(ctpop(cast(T)(value & ~mask)))) mask <<= shift; else mask >>= shift; }} return cttz(cast(T)mask) + (S(popcnt) != ctpop(cast(T)(value & ~mask))); } /// unittest { assert(nTrailingBitsToCount(0xF0u, 3u) == 7); assert(nTrailingBitsToCount(0xE00u, 3u) == 12); foreach(uint i; 1 .. 32) assert(nTrailingBitsToCount(uint.max, i) == i); } /++ +/ T nLeadingBitsToCount(T)(in T value, in T popcnt) if (__traits(isUnsigned, T)) { import std.traits; import mir.internal.utility: Iota; alias S = Signed!(CommonType!(int, T)); S mask = S(-1) << T.sizeof * 4; foreach_reverse (s; Iota!(bitElemShift!T - 1)) {{ enum shift = 1 << s; if (S(popcnt) > S(ctpop(cast(T)(value & mask)))) mask >>= shift; else mask <<= shift; }} return ctlz(cast(T)~mask) + (S(popcnt) != ctpop(cast(T)(value & mask))); } /// unittest { assert(nLeadingBitsToCount(0xF0u, 3u) == 32 - 5); assert(nLeadingBitsToCount(0x700u, 3u) == 32 - 8); foreach(uint i; 1 .. 32) assert(nLeadingBitsToCount(uint.max, i) == i); } /++ Tests the bit. Returns: A non-zero value if the bit was set, and a zero if it was clear. +/ auto bt(Field, T = typeof(Field.init[size_t.init]))(auto ref Field p, size_t bitnum) if (__traits(isUnsigned, T)) { auto index = bitnum >> bitElemShift!T; auto mask = T(1) << (bitnum & bitShiftMask!T); return p[index] & mask; } /// @system pure unittest { size_t[2] array; array[0] = 2; array[1] = 0x100; assert(bt(array.ptr, 1)); assert(array[0] == 2); assert(array[1] == 0x100); } /++ Tests and assign the bit. Returns: A non-zero value if the bit was set, and a zero if it was clear. +/ auto bta(Field, T = typeof(Field.init[size_t.init]))(auto ref Field p, size_t bitnum, bool value) if (__traits(isUnsigned, T)) { auto index = bitnum >> bitElemShift!T; auto shift = bitnum & bitShiftMask!T; auto mask = T(1) << shift; static if (__traits(compiles, &p[size_t.init])) { auto qp = &p[index]; auto q = *qp; auto ret = q & mask; *qp = cast(T)((q & ~mask) ^ (T(value) << shift)); } else { auto q = p[index]; auto ret = q & mask; p[index] = cast(T)((q & ~mask) ^ (T(value) << shift)); } return ret; } /++ Tests and complements the bit. Returns: A non-zero value if the bit was set, and a zero if it was clear. +/ auto btc(Field, T = typeof(Field.init[size_t.init]))(auto ref Field p, size_t bitnum) if (__traits(isUnsigned, T)) { auto index = bitnum >> bitElemShift!T; auto mask = T(1) << (bitnum & bitShiftMask!T); static if (__traits(compiles, &p[size_t.init])) { auto qp = &p[index]; auto q = *qp; auto ret = q & mask; *qp = cast(T)(q ^ mask); } else { auto q = p[index]; auto ret = q & mask; p[index] = cast(T)(q ^ mask); } return ret; } /++ Tests and resets (sets to 0) the bit. Returns: A non-zero value if the bit was set, and a zero if it was clear. +/ auto btr(Field, T = typeof(Field.init[size_t.init]))(auto ref Field p, size_t bitnum) if (__traits(isUnsigned, T)) { auto index = bitnum >> bitElemShift!T; auto mask = T(1) << (bitnum & bitShiftMask!T); static if (__traits(compiles, &p[size_t.init])) { auto qp = &p[index]; auto q = *qp; auto ret = q & mask; *qp = cast(T)(q & ~mask); } else { auto q = p[index]; auto ret = q & mask; p[index] = cast(T)(q & ~mask); } return ret; } /++ Tests and sets the bit. Params: p = a non-NULL field / pointer to an array of unsigned integers. bitnum = a bit number, starting with bit 0 of p[0], and progressing. It addresses bits like the expression: --- p[index / (T.sizeof*8)] & (1 << (index & ((T.sizeof*8) - 1))) --- Returns: A non-zero value if the bit was set, and a zero if it was clear. +/ auto bts(Field, T = typeof(Field.init[size_t.init]))(auto ref Field p, size_t bitnum) if (__traits(isUnsigned, T)) { auto index = bitnum >> bitElemShift!T; auto mask = T(1) << (bitnum & bitShiftMask!T); static if (__traits(compiles, &p[size_t.init])) { auto qp = &p[index]; auto q = *qp; auto ret = q & mask; *qp = cast(T)(q | mask); } else { auto q = p[index]; auto ret = q & mask; p[index] = cast(T)(q | mask); } return ret; } /// @system pure unittest { size_t[2] array; array[0] = 2; array[1] = 0x100; assert(btc(array.ptr, 35) == 0); if (size_t.sizeof == 8) { assert(array[0] == 0x8_0000_0002); assert(array[1] == 0x100); } else { assert(array[0] == 2); assert(array[1] == 0x108); } assert(btc(array.ptr, 35)); assert(array[0] == 2); assert(array[1] == 0x100); assert(bts(array.ptr, 35) == 0); if (size_t.sizeof == 8) { assert(array[0] == 0x8_0000_0002); assert(array[1] == 0x100); } else { assert(array[0] == 2); assert(array[1] == 0x108); } assert(btr(array.ptr, 35)); assert(array[0] == 2); assert(array[1] == 0x100); } /// The 'ctpop' family of intrinsics counts the number of bits set in a value. T ctpop(T)(in T src) if (__traits(isUnsigned, T)) { version(LDC) if (!__ctfe) return llvm_ctpop(src); version(GNU) if (!__ctfe) { static if (T.sizeof < __builtin_clong.sizeof) return cast(T) __builtin_popcount(src); else static if (T.sizeof <= __builtin_clong.sizeof) return cast(T) __builtin_popcountl(src); else return cast(T) __builtin_popcountll(src); } import core.bitop: popcnt; return cast(T) popcnt(src); } /++ The 'ctlz' family of intrinsic functions counts the number of leading zeros in a variable. Result is undefined if the argument is zero. +/ T ctlz(T)(in T src) if (__traits(isUnsigned, T)) { version(LDC) if (!__ctfe) return llvm_ctlz(src, true); version(GNU) if (!__ctfe) { // Do not zero-extend when counting leading zeroes. static if (T.sizeof < __builtin_clong.sizeof && T.sizeof >= uint.sizeof) return cast(T) __builtin_clz(src); else static if (T.sizeof == __builtin_clong.sizeof) return cast(T) __builtin_clzl(src); else static if (T.sizeof > __builtin_clong.sizeof) return cast(T) __builtin_clzll(src); } import core.bitop: bsr; return cast(T)(T.sizeof * 8 - 1 - bsr(src)); } version (mir_test) @nogc nothrow pure @safe unittest { assert(ctlz(cast(ubyte) 0b0011_1111) == 2); assert(ctlz(cast(ushort) 0b0000_0001_1111_1111) == 7); } /++ The 'cttz' family of intrinsic functions counts the number of trailing zeros. Result is undefined if the argument is zero. +/ T cttz(T)(in T src) if (__traits(isUnsigned, T)) { version(LDC) if (!__ctfe) return llvm_cttz(src, true); version(GNU) if (!__ctfe) { static if (T.sizeof <__builtin_clong.sizeof) return cast(T) __builtin_ctz(src); else static if (T.sizeof <=__builtin_clong.sizeof) return cast(T) __builtin_ctzl(src); else return cast(T) __builtin_ctzll(src); } import core.bitop: bsf; return cast(T) bsf(src); } mir-core-1.0.2/source/mir/checkedint.d000066400000000000000000000603171353705753200176050ustar00rootroot00000000000000 /********************************************** * This module implements integral arithmetic primitives that check * for out-of-range results. * * Integral arithmetic operators operate on fixed width types. * Results that are not representable in those fixed widths are silently * truncated to fit. * This module offers integral arithmetic primitives that produce the * same results, but set an 'overflow' flag when such truncation occurs. * The setting is sticky, meaning that numerous operations can be cascaded * and then the flag need only be checked at the end. * Whether the operation is signed or unsigned is indicated by an 's' or 'u' * suffix, respectively. While this could be achieved without such suffixes by * using overloading on the signedness of the types, the suffix makes it clear * which is happening without needing to examine the types. * * While the generic versions of these functions are computationally expensive * relative to the cost of the operation itself, compiler implementations are free * to recognize them and generate equivalent and faster code. * * References: $(LINK2 http://blog.regehr.org/archives/1139, Fast Integer Overflow Checks) * Copyright: Copyright (c) Walter Bright 2014. * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: Walter Bright * Source: $(DRUNTIMESRC core/_checkedint.d) */ module mir.checkedint; version (GNU) { // GDC uses intrinsics for core.checkedint functions. public import core.checkedint : adds, addu, subs, subu, muls, mulu, negs; } else: version (LDC) { import ldc.intrinsics; // llvm.(u)mul.with.overflow.i64 might fall back to a software implementation // in the form of __mulodi4, which only exists in compiler-rt and not // libgcc. Thus, we need to be sure not to emit it for now (see GitHub #818). version (X86_64) version = LDC_HasNativeI64Mul; } nothrow: @safe: @nogc: pure: /******************************* * Add two signed integers, checking for overflow. * * The overflow is sticky, meaning a sequence of operations can * be done and overflow need only be checked at the end. * Params: * x = left operand * y = right operand * overflow = set if an overflow occurs, is not affected otherwise * Returns: * the sum */ pragma(inline, true) int adds(int x, int y, scope ref bool overflow) { version (LDC) { if (!__ctfe) { auto res = llvm_sadd_with_overflow(x, y); overflow |= res.overflow; return res.result; } } long r = cast(long)x + cast(long)y; if (r < int.min || r > int.max) overflow = true; return cast(int)r; } unittest { bool overflow; assert(adds(2, 3, overflow) == 5); assert(!overflow); assert(adds(1, int.max - 1, overflow) == int.max); assert(!overflow); assert(adds(int.min + 1, -1, overflow) == int.min); assert(!overflow); assert(adds(int.max, 1, overflow) == int.min); assert(overflow); overflow = false; assert(adds(int.min, -1, overflow) == int.max); assert(overflow); assert(adds(0, 0, overflow) == 0); assert(overflow); // sticky } /// ditto pragma(inline, true) long adds(long x, long y, scope ref bool overflow) { version (LDC) { if (!__ctfe) { auto res = llvm_sadd_with_overflow(x, y); overflow |= res.overflow; return res.result; } } long r = cast(ulong)x + cast(ulong)y; if (x < 0 && y < 0 && r >= 0 || x >= 0 && y >= 0 && r < 0) overflow = true; return r; } unittest { bool overflow; assert(adds(2L, 3L, overflow) == 5); assert(!overflow); assert(adds(1L, long.max - 1, overflow) == long.max); assert(!overflow); assert(adds(long.min + 1, -1, overflow) == long.min); assert(!overflow); assert(adds(long.max, 1, overflow) == long.min); assert(overflow); overflow = false; assert(adds(long.min, -1, overflow) == long.max); assert(overflow); assert(adds(0L, 0L, overflow) == 0); assert(overflow); // sticky } static if (is(cent)) { /// ditto pragma(inline, true) cent adds(cent x, cent y, scope ref bool overflow) { version (LDC) { if (!__ctfe) { auto res = llvm_sadd_with_overflow(x, y); overflow |= res.overflow; return res.result; } } cent r = cast(ucent)x + cast(ucent)y; if (x < 0 && y < 0 && r >= 0 || x >= 0 && y >= 0 && r < 0) overflow = true; return r; } unittest { bool overflow; assert(adds(cast(cent)2L, 3L, overflow) == 5); assert(!overflow); assert(adds(1L, cent.max - 1, overflow) == cent.max); assert(!overflow); assert(adds(cent.min + 1, -1, overflow) == cent.min); assert(!overflow); assert(adds(cent.max, 1, overflow) == cent.min); assert(overflow); overflow = false; assert(adds(cent.min, -1, overflow) == cent.max); assert(overflow); assert(adds(cast(cent)0L, 0L, overflow) == 0); assert(overflow); // sticky } } /******************************* * Add two unsigned integers, checking for overflow (aka carry). * * The overflow is sticky, meaning a sequence of operations can * be done and overflow need only be checked at the end. * Params: * x = left operand * y = right operand * overflow = set if an overflow occurs, is not affected otherwise * Returns: * the sum */ pragma(inline, true) uint addu(uint x, uint y, scope ref bool overflow) { version (LDC) { if (!__ctfe) { auto res = llvm_uadd_with_overflow(x, y); overflow |= res.overflow; return res.result; } } immutable uint r = x + y; if (r < x || r < y) overflow = true; return r; } unittest { bool overflow; assert(addu(2, 3, overflow) == 5); assert(!overflow); assert(addu(1, uint.max - 1, overflow) == uint.max); assert(!overflow); assert(addu(uint.min, -1, overflow) == uint.max); assert(!overflow); assert(addu(uint.max, 1, overflow) == uint.min); assert(overflow); overflow = false; assert(addu(uint.min + 1, -1, overflow) == uint.min); assert(overflow); assert(addu(0, 0, overflow) == 0); assert(overflow); // sticky } /// ditto pragma(inline, true) ulong addu(ulong x, ulong y, scope ref bool overflow) { version (LDC) { if (!__ctfe) { auto res = llvm_uadd_with_overflow(x, y); overflow |= res.overflow; return res.result; } } immutable ulong r = x + y; if (r < x || r < y) overflow = true; return r; } unittest { bool overflow; assert(addu(2L, 3L, overflow) == 5); assert(!overflow); assert(addu(1, ulong.max - 1, overflow) == ulong.max); assert(!overflow); assert(addu(ulong.min, -1L, overflow) == ulong.max); assert(!overflow); assert(addu(ulong.max, 1, overflow) == ulong.min); assert(overflow); overflow = false; assert(addu(ulong.min + 1, -1L, overflow) == ulong.min); assert(overflow); assert(addu(0L, 0L, overflow) == 0); assert(overflow); // sticky } static if (is(ucent)) { /// ditto pragma(inline, true) ucent addu(ucent x, ucent y, scope ref bool overflow) { version (LDC) { if (!__ctfe) { auto res = llvm_uadd_with_overflow(x, y); overflow |= res.overflow; return res.result; } } immutable ucent r = x + y; if (r < x || r < y) overflow = true; return r; } unittest { bool overflow; assert(addu(cast(ucent)2L, 3L, overflow) == 5); assert(!overflow); assert(addu(1, ucent.max - 1, overflow) == ucent.max); assert(!overflow); assert(addu(ucent.min, -1L, overflow) == ucent.max); assert(!overflow); assert(addu(ucent.max, 1, overflow) == ucent.min); assert(overflow); overflow = false; assert(addu(ucent.min + 1, -1L, overflow) == ucent.min); assert(overflow); assert(addu(cast(ucent)0L, 0L, overflow) == 0); assert(overflow); // sticky } } /******************************* * Subtract two signed integers, checking for overflow. * * The overflow is sticky, meaning a sequence of operations can * be done and overflow need only be checked at the end. * Params: * x = left operand * y = right operand * overflow = set if an overflow occurs, is not affected otherwise * Returns: * the difference */ pragma(inline, true) int subs(int x, int y, scope ref bool overflow) { version (LDC) { if (!__ctfe) { auto res = llvm_ssub_with_overflow(x, y); overflow |= res.overflow; return res.result; } } immutable long r = cast(long)x - cast(long)y; if (r < int.min || r > int.max) overflow = true; return cast(int)r; } unittest { bool overflow; assert(subs(2, -3, overflow) == 5); assert(!overflow); assert(subs(1, -int.max + 1, overflow) == int.max); assert(!overflow); assert(subs(int.min + 1, 1, overflow) == int.min); assert(!overflow); assert(subs(int.max, -1, overflow) == int.min); assert(overflow); overflow = false; assert(subs(int.min, 1, overflow) == int.max); assert(overflow); assert(subs(0, 0, overflow) == 0); assert(overflow); // sticky } /// ditto pragma(inline, true) long subs(long x, long y, scope ref bool overflow) { version (LDC) { if (!__ctfe) { auto res = llvm_ssub_with_overflow(x, y); overflow |= res.overflow; return res.result; } } immutable long r = cast(ulong)x - cast(ulong)y; if (x < 0 && y >= 0 && r >= 0 || x >= 0 && y < 0 && (r < 0 || y == long.min)) overflow = true; return r; } unittest { bool overflow; assert(subs(2L, -3L, overflow) == 5); assert(!overflow); assert(subs(1L, -long.max + 1, overflow) == long.max); assert(!overflow); assert(subs(long.min + 1, 1, overflow) == long.min); assert(!overflow); assert(subs(-1L, long.min, overflow) == long.max); assert(!overflow); assert(subs(long.max, -1, overflow) == long.min); assert(overflow); overflow = false; assert(subs(long.min, 1, overflow) == long.max); assert(overflow); assert(subs(0L, 0L, overflow) == 0); assert(overflow); // sticky } static if (is(cent)) { /// ditto pragma(inline, true) cent subs(cent x, cent y, scope ref bool overflow) { version (LDC) { if (!__ctfe) { auto res = llvm_ssub_with_overflow(x, y); overflow |= res.overflow; return res.result; } } immutable cent r = cast(ucent)x - cast(ucent)y; if (x < 0 && y >= 0 && r >= 0 || x >= 0 && y < 0 && (r < 0 || y == long.min)) overflow = true; return r; } unittest { bool overflow; assert(subs(cast(cent)2L, -3L, overflow) == 5); assert(!overflow); assert(subs(1L, -cent.max + 1, overflow) == cent.max); assert(!overflow); assert(subs(cent.min + 1, 1, overflow) == cent.min); assert(!overflow); assert(subs(-1L, cent.min, overflow) == cent.max); assert(!overflow); assert(subs(cent.max, -1, overflow) == cent.min); assert(overflow); overflow = false; assert(subs(cent.min, 1, overflow) == cent.max); assert(overflow); assert(subs(cast(cent)0L, 0L, overflow) == 0); assert(overflow); // sticky } } /******************************* * Subtract two unsigned integers, checking for overflow (aka borrow). * * The overflow is sticky, meaning a sequence of operations can * be done and overflow need only be checked at the end. * Params: * x = left operand * y = right operand * overflow = set if an overflow occurs, is not affected otherwise * Returns: * the difference */ pragma(inline, true) uint subu(uint x, uint y, scope ref bool overflow) { version (LDC) { if (!__ctfe) { auto res = llvm_usub_with_overflow(x, y); overflow |= res.overflow; return res.result; } } if (x < y) overflow = true; return x - y; } unittest { bool overflow; assert(subu(3, 2, overflow) == 1); assert(!overflow); assert(subu(uint.max, 1, overflow) == uint.max - 1); assert(!overflow); assert(subu(1, 1, overflow) == uint.min); assert(!overflow); assert(subu(0, 1, overflow) == uint.max); assert(overflow); overflow = false; assert(subu(uint.max - 1, uint.max, overflow) == uint.max); assert(overflow); assert(subu(0, 0, overflow) == 0); assert(overflow); // sticky } /// ditto pragma(inline, true) ulong subu(ulong x, ulong y, scope ref bool overflow) { version (LDC) { if (!__ctfe) { auto res = llvm_usub_with_overflow(x, y); overflow |= res.overflow; return res.result; } } if (x < y) overflow = true; return x - y; } unittest { bool overflow; assert(subu(3UL, 2UL, overflow) == 1); assert(!overflow); assert(subu(ulong.max, 1, overflow) == ulong.max - 1); assert(!overflow); assert(subu(1UL, 1UL, overflow) == ulong.min); assert(!overflow); assert(subu(0UL, 1UL, overflow) == ulong.max); assert(overflow); overflow = false; assert(subu(ulong.max - 1, ulong.max, overflow) == ulong.max); assert(overflow); assert(subu(0UL, 0UL, overflow) == 0); assert(overflow); // sticky } static if (is(ucent)) { /// ditto pragma(inline, true) ucent subu(ucent x, ucent y, scope ref bool overflow) { version (LDC) { if (!__ctfe) { auto res = llvm_usub_with_overflow(x, y); overflow |= res.overflow; return res.result; } } if (x < y) overflow = true; return x - y; } unittest { bool overflow; assert(subu(cast(ucent)3UL, 2UL, overflow) == 1); assert(!overflow); assert(subu(ucent.max, 1, overflow) == ucent.max - 1); assert(!overflow); assert(subu(1UL, 1UL, overflow) == ucent.min); assert(!overflow); assert(subu(cast(ucent)0UL, 1UL, overflow) == ucent.max); assert(overflow); overflow = false; assert(subu(ucent.max - 1, ucent.max, overflow) == ucent.max); assert(overflow); assert(subu(cast(ucent)0UL, 0UL, overflow) == 0); assert(overflow); // sticky } } /*********************************************** * Negate an integer. * * Params: * x = operand * overflow = set if x cannot be negated, is not affected otherwise * Returns: * the negation of x */ pragma(inline, true) int negs(int x, scope ref bool overflow) { if (x == int.min) overflow = true; return -x; } unittest { bool overflow; assert(negs(0, overflow) == -0); assert(!overflow); assert(negs(1234, overflow) == -1234); assert(!overflow); assert(negs(-5678, overflow) == 5678); assert(!overflow); assert(negs(int.min, overflow) == -int.min); assert(overflow); assert(negs(0, overflow) == -0); assert(overflow); // sticky } /// ditto pragma(inline, true) long negs(long x, scope ref bool overflow) { if (x == long.min) overflow = true; return -x; } unittest { bool overflow; assert(negs(0L, overflow) == -0); assert(!overflow); assert(negs(1234L, overflow) == -1234); assert(!overflow); assert(negs(-5678L, overflow) == 5678); assert(!overflow); assert(negs(long.min, overflow) == -long.min); assert(overflow); assert(negs(0L, overflow) == -0); assert(overflow); // sticky } static if (is(cent)) { /// ditto pragma(inline, true) cent negs(cent x, scope ref bool overflow) { if (x == cent.min) overflow = true; return -x; } unittest { bool overflow; assert(negs(cast(cent)0L, overflow) == -0); assert(!overflow); assert(negs(cast(cent)1234L, overflow) == -1234); assert(!overflow); assert(negs(cast(cent)-5678L, overflow) == 5678); assert(!overflow); assert(negs(cent.min, overflow) == -cent.min); assert(overflow); assert(negs(cast(cent)0L, overflow) == -0); assert(overflow); // sticky } } /******************************* * Multiply two signed integers, checking for overflow. * * The overflow is sticky, meaning a sequence of operations can * be done and overflow need only be checked at the end. * Params: * x = left operand * y = right operand * overflow = set if an overflow occurs, is not affected otherwise * Returns: * the product */ pragma(inline, true) int muls(int x, int y, scope ref bool overflow) { version (LDC) { if (!__ctfe) { auto res = llvm_smul_with_overflow(x, y); overflow |= res.overflow; return res.result; } } long r = cast(long)x * cast(long)y; if (r < int.min || r > int.max) overflow = true; return cast(int)r; } unittest { bool overflow; assert(muls(2, 3, overflow) == 6); assert(!overflow); assert(muls(-200, 300, overflow) == -60_000); assert(!overflow); assert(muls(1, int.max, overflow) == int.max); assert(!overflow); assert(muls(int.min, 1, overflow) == int.min); assert(!overflow); assert(muls(int.max, 2, overflow) == (int.max * 2)); assert(overflow); overflow = false; assert(muls(int.min, -1, overflow) == int.min); assert(overflow); assert(muls(0, 0, overflow) == 0); assert(overflow); // sticky } /// ditto pragma(inline, true) long muls(long x, long y, scope ref bool overflow) { version (LDC_HasNativeI64Mul) { if (!__ctfe) { auto res = llvm_smul_with_overflow(x, y); overflow |= res.overflow; return res.result; } } immutable long r = cast(ulong)x * cast(ulong)y; enum not0or1 = ~1L; if ((x & not0or1) && ((r == y)? r : (r / x) != y)) overflow = true; return r; } unittest { bool overflow; assert(muls(2L, 3L, overflow) == 6); assert(!overflow); assert(muls(-200L, 300L, overflow) == -60_000); assert(!overflow); assert(muls(1, long.max, overflow) == long.max); assert(!overflow); assert(muls(long.min, 1L, overflow) == long.min); assert(!overflow); assert(muls(long.max, 2L, overflow) == (long.max * 2)); assert(overflow); overflow = false; assert(muls(-1L, long.min, overflow) == long.min); assert(overflow); overflow = false; assert(muls(long.min, -1L, overflow) == long.min); assert(overflow); assert(muls(0L, 0L, overflow) == 0); assert(overflow); // sticky } static if (is(cent)) { /// ditto pragma(inline, true) cent muls(cent x, cent y, scope ref bool overflow) { version (LDC_HasNativeI64Mul) { if (!__ctfe) { auto res = llvm_smul_with_overflow(x, y); overflow |= res.overflow; return res.result; } } immutable cent r = cast(ucent)x * cast(ucent)y; enum not0or1 = ~1L; if ((x & not0or1) && ((r == y)? r : (r / x) != y)) overflow = true; return r; } unittest { bool overflow; assert(muls(cast(cent)2L, 3L, overflow) == 6); assert(!overflow); assert(muls(cast(cent)-200L, 300L, overflow) == -60_000); assert(!overflow); assert(muls(1, cent.max, overflow) == cent.max); assert(!overflow); assert(muls(cent.min, 1L, overflow) == cent.min); assert(!overflow); assert(muls(cent.max, 2L, overflow) == (cent.max * 2)); assert(overflow); overflow = false; assert(muls(-1L, cent.min, overflow) == cent.min); assert(overflow); overflow = false; assert(muls(cent.min, -1L, overflow) == cent.min); assert(overflow); assert(muls(cast(cent)0L, 0L, overflow) == 0); assert(overflow); // sticky } } /******************************* * Multiply two unsigned integers, checking for overflow (aka carry). * * The overflow is sticky, meaning a sequence of operations can * be done and overflow need only be checked at the end. * Params: * x = left operand * y = right operand * overflow = set if an overflow occurs, is not affected otherwise * Returns: * the product */ pragma(inline, true) uint mulu(uint x, uint y, scope ref bool overflow) { version (LDC) { if (!__ctfe) { auto res = llvm_umul_with_overflow(x, y); overflow |= res.overflow; return res.result; } } immutable ulong r = ulong(x) * ulong(y); if (r >> 32) overflow = true; return cast(uint) r; } unittest { void test(uint x, uint y, uint r, bool overflow) @nogc nothrow { bool o; assert(mulu(x, y, o) == r); assert(o == overflow); } test(2, 3, 6, false); test(1, uint.max, uint.max, false); test(0, 1, 0, false); test(0, uint.max, 0, false); test(uint.max, 2, 2 * uint.max, true); test(1 << 16, 1U << 16, 0, true); bool overflow = true; assert(mulu(0, 0, overflow) == 0); assert(overflow); // sticky } /// ditto pragma(inline, true) ulong mulu(ulong x, uint y, scope ref bool overflow) { ulong r = x * y; if (x >> 32 && r / x != y) overflow = true; return r; } /// ditto pragma(inline, true) ulong mulu(ulong x, ulong y, scope ref bool overflow) { version (LDC_HasNativeI64Mul) { if (!__ctfe) { auto res = llvm_umul_with_overflow(x, y); overflow |= res.overflow; return res.result; } } immutable ulong r = x * y; if ((x | y) >> 32 && x && r / x != y) overflow = true; return r; } unittest { void test(T, U)(T x, U y, ulong r, bool overflow) @nogc nothrow { bool o; assert(mulu(x, y, o) == r); assert(o == overflow); } // One operand is zero test(0, 3, 0, false); test(0UL, 3, 0, false); test(0UL, 3UL, 0, false); test(3, 0, 0, false); test(3UL, 0, 0, false); test(3UL, 0UL, 0, false); // Small numbers test(2, 3, 6, false); test(2UL, 3, 6, false); test(2UL, 3UL, 6, false); // At the 32/64 border test(1, ulong(uint.max), uint.max, false); test(1UL, ulong(uint.max), uint.max, false); test(ulong(uint.max), 1, uint.max, false); test(ulong(uint.max), 1UL, uint.max, false); test(1, 1 + ulong(uint.max), 1 + ulong(uint.max), false); test(1UL, 1 + ulong(uint.max), 1 + ulong(uint.max), false); test(1 + ulong(uint.max), 1, 1 + ulong(uint.max), false); test(1 + ulong(uint.max), 1UL, 1 + ulong(uint.max), false); // At the limit test(1, ulong.max, ulong.max, false); test(1UL, ulong.max, ulong.max, false); test(ulong.max, 1, ulong.max, false); test(ulong.max, 1UL, ulong.max, false); // Miscellaneous test(0, 1, 0, false); test(0, ulong.max, 0, false); test(ulong.max, 2, 2 * ulong.max, true); test(1UL << 32, 1UL << 32, 0, true); // Must be sticky bool overflow = true; assert(mulu(0UL, 0UL, overflow) == 0); assert(overflow); // sticky } static if (is(ucent)) { /// ditto pragma(inline, true) ucent mulu(ucent x, ucent y, scope ref bool overflow) { version (LDC_HasNativeI64Mul) { if (!__ctfe) { auto res = llvm_umul_with_overflow(x, y); overflow |= res.overflow; return res.result; } } immutable ucent r = x * y; if (x && (r / x) != y) overflow = true; return r; } unittest { void test(ucent x, ucent y, ucent r, bool overflow) @nogc nothrow { bool o; assert(mulu(x, y, o) == r); assert(o == overflow); } test(2, 3, 6, false); test(1, ucent.max, ucent.max, false); test(0, 1, 0, false); test(0, ucent.max, 0, false); test(ucent.max, 2, 2 * ucent.max, true); test(cast(ucent)1UL << 64, cast(ucent)1UL << 64, 0, true); bool overflow = true; assert(mulu(0UL, 0UL, overflow) == 0); assert(overflow); // sticky } } mir-core-1.0.2/source/mir/conv.d000066400000000000000000000757301353705753200164560ustar00rootroot00000000000000/++ Conversion utilities. License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: Phobos Team, Ilya Yaroshenko +/ module mir.conv; import std.traits; /++ The `to` template converts a value from one type _to another. The source type is deduced and the target type must be specified, for example the expression `to!int(42.0)` converts the number 42 from `double` _to `int`. The conversion is "unsafe", i.e., it does not check for overflow. +/ template to(T) { /// auto ref T to(A...)(auto ref A args) if (A.length > 0) { static if (A.length == 1 && isImplicitlyConvertible!(A[0], T)) return args[0]; else static if (is(T == class) && is(typeof(new T(args)))) return new T(args); else static if (is(typeof(T(args)))) return T(args); else static if (A.length == 1) return cast(T) args[0]; else static assert(0); } } /++ emplaceRef is a package function for phobos internal use. It works like emplace, but takes its argument by ref (as opposed to "by pointer"). This makes it easier to use, easier to be safe, and faster in a non-inline build. Furthermore, emplaceRef optionally takes a type parameter, which specifies the type we want to build. This helps to build qualified objects on mutable buffer, without breaking the type system with unsafe casts. +/ template emplaceRef(T) { /// void emplaceRef(UT, Args...)(ref UT chunk, auto ref Args args) { static if (args.length == 0) { static assert(is(typeof({static T i;})), "Cannot emplace a %1$s because " ~ T.stringof ~ "s.this() is annotated with @disable."); static if (is(T == class)) static assert(!isAbstractClass!T, T.stringof ~ " is abstract and it can't be emplaced"); emplaceInitializer(chunk); } else static if ( !is(T == struct) && Args.length == 1 /* primitives, enums, arrays */ || Args.length == 1 && is(typeof({T t = args[0];})) /* conversions */ || is(typeof(T(args))) /* general constructors */) { static struct S { T payload; this(ref Args x) { static if (Args.length == 1) static if (is(typeof(payload = x[0]))) payload = x[0]; else payload = T(x[0]); else payload = T(x); } } if (__ctfe) { static if (is(typeof(chunk = T(args)))) chunk = T(args); else static if (args.length == 1 && is(typeof(chunk = args[0]))) chunk = args[0]; else assert(0, "CTFE emplace doesn't support " ~ T.stringof ~ " from " ~ Args.stringof); } else { S* p = () @trusted { return cast(S*) &chunk; }(); static if (UT.sizeof > 0) emplaceInitializer(*p); p.__ctor(args); } } else static if (is(typeof(chunk.__ctor(args)))) { // This catches the rare case of local types that keep a frame pointer emplaceInitializer(chunk); chunk.__ctor(args); } else { //We can't emplace. Try to diagnose a disabled postblit. static assert(!(Args.length == 1 && is(Args[0] : T)), "Cannot emplace a " ~ T.stringof ~ " because " ~ T.stringof ~ ".this(this) is annotated with @disable."); //We can't emplace. static assert(false, T.stringof ~ " cannot be emplaced from " ~ Args[].stringof ~ "."); } } } // ditto void emplaceRef(UT, Args...)(ref UT chunk, auto ref Args args) if (is(UT == Unqual!UT)) { emplaceRef!UT(chunk, args); } /++ Emplace helper function. +/ void emplaceInitializer(T)(scope ref T chunk) @trusted pure nothrow { static if (!hasElaborateAssign!T && isAssignable!T) chunk = T.init; else { static if (__VERSION__ < 2083) { import core.stdc.string : memcpy; static immutable T init = T.init; memcpy(&chunk, &init, T.sizeof); } else static if (__traits(isZeroInit, T)) { import core.stdc.string : memset; memset(&chunk, 0, T.sizeof); } else { import core.stdc.string : memcpy; static immutable T init = T.init; memcpy(&chunk, &init, T.sizeof); } } } // emplace /** Given a pointer `chunk` to uninitialized memory (but already typed as `T`), constructs an object of non-`class` type `T` at that address. If `T` is a class, initializes the class reference to null. Returns: A pointer to the newly constructed object (which is the same as `chunk`). */ T* emplace(T)(T* chunk) @safe pure nothrow { emplaceRef!T(*chunk); return chunk; } /// @system unittest { static struct S { int i = 42; } S[2] s2 = void; emplace(&s2); assert(s2[0].i == 42 && s2[1].i == 42); } /// @system unittest { interface I {} class K : I {} K k = void; emplace(&k); assert(k is null); I i = void; emplace(&i); assert(i is null); } /** Given a pointer `chunk` to uninitialized memory (but already typed as a non-class type `T`), constructs an object of type `T` at that address from arguments `args`. If `T` is a class, initializes the class reference to `args[0]`. This function can be `@trusted` if the corresponding constructor of `T` is `@safe`. Returns: A pointer to the newly constructed object (which is the same as `chunk`). */ T* emplace(T, Args...)(T* chunk, auto ref Args args) if (is(T == struct) || Args.length == 1) { emplaceRef!T(*chunk, args); return chunk; } /// @system unittest { int a; int b = 42; assert(*emplace!int(&a, b) == 42); } @system unittest { shared int i; emplace(&i, 42); assert(i == 42); } private @nogc pure nothrow @safe void testEmplaceChunk(void[] chunk, size_t typeSize, size_t typeAlignment) { assert(chunk.length >= typeSize, "emplace: Chunk size too small."); assert((cast(size_t) chunk.ptr) % typeAlignment == 0, "emplace: Chunk is not aligned."); } /** Given a raw memory area `chunk` (but already typed as a class type `T`), constructs an object of `class` type `T` at that address. The constructor is passed the arguments `Args`. If `T` is an inner class whose `outer` field can be used to access an instance of the enclosing class, then `Args` must not be empty, and the first member of it must be a valid initializer for that `outer` field. Correct initialization of this field is essential to access members of the outer class inside `T` methods. Note: This function is `@safe` if the corresponding constructor of `T` is `@safe`. Returns: The newly constructed object. */ T emplace(T, Args...)(T chunk, auto ref Args args) if (is(T == class)) { static assert(!isAbstractClass!T, T.stringof ~ " is abstract and it can't be emplaced"); // Initialize the object in its pre-ctor state enum classSize = __traits(classInstanceSize, T); (() @trusted => (cast(void*) chunk)[0 .. classSize] = typeid(T).initializer[])(); static if (isInnerClass!T) { static assert(Args.length > 0, "Initializing an inner class requires a pointer to the outer class"); static assert(is(Args[0] : typeof(T.outer)), "The first argument must be a pointer to the outer class"); chunk.outer = args[0]; alias args1 = args[1..$]; } else alias args1 = args; // Call the ctor if any static if (is(typeof(chunk.__ctor(args1)))) { // T defines a genuine constructor accepting args // Go the classic route: write .init first, then call ctor chunk.__ctor(args1); } else { static assert(args1.length == 0 && !is(typeof(&T.__ctor)), "Don't know how to initialize an object of type " ~ T.stringof ~ " with arguments " ~ typeof(args1).stringof); } return chunk; } /// @safe unittest { () @safe { class SafeClass { int x; @safe this(int x) { this.x = x; } } auto buf = new void[__traits(classInstanceSize, SafeClass)]; auto support = (() @trusted => cast(SafeClass)(buf.ptr))(); auto safeClass = emplace!SafeClass(support, 5); assert(safeClass.x == 5); class UnsafeClass { int x; @system this(int x) { this.x = x; } } auto buf2 = new void[__traits(classInstanceSize, UnsafeClass)]; auto support2 = (() @trusted => cast(UnsafeClass)(buf2.ptr))(); static assert(!__traits(compiles, emplace!UnsafeClass(support2, 5))); static assert(!__traits(compiles, emplace!UnsafeClass(buf2, 5))); }(); } @safe unittest { class Outer { int i = 3; class Inner { @safe auto getI() { return i; } } } auto outerBuf = new void[__traits(classInstanceSize, Outer)]; auto outerSupport = (() @trusted => cast(Outer)(outerBuf.ptr))(); auto innerBuf = new void[__traits(classInstanceSize, Outer.Inner)]; auto innerSupport = (() @trusted => cast(Outer.Inner)(innerBuf.ptr))(); auto inner = innerSupport.emplace!(Outer.Inner)(outerSupport.emplace!Outer); assert(inner.getI == 3); } /** Given a raw memory area `chunk`, constructs an object of `class` type `T` at that address. The constructor is passed the arguments `Args`. If `T` is an inner class whose `outer` field can be used to access an instance of the enclosing class, then `Args` must not be empty, and the first member of it must be a valid initializer for that `outer` field. Correct initialization of this field is essential to access members of the outer class inside `T` methods. Preconditions: `chunk` must be at least as large as `T` needs and should have an alignment multiple of `T`'s alignment. (The size of a `class` instance is obtained by using $(D __traits(classInstanceSize, T))). Note: This function can be `@trusted` if the corresponding constructor of `T` is `@safe`. Returns: The newly constructed object. */ T emplace(T, Args...)(void[] chunk, auto ref Args args) if (is(T == class)) { enum classSize = __traits(classInstanceSize, T); testEmplaceChunk(chunk, classSize, classInstanceAlignment!T); return emplace!T(cast(T)(chunk.ptr), args); } /// @system unittest { static class C { int i; this(int i){this.i = i;} } auto buf = new void[__traits(classInstanceSize, C)]; auto c = emplace!C(buf, 5); assert(c.i == 5); } @system unittest { class Outer { int i = 3; class Inner { auto getI() { return i; } } } auto outerBuf = new void[__traits(classInstanceSize, Outer)]; auto innerBuf = new void[__traits(classInstanceSize, Outer.Inner)]; auto inner = innerBuf.emplace!(Outer.Inner)(outerBuf.emplace!Outer); assert(inner.getI == 3); } @nogc pure nothrow @safe unittest { int var = 6; align(__conv_EmplaceTestClass.alignof) ubyte[__traits(classInstanceSize, __conv_EmplaceTestClass)] buf; auto support = (() @trusted => cast(__conv_EmplaceTestClass)(buf.ptr))(); auto k = emplace!__conv_EmplaceTestClass(support, 5, var); assert(k.i == 5); assert(var == 7); } /** Given a raw memory area `chunk`, constructs an object of non-$(D class) type `T` at that address. The constructor is passed the arguments `args`, if any. Preconditions: `chunk` must be at least as large as `T` needs and should have an alignment multiple of `T`'s alignment. Note: This function can be `@trusted` if the corresponding constructor of `T` is `@safe`. Returns: A pointer to the newly constructed object. */ T* emplace(T, Args...)(void[] chunk, auto ref Args args) if (!is(T == class)) { testEmplaceChunk(chunk, T.sizeof, T.alignof); emplaceRef!T(*cast(Unqual!T*) chunk.ptr, args); return cast(T*) chunk.ptr; } /// @system unittest { struct S { int a, b; } auto buf = new void[S.sizeof]; S s; s.a = 42; s.b = 43; auto s1 = emplace!S(buf, s); assert(s1.a == 42 && s1.b == 43); } // Bulk of emplace unittests starts here @system unittest /* unions */ { static union U { string a; int b; struct { long c; int[] d; } } U u1 = void; U u2 = { "hello" }; emplace(&u1, u2); assert(u1.a == "hello"); } version (unittest) private struct __conv_EmplaceTest { int i = 3; this(int i) { assert(this.i == 3 && i == 5); this.i = i; } this(int i, ref int j) { assert(i == 5 && j == 6); this.i = i; ++j; } @disable: this(); this(this); void opAssign(); } version (unittest) private class __conv_EmplaceTestClass { int i = 3; this(int i) @nogc @safe pure nothrow { assert(this.i == 3 && i == 5); this.i = i; } this(int i, ref int j) @nogc @safe pure nothrow { assert(i == 5 && j == 6); this.i = i; ++j; } } @system unittest // bugzilla 15772 { abstract class Foo {} class Bar: Foo {} void[] memory; // test in emplaceInitializer static assert(!is(typeof(emplace!Foo(cast(Foo*) memory.ptr)))); static assert( is(typeof(emplace!Bar(cast(Bar*) memory.ptr)))); // test in the emplace overload that takes void[] static assert(!is(typeof(emplace!Foo(memory)))); static assert( is(typeof(emplace!Bar(memory)))); } @system unittest { struct S { @disable this(); } S s = void; static assert(!__traits(compiles, emplace(&s))); emplace(&s, S.init); } @system unittest { struct S1 {} struct S2 { void opAssign(S2); } S1 s1 = void; S2 s2 = void; S1[2] as1 = void; S2[2] as2 = void; emplace(&s1); emplace(&s2); emplace(&as1); emplace(&as2); } @system unittest { static struct S1 { this(this) @disable; } static struct S2 { this() @disable; } S1[2] ss1 = void; S2[2] ss2 = void; emplace(&ss1); static assert(!__traits(compiles, emplace(&ss2))); S1 s1 = S1.init; S2 s2 = S2.init; static assert(!__traits(compiles, emplace(&ss1, s1))); emplace(&ss2, s2); } @system unittest { struct S { immutable int i; } S s = void; S[2] ss1 = void; S[2] ss2 = void; emplace(&s, 5); assert(s.i == 5); emplace(&ss1, s); assert(ss1[0].i == 5 && ss1[1].i == 5); emplace(&ss2, ss1); assert(ss2 == ss1); } //Start testing emplace-args here @system unittest { interface I {} class K : I {} K k = null, k2 = new K; assert(k !is k2); emplace!K(&k, k2); assert(k is k2); I i = null; assert(i !is k); emplace!I(&i, k); assert(i is k); } @system unittest { static struct S { int i = 5; void opAssign(S){assert(0);} } S[2] sa = void; S[2] sb; emplace(&sa, sb); assert(sa[0].i == 5 && sa[1].i == 5); } //Start testing emplace-struct here // Test constructor branch @system unittest { struct S { double x = 5, y = 6; this(int a, int b) { assert(x == 5 && y == 6); x = a; y = b; } } auto s1 = new void[S.sizeof]; auto s2 = S(42, 43); assert(*emplace!S(cast(S*) s1.ptr, s2) == s2); assert(*emplace!S(cast(S*) s1, 44, 45) == S(44, 45)); } @system unittest { __conv_EmplaceTest k = void; emplace(&k, 5); assert(k.i == 5); } @system unittest { int var = 6; __conv_EmplaceTest k = void; emplace(&k, 5, var); assert(k.i == 5); assert(var == 7); } // Test matching fields branch @system unittest { struct S { uint n; } S s; emplace!S(&s, 2U); assert(s.n == 2); } @safe unittest { struct S { int a, b; this(int){} } S s; static assert(!__traits(compiles, emplace!S(&s, 2, 3))); } @system unittest { struct S { int a, b = 7; } S s1 = void, s2 = void; emplace!S(&s1, 2); assert(s1.a == 2 && s1.b == 7); emplace!S(&s2, 2, 3); assert(s2.a == 2 && s2.b == 3); } //opAssign @system unittest { static struct S { int i = 5; void opAssign(int){assert(0);} void opAssign(S){assert(0);} } S sa1 = void; S sa2 = void; S sb1 = S(1); emplace(&sa1, sb1); emplace(&sa2, 2); assert(sa1.i == 1); assert(sa2.i == 2); } //postblit precedence @system unittest { //Works, but breaks in "-w -O" because of @@@9332@@@. //Uncomment test when 9332 is fixed. static struct S { int i; this(S other){assert(false);} this(int i){this.i = i;} this(this){} } S a = void; assert(is(typeof({S b = a;}))); //Postblit assert(is(typeof({S b = S(a);}))); //Constructor auto b = S(5); emplace(&a, b); assert(a.i == 5); static struct S2 { int* p; this(const S2){} } static assert(!is(immutable S2 : S2)); S2 s2 = void; immutable is2 = (immutable S2).init; emplace(&s2, is2); } //nested structs and postblit @system unittest { static struct S { int* p; this(int i){p = [i].ptr;} this(this) { if (p) p = [*p].ptr; } } static struct SS { S s; void opAssign(const SS) { assert(0); } } SS ssa = void; SS ssb = SS(S(5)); emplace(&ssa, ssb); assert(*ssa.s.p == 5); assert(ssa.s.p != ssb.s.p); } //disabled postblit @system unittest { static struct S1 { int i; @disable this(this); } S1 s1 = void; emplace(&s1, 1); assert(s1.i == 1); static assert(!__traits(compiles, emplace(&s1, S1.init))); static struct S2 { int i; @disable this(this); this(ref S2){} } S2 s2 = void; static assert(!__traits(compiles, emplace(&s2, 1))); emplace(&s2, S2.init); static struct SS1 { S1 s; } SS1 ss1 = void; emplace(&ss1); static assert(!__traits(compiles, emplace(&ss1, SS1.init))); static struct SS2 { S2 s; } SS2 ss2 = void; emplace(&ss2); static assert(!__traits(compiles, emplace(&ss2, SS2.init))); // SS1 sss1 = s1; //This doesn't compile // SS1 sss1 = SS1(s1); //This doesn't compile // So emplace shouldn't compile either static assert(!__traits(compiles, emplace(&sss1, s1))); static assert(!__traits(compiles, emplace(&sss2, s2))); } //Imutability @system unittest { //Castable immutability { static struct S1 { int i; } static assert(is( immutable(S1) : S1)); S1 sa = void; auto sb = immutable(S1)(5); emplace(&sa, sb); assert(sa.i == 5); } //Un-castable immutability { static struct S2 { int* p; } static assert(!is(immutable(S2) : S2)); S2 sa = void; auto sb = immutable(S2)(null); assert(!__traits(compiles, emplace(&sa, sb))); } } @system unittest { static struct S { immutable int i; immutable(int)* j; } S s = void; emplace(&s, 1, null); emplace(&s, 2, &s.i); assert(s is S(2, &s.i)); } //Context pointer @system unittest { int i = 0; { struct S1 { void foo(){++i;} } S1 sa = void; S1 sb; emplace(&sa, sb); sa.foo(); assert(i == 1); } { struct S2 { void foo(){++i;} this(this){} } S2 sa = void; S2 sb; emplace(&sa, sb); sa.foo(); assert(i == 2); } } //Alias this @system unittest { static struct S { int i; } //By Ref { static struct SS1 { int j; S s; alias s this; } S s = void; SS1 ss = SS1(1, S(2)); emplace(&s, ss); assert(s.i == 2); } //By Value { static struct SS2 { int j; S s; S foo() @property{return s;} alias foo this; } S s = void; SS2 ss = SS2(1, S(2)); emplace(&s, ss); assert(s.i == 2); } } version (unittest) { //Ambiguity private struct __std_conv_S { int i; this(__std_conv_SS ss) {assert(0);} static opCall(__std_conv_SS ss) { __std_conv_S s; s.i = ss.j; return s; } } private struct __std_conv_SS { int j; __std_conv_S s; ref __std_conv_S foo() return @property {s.i = j; return s;} alias foo this; } } @system unittest { static assert(is(__std_conv_SS : __std_conv_S)); __std_conv_S s = void; __std_conv_SS ss = __std_conv_SS(1); __std_conv_S sTest1 = ss; //this calls "SS alias this" (and not "S.this(SS)") emplace(&s, ss); //"alias this" should take precedence in emplace over "opCall" assert(s.i == 1); } //Nested classes @system unittest { class A{} static struct S { A a; } S s1 = void; S s2 = S(new A); emplace(&s1, s2); assert(s1.a is s2.a); } //safety & nothrow & CTFE @system unittest { //emplace should be safe for anything with no elaborate opassign static struct S1 { int i; } static struct S2 { int i; this(int j)@safe nothrow{i = j;} } int i; S1 s1 = void; S2 s2 = void; auto pi = &i; auto ps1 = &s1; auto ps2 = &s2; void foo() @safe nothrow { emplace(pi); emplace(pi, 5); emplace(ps1); emplace(ps1, 5); emplace(ps1, S1.init); emplace(ps2); emplace(ps2, 5); emplace(ps2, S2.init); } foo(); T bar(T)() @property { T t/+ = void+/; //CTFE void illegal emplace(&t, 5); return t; } // CTFE enum a = bar!int; static assert(a == 5); enum b = bar!S1; static assert(b.i == 5); enum c = bar!S2; static assert(c.i == 5); // runtime auto aa = bar!int; assert(aa == 5); auto bb = bar!S1; assert(bb.i == 5); auto cc = bar!S2; assert(cc.i == 5); } @system unittest { struct S { int[2] get(){return [1, 2];} alias get this; } struct SS { int[2] ii; } struct ISS { int[2] ii; } S s; SS ss = void; ISS iss = void; emplace(&ss, s); emplace(&iss, s); assert(ss.ii == [1, 2]); assert(iss.ii == [1, 2]); } //disable opAssign @system unittest { static struct S { @disable void opAssign(S); } S s; emplace(&s, S.init); } //opCall @system unittest { int i; //Without constructor { static struct S1 { int i; static S1 opCall(int*){assert(0);} } S1 s = void; static assert(!__traits(compiles, emplace(&s, 1))); } //With constructor { static struct S2 { int i = 0; static S2 opCall(int*){assert(0);} static S2 opCall(int){assert(0);} this(int i){this.i = i;} } S2 s = void; emplace(&s, 1); assert(s.i == 1); } //With postblit ambiguity { static struct S3 { int i = 0; static S3 opCall(ref S3){assert(0);} } S3 s = void; emplace(&s, S3.init); } } //static arrays @system unittest { static struct S { int[2] ii; } static struct IS { immutable int[2] ii; } int[2] ii; S s = void; IS ims = void; ubyte ub = 2; emplace(&s, ub); emplace(&s, ii); emplace(&ims, ub); emplace(&ims, ii); uint[2] uu; static assert(!__traits(compiles, {S ss = S(uu);})); static assert(!__traits(compiles, emplace(&s, uu))); } @system unittest { int[2] sii; int[2] sii2; uint[2] uii; uint[2] uii2; emplace(&sii, 1); emplace(&sii, 1U); emplace(&uii, 1); emplace(&uii, 1U); emplace(&sii, sii2); //emplace(&sii, uii2); //Sorry, this implementation doesn't know how to... //emplace(&uii, sii2); //Sorry, this implementation doesn't know how to... emplace(&uii, uii2); emplace(&sii, sii2[]); //emplace(&sii, uii2[]); //Sorry, this implementation doesn't know how to... //emplace(&uii, sii2[]); //Sorry, this implementation doesn't know how to... emplace(&uii, uii2[]); } @system unittest { bool allowDestruction = false; struct S { int i; this(this){} ~this(){assert(allowDestruction);} } S s = S(1); S[2] ss1 = void; S[2] ss2 = void; S[2] ss3 = void; emplace(&ss1, s); emplace(&ss2, ss1); emplace(&ss3, ss2[]); assert(ss1[1] == s); assert(ss2[1] == s); assert(ss3[1] == s); allowDestruction = true; } @system unittest { //Checks postblit, construction, and context pointer int count = 0; struct S { this(this) { ++count; } ~this() { --count; } } S s; { S[4] ss = void; emplace(&ss, s); assert(count == 4); } assert(count == 0); } @system unittest { struct S { int i; } S s; S[2][2][2] sss = void; emplace(&sss, s); } @system unittest //Constness { int a = void; emplaceRef!(const int)(a, 5); immutable i = 5; const(int)* p = void; emplaceRef!(const int*)(p, &i); struct S { int* p; } alias IS = immutable(S); S s = void; emplaceRef!IS(s, IS()); S[2] ss = void; emplaceRef!(IS[2])(ss, IS()); IS[2] iss = IS.init; emplaceRef!(IS[2])(ss, iss); emplaceRef!(IS[2])(ss, iss[]); } pure nothrow @safe @nogc unittest { int i; emplaceRef(i); emplaceRef!int(i); emplaceRef(i, 5); emplaceRef!int(i, 5); } // Test attribute propagation for UDTs pure nothrow @safe /* @nogc */ unittest { static struct Safe { this(this) pure nothrow @safe @nogc {} } Safe safe = void; emplaceRef(safe, Safe()); Safe[1] safeArr = [Safe()]; Safe[1] uninitializedSafeArr = void; emplaceRef(uninitializedSafeArr, safe); emplaceRef(uninitializedSafeArr, safeArr); static struct Unsafe { this(this) @system {} } Unsafe unsafe = void; static assert(!__traits(compiles, emplaceRef(unsafe, Unsafe()))); Unsafe[1] unsafeArr = [Unsafe()]; Unsafe[1] uninitializedUnsafeArr = void; static assert(!__traits(compiles, emplaceRef(uninitializedUnsafeArr, unsafe))); static assert(!__traits(compiles, emplaceRef(uninitializedUnsafeArr, unsafeArr))); } @system unittest { // Issue 15313 static struct Node { int payload; Node* next; uint refs; } import core.stdc.stdlib : malloc; void[] buf = malloc(Node.sizeof)[0 .. Node.sizeof]; const Node* n = emplace!(const Node)(buf, 42, null, 10); assert(n.payload == 42); assert(n.next == null); assert(n.refs == 10); } @system unittest { int var = 6; auto k = emplace!__conv_EmplaceTest(new void[__conv_EmplaceTest.sizeof], 5, var); assert(k.i == 5); assert(var == 7); } @system unittest { class A { int x = 5; int y = 42; this(int z) { assert(x == 5 && y == 42); x = y = z; } } void[] buf; static align(A.alignof) byte[__traits(classInstanceSize, A)] sbuf; buf = sbuf[]; auto a = emplace!A(buf, 55); assert(a.x == 55 && a.y == 55); // emplace in bigger buffer buf = new byte[](__traits(classInstanceSize, A) + 10); a = emplace!A(buf, 55); assert(a.x == 55 && a.y == 55); // need ctor args static assert(!is(typeof(emplace!A(buf)))); } // Bulk of emplace unittests ends here /++ +/ T[] uninitializedFillDefault(T)(return scope T[] array) nothrow @nogc { static if (__VERSION__ < 2083) { static if (__traits(isIntegral, T) && 0 == cast(T) (T.init + 1)) { import core.stdc.string : memset; memset(array.ptr, 0xff, T.sizeof * array.length); return array; } else { pragma(inline, false); foreach(ref e; array) emplaceInitializer(e); return array; } } else { static if (__traits(isZeroInit, T)) { import core.stdc.string : memset; memset(array.ptr, 0, T.sizeof * array.length); return array; } else static if (__traits(isIntegral, T) && 0 == cast(T) (T.init + 1)) { import core.stdc.string : memset; memset(array.ptr, 0xff, T.sizeof * array.length); return array; } else { pragma(inline, false); foreach(ref e; array) emplaceInitializer(e); return array; } } } /// pure nothrow @nogc @system unittest { static struct S { int x = 42; @disable this(this); } int[5] expected = [42, 42, 42, 42, 42]; S[5] arr = void; uninitializedFillDefault(arr); assert((cast(int*) arr.ptr)[0 .. arr.length] == expected); } /// @system unittest { int[] a = [1, 2, 4]; uninitializedFillDefault(a); assert(a == [0, 0, 0]); } /++ Destroy structs and unions usnig `__xdtor` member if any. Do nothing for other types. +/ void xdestroy(T)(scope T[] ar) { static if ((is(T == struct) || is(T == union)) && __traits(hasMember, T, "__xdtor")) { static if (__traits(isSame, T, __traits(parent, ar[0].__xdtor))) { pragma(inline, false); foreach (ref e; ar) e.__xdtor(); } } } /// version(mir_test) nothrow @nogc unittest { __gshared int d; __gshared int c; struct D { ~this() nothrow @nogc {d++;} } extern(C++) struct C { ~this() nothrow @nogc {c++;} } C[2] carray; D[2] darray; carray.xdestroy; darray.xdestroy; assert(c == 2); assert(d == 2); c = 0; d = 0; } /* Determines whether `T` is a class nested inside another class and that `T.outer` is the implicit reference to the outer class (i.e. `outer` has not been used as a field or method name) Params: T = type to test Returns: `true` if `T` is a class nested inside another, with the conditions described above; `false` otherwise */ private template isInnerClass(T) if (is(T == class)) { static if (is(typeof(T.outer))) { import std.meta : staticIndexOf; enum isInnerClass = __traits(isSame, typeof(T.outer), __traits(parent, T)) && (staticIndexOf!(__traits(allMembers, T), "outer") == -1); } else enum isInnerClass = false; } mir-core-1.0.2/source/mir/functional.d000066400000000000000000000472461353705753200176540ustar00rootroot00000000000000/++ Functions that manipulate other functions. This module provides functions for compile time function composition. These functions are helpful when constructing predicates for the algorithms in $(MREF mir, ndslice). $(BOOKTABLE $(H2 Functions), $(TR $(TH Function Name) $(TH Description)) $(TR $(TD $(LREF naryFun)) $(TD Create a unary, binary or N-nary function from a string. Most often used when defining algorithms on ranges and slices. )) $(TR $(TD $(LREF pipe)) $(TD Join a couple of functions into one that executes the original functions one after the other, using one function's result for the next function's argument. )) $(TR $(TD $(LREF not)) $(TD Creates a function that negates another. )) $(TR $(TD $(LREF reverseArgs)) $(TD Predicate that reverses the order of its arguments. )) $(TR $(TD $(LREF forward)) $(TD Forwards function arguments with saving ref-ness. )) $(TR $(TD $(LREF refTuple)) $(TD Removes $(LREF Ref) shell. )) $(TR $(TD $(LREF unref)) $(TD Creates a $(LREF RefTuple) structure. )) $(TR $(TD $(LREF __ref)) $(TD Creates a $(LREF Ref) structure. )) ) Copyright: Andrei Alexandrescu 2008 - 2009, Ilya Yaroshenko 2016-. License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: Ilya Yaroshenko, $(HTTP erdani.org, Andrei Alexandrescu (some original code from std.functional)) Macros: NDSLICE = $(REF_ALTTEXT $(TT $2), $2, mir, ndslice, $1)$(NBSP) +/ module mir.functional; import std.meta; import std.traits; private enum isRef(T) = is(T : Ref!T0, T0); import mir.math.common: optmath; @optmath: /++ Constructs static array. +/ T[N] staticArray(T, size_t N)(T[N] a...) { return a; } /++ Simple wrapper that holds a pointer. It is used for as workaround to return multiple auto ref values. +/ struct Ref(T) if (!isRef!T) { @optmath: @disable this(); /// this(ref T value) @trusted { __ptr = &value; } /// T* __ptr; /// ref inout(T) __value() inout @property { return *__ptr; } /// alias __value this; /// bool opEquals(scope Ref!T rhs) const scope { return __value == rhs.__value; } static if (__traits(hasMember, T, "toHash") || __traits(isScalar, T)) /// size_t toHash() const { return hashOf(__value); } } /// Creates $(LREF Ref) wrapper. Ref!T _ref(T)(ref T value) { return Ref!T(value); } private mixin template _RefTupleMixin(T...) if (T.length <= 26) { static if (T.length) { enum i = T.length - 1; static if (isRef!(T[i])) mixin(`@optmath @property ref ` ~ cast(char)('a' + i) ~ `() { return *expand[` ~ i.stringof ~ `].__ptr; }` ); else mixin(`alias ` ~ cast(char)('a' + i) ~ ` = expand[` ~ i.stringof ~ `];`); mixin ._RefTupleMixin!(T[0 .. $-1]); } } /++ Simplified tuple structure. Some fields may be type of $(LREF Ref). Ref stores a pointer to a values. +/ struct RefTuple(T...) { @optmath: T expand; alias expand this; mixin _RefTupleMixin!T; } /// Removes $(LREF Ref) shell. alias Unref(V : Ref!T, T) = T; /// ditto alias Unref(V : RefTuple!T, T...) = RefTuple!(staticMap!(.Unref, T)); /// ditto alias Unref(V) = V; /++ Returns: a $(LREF RefTuple) structure. +/ RefTuple!Args refTuple(Args...)(auto ref Args args) { return RefTuple!Args(args); } /// Removes $(LREF Ref) shell. ref T unref(V : Ref!T, T)(scope return V value) { return *value.__ptr; } /// ditto Unref!(RefTuple!T) unref(V : RefTuple!T, T...)(V value) { typeof(return) ret; foreach(i, ref elem; ret.expand) elem = unref(value.expand[i]); return ret; } /// ditto ref V unref(V)(scope return ref V value) { return value; } /// ditto V unref(V)(V value) { return value; } private string joinStrings()(string[] strs) { if (strs.length) { auto ret = strs[0]; foreach(s; strs[1 .. $]) ret ~= s; return ret; } return null; } /++ Takes multiple functions and adjoins them together. The result is a $(LREF RefTuple) with one element per passed-in function. Upon invocation, the returned tuple is the adjoined results of all functions. Note: In the special case where only a single function is provided (`F.length == 1`), adjoin simply aliases to the single passed function (`F[0]`). +/ template adjoin(fun...) if (fun.length && fun.length <= 26) { static if (fun.length != 1) { static if (Filter!(_needNary, fun).length == 0) { /// @optmath auto adjoin(Args...)(auto ref Args args) { template _adjoin(size_t i) { static if (__traits(compiles, &fun[i](forward!args))) enum _adjoin = "Ref!(typeof(fun[" ~ i.stringof ~ "](forward!args)))(fun[" ~ i.stringof ~ "](forward!args)), "; else enum _adjoin = "fun[" ~ i.stringof ~ "](forward!args), "; } import mir.internal.utility; mixin("return refTuple(" ~ [staticMap!(_adjoin, Iota!(fun.length))].joinStrings ~ ");"); } } else alias adjoin = .adjoin!(staticMap!(naryFun, fun)); } else alias adjoin = naryFun!(fun[0]); } /// @safe version(mir_test) unittest { static bool f1(int a) { return a != 0; } static int f2(int a) { return a / 2; } auto x = adjoin!(f1, f2)(5); assert(is(typeof(x) == RefTuple!(bool, int))); assert(x.a == true && x.b == 2); } @safe version(mir_test) unittest { static bool F1(int a) { return a != 0; } auto x1 = adjoin!(F1)(5); static int F2(int a) { return a / 2; } auto x2 = adjoin!(F1, F2)(5); assert(is(typeof(x2) == RefTuple!(bool, int))); assert(x2.a && x2.b == 2); auto x3 = adjoin!(F1, F2, F2)(5); assert(is(typeof(x3) == RefTuple!(bool, int, int))); assert(x3.a && x3.b == 2 && x3.c == 2); bool F4(int a) { return a != x1; } alias eff4 = adjoin!(F4); static struct S { bool delegate(int) @safe store; int fun() { return 42 + store(5); } } S s; s.store = (int a) { return eff4(a); }; auto x4 = s.fun(); assert(x4 == 43); } //@safe version(mir_test) unittest { alias funs = staticMap!(naryFun, "a", "a * 2", "a * 3", "a * a", "-a"); alias afun = adjoin!funs; int a = 5, b = 5; assert(afun(a) == refTuple(Ref!int(a), 10, 15, 25, -5)); assert(afun(a) == refTuple(Ref!int(b), 10, 15, 25, -5)); static class C{} alias IC = immutable(C); IC foo(){return typeof(return).init;} RefTuple!(IC, IC, IC, IC) ret1 = adjoin!(foo, foo, foo, foo)(); static struct S{int* p;} alias IS = immutable(S); IS bar(){return typeof(return).init;} enum RefTuple!(IS, IS, IS, IS) ret2 = adjoin!(bar, bar, bar, bar)(); } private template needOpCallAlias(alias fun) { /* Determine whether or not naryFun need to alias to fun or * fun.opCall. Basically, fun is a function object if fun(...) compiles. We * want is(naryFun!fun) (resp., is(naryFun!fun)) to be true if fun is * any function object. There are 4 possible cases: * * 1) fun is the type of a function object with static opCall; * 2) fun is an instance of a function object with static opCall; * 3) fun is the type of a function object with non-static opCall; * 4) fun is an instance of a function object with non-static opCall. * * In case (1), is(naryFun!fun) should compile, but does not if naryFun * aliases itself to fun, because typeof(fun) is an error when fun itself * is a type. So it must be aliased to fun.opCall instead. All other cases * should be aliased to fun directly. */ static if (is(typeof(fun.opCall) == function)) { enum needOpCallAlias = !is(typeof(fun)) && __traits(compiles, () { return fun(Parameters!fun.init); }); } else enum needOpCallAlias = false; } private template _naryAliases(size_t n) if (n <= 26) { static if (n == 0) enum _naryAliases = ""; else { enum i = n - 1; enum _naryAliases = _naryAliases!i ~ "alias " ~ cast(char)('a' + i) ~ " = args[" ~ i.stringof ~ "];\n"; } } /++ Transforms a string representing an expression into a binary function. The string must use symbol names `a`, `b`, ..., `z` as the parameters. If `fun` is not a string, `naryFun` aliases itself away to `fun`. +/ template naryFun(alias fun) { static if (is(typeof(fun) : string)) { import mir.math.common; /// Specialization for string lambdas @optmath auto ref naryFun(Args...)(auto ref Args args) if (args.length <= 26) { mixin(_naryAliases!(Args.length)); return mixin(fun); } } else static if (needOpCallAlias!fun) alias naryFun = fun.opCall; else alias naryFun = fun; } /// @safe version(mir_test) unittest { // Strings are compiled into functions: alias isEven = naryFun!("(a & 1) == 0"); assert(isEven(2) && !isEven(1)); } /// @safe version(mir_test) unittest { alias less = naryFun!("a < b"); assert(less(1, 2) && !less(2, 1)); alias greater = naryFun!("a > b"); assert(!greater("1", "2") && greater("2", "1")); } /// `naryFun` accepts up to 26 arguments. @safe version(mir_test) unittest { assert(naryFun!("a * b + c")(2, 3, 4) == 10); } /// `naryFun` can return by reference. version(mir_test) unittest { int a; assert(&naryFun!("a")(a) == &a); } /// `args` parameter tuple version(mir_test) unittest { assert(naryFun!("args[0] + args[1]")(2, 3) == 5); } @safe version(mir_test) unittest { static int f1(int a) { return a + 1; } static assert(is(typeof(naryFun!(f1)(1)) == int)); assert(naryFun!(f1)(41) == 42); int f2(int a) { return a + 1; } static assert(is(typeof(naryFun!(f2)(1)) == int)); assert(naryFun!(f2)(41) == 42); assert(naryFun!("a + 1")(41) == 42); int num = 41; assert(naryFun!"a + 1"(num) == 42); // Issue 9906 struct Seen { static bool opCall(int n) { return true; } } static assert(needOpCallAlias!Seen); static assert(is(typeof(naryFun!Seen(1)))); assert(naryFun!Seen(1)); Seen s; static assert(!needOpCallAlias!s); static assert(is(typeof(naryFun!s(1)))); assert(naryFun!s(1)); struct FuncObj { bool opCall(int n) { return true; } } FuncObj fo; static assert(!needOpCallAlias!fo); static assert(is(typeof(naryFun!fo))); assert(naryFun!fo(1)); // Function object with non-static opCall can only be called with an // instance, not with merely the type. static assert(!is(typeof(naryFun!FuncObj))); } @safe version(mir_test) unittest { static int f1(int a, string b) { return a + 1; } static assert(is(typeof(naryFun!(f1)(1, "2")) == int)); assert(naryFun!(f1)(41, "a") == 42); string f2(int a, string b) { return b ~ "2"; } static assert(is(typeof(naryFun!(f2)(1, "1")) == string)); assert(naryFun!(f2)(1, "4") == "42"); assert(naryFun!("a + b")(41, 1) == 42); //@@BUG //assert(naryFun!("return a + b;")(41, 1) == 42); // Issue 9906 struct Seen { static bool opCall(int x, int y) { return true; } } static assert(is(typeof(naryFun!Seen))); assert(naryFun!Seen(1,1)); struct FuncObj { bool opCall(int x, int y) { return true; } } FuncObj fo; static assert(!needOpCallAlias!fo); static assert(is(typeof(naryFun!fo))); assert(naryFun!fo(1,1)); // Function object with non-static opCall can only be called with an // instance, not with merely the type. static assert(!is(typeof(naryFun!FuncObj))); } /++ N-ary predicate that reverses the order of arguments, e.g., given `pred(a, b, c)`, returns `pred(c, b, a)`. +/ template reverseArgs(alias fun) { /// @optmath auto ref reverseArgs(Args...)(auto ref Args args) if (is(typeof(fun(Reverse!args)))) { return fun(Reverse!args); } } /// @safe version(mir_test) unittest { int abc(int a, int b, int c) { return a * b + c; } alias cba = reverseArgs!abc; assert(abc(91, 17, 32) == cba(32, 17, 91)); } @safe version(mir_test) unittest { int a(int a) { return a * 2; } alias _a = reverseArgs!a; assert(a(2) == _a(2)); } @safe version(mir_test) unittest { int b() { return 4; } alias _b = reverseArgs!b; assert(b() == _b()); } @safe version(mir_test) unittest { alias gt = reverseArgs!(naryFun!("a < b")); assert(gt(2, 1) && !gt(1, 1)); int x = 42; bool xyz(int a, int b) { return a * x < b / x; } auto foo = &xyz; foo(4, 5); alias zyx = reverseArgs!(foo); assert(zyx(5, 4) == foo(4, 5)); } /++ Negates predicate `pred`. +/ template not(alias pred) { static if (!is(typeof(pred) : string) && !needOpCallAlias!pred) /// @optmath bool not(T...)(auto ref T args) { return !pred(args); } else alias not = .not!(naryFun!pred); } /// @safe version(mir_test) unittest { import std.algorithm.searching : find; import std.uni : isWhite; string a = " Hello, world!"; assert(find!(not!isWhite)(a) == "Hello, world!"); } @safe version(mir_test) unittest { assert(not!"a != 5"(5)); assert(not!"a != b"(5, 5)); assert(not!(() => false)()); assert(not!(a => a != 5)(5)); assert(not!((a, b) => a != b)(5, 5)); assert(not!((a, b, c) => a * b * c != 125 )(5, 5, 5)); } private template _pipe(size_t n) { static if (n) { enum i = n - 1; enum _pipe = "f[" ~ i.stringof ~ "](" ~ ._pipe!i ~ ")"; } else enum _pipe = "args"; } private template _unpipe(alias fun) { static if (__traits(compiles, TemplateOf!fun)) static if (__traits(isSame, TemplateOf!fun, .pipe)) alias _unpipe = TemplateArgsOf!fun; else alias _unpipe = fun; else alias _unpipe = fun; } private enum _needNary(alias fun) = is(typeof(fun) : string) || needOpCallAlias!fun; /++ Composes passed-in functions `fun[0], fun[1], ...` returning a function `f(x)` that in turn returns `...(fun[1](fun[0](x)))...`. Each function can be a regular functions, a delegate, a lambda, or a string. +/ template pipe(fun...) { static if (fun.length != 1) { alias f = staticMap!(_unpipe, fun); static if (f.length == fun.length && Filter!(_needNary, f).length == 0) { /// @optmath auto ref pipe(Args...)(auto ref Args args) { return mixin (_pipe!(fun.length)); } } else alias pipe = .pipe!(staticMap!(naryFun, f)); } else alias pipe = naryFun!(fun[0]); } /// @safe version(mir_test) unittest { assert(pipe!("a + b", a => a * 10)(2, 3) == 50); } /// `pipe` can return by reference. version(mir_test) unittest { int a; assert(&pipe!("a", "a")(a) == &a); } /// Template bloat reduction version(mir_test) unittest { enum a = "a * 2"; alias b = e => e + 2; alias p0 = pipe!(pipe!(a, b), pipe!(b, a)); alias p1 = pipe!(a, b, b, a); static assert(__traits(isSame, p0, p1)); } @safe version(mir_test) unittest { import std.algorithm.comparison : equal; import std.algorithm.iteration : map; import std.array : split; import std.conv : to; // First split a string in whitespace-separated tokens and then // convert each token into an integer assert(pipe!(split, map!(to!(int)))("1 2 3").equal([1, 2, 3])); } /++ Forwards function arguments with saving ref-ness. +/ template forward(args...) { static if (args.length) { alias arg = args[0]; static if (__traits(isRef, arg)) alias fwd = arg; else @optmath @property fwd()() { static if (is(typeof(arg) == struct)) { import std.algorithm.mutation : move; return arg.move; } else return arg; } alias forward = AliasSeq!(fwd, forward!(args[1..$])); } else alias forward = AliasSeq!(); } /// @safe version(mir_test) unittest { class C { static int foo(int n) { return 1; } static int foo(ref int n) { return 2; } } int bar()(auto ref int x) { return C.foo(forward!x); } assert(bar(1) == 1); int i; assert(bar(i) == 2); } /// @safe version(mir_test) unittest { void foo(int n, ref string s) { s = null; foreach (i; 0..n) s ~= "Hello"; } // forwards all arguments which are bound to parameter tuple void bar(Args...)(auto ref Args args) { return foo(forward!args); } // forwards all arguments with swapping order void baz(Args...)(auto ref Args args) { return foo(forward!args[$/2..$], forward!args[0..$/2]); } string s; bar(1, s); assert(s == "Hello"); baz(s, 2); assert(s == "HelloHello"); } @safe version(mir_test) unittest { auto foo(TL...)(auto ref TL args) { string result = ""; foreach (i, _; args) { result ~= __traits(isRef, args[i]) ? "L" : "R"; } return result; } string bar(TL...)(auto ref TL args) { return foo(forward!args); } string baz(TL...)(auto ref TL args) { int x; return foo(forward!args[3], forward!args[2], 1, forward!args[1], forward!args[0], x); } struct S {} S makeS(){ return S(); } int n; string s; assert(bar(S(), makeS(), n, s) == "RRLL"); assert(baz(S(), makeS(), n, s) == "LLRRRL"); } @safe version(mir_test) unittest { ref int foo(return ref int a) { return a; } ref int bar(Args)(auto ref Args args) { return foo(forward!args); } static assert(!__traits(compiles, { auto x1 = bar(3); })); // case of NG int value = 3; auto x2 = bar(value); // case of OK } struct AliasCall(T, string methodName, TemplateArgs...) { T __this; alias __this this; /// auto lightConst()() const @property { import mir.qualifier; return AliasCall!(LightConstOf!T, methodName, TemplateArgs)(__this.lightConst); } /// auto lightImmutable()() immutable @property { import mir.qualifier; return AliasCall!(LightImmutableOf!T, methodName, TemplateArgs)(__this.lightImmutable); } this()(auto ref T value) { __this = value; } auto ref opCall(Args...)(auto ref Args args) { mixin("return __this." ~ methodName ~ (TemplateArgs.length ? "!TemplateArgs" : "") ~ "(forward!args);"); } } /++ Replaces call operator (`opCall`) for the value using its method. The funciton is designed to use with $(NDSLICE, topology, vmap) or $(NDSLICE, topology, map). Params: methodName = name of the methods to use for opCall and opIndex TemplateArgs = template arguments +/ template aliasCall(string methodName, TemplateArgs...) { /++ Params: value = the value to wrap Returns: wrapped value with implemented opCall and opIndex methods +/ AliasCall!(T, methodName, TemplateArgs) aliasCall(T)(T value) @property { return typeof(return)(value); } /// ditto ref AliasCall!(T, methodName, TemplateArgs) aliasCall(T)(return ref T value) @property @trusted { return *cast(typeof(return)*) &value; } } /// @safe pure nothrow version(mir_test) unittest { static struct S { auto lightConst()() const @property { return S(); } auto fun(size_t ct_param = 1)(size_t rt_param) const { return rt_param + ct_param; } } S s; auto sfun = aliasCall!"fun"(s); assert(sfun(3) == 4); auto sfun10 = aliasCall!("fun", 10)(s); // uses fun!10 assert(sfun10(3) == 13); } mir-core-1.0.2/source/mir/internal/000077500000000000000000000000001353705753200171445ustar00rootroot00000000000000mir-core-1.0.2/source/mir/internal/memory.d000066400000000000000000000141751353705753200206310ustar00rootroot00000000000000/++ Copyright: See Phobos Copyright License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: $(HTTP erdani.com, Andrei Alexandrescu), Ilya Yaroshenko (Mir rework of original Phobos code) +/ module mir.internal.memory; pure nothrow @nogc extern(C) { /// void* malloc(size_t size); /// void* calloc(size_t nmemb, size_t size); /// void* realloc(void* ptr, size_t size); /// void free(void* ptr); } pure: enum uint platformAlignment = double.alignof > real.alignof ? double.alignof : real.alignof; @nogc nothrow: @safe pure package bool isGoodDynamicAlignment()(uint x) { return (x & -x) > (x - 1) && x >= (void*).sizeof; } version (Posix) private extern(C) int posix_memalign(void**, size_t, size_t); version (Windows) { // DMD Win 32 bit, DigitalMars C standard library misses the _aligned_xxx // functions family (snn.lib) version(CRuntime_DigitalMars) { // Helper to cast the infos written before the aligned pointer // this header keeps track of the size (required to realloc) and of // the base ptr (required to free). private struct AlignInfo() { void* basePtr; size_t size; @nogc nothrow pragma(inline, true) static AlignInfo* opCall()(void* ptr) { return cast(AlignInfo*) (ptr - AlignInfo.sizeof); } } private void* _aligned_malloc()(size_t size, size_t alignment) { size_t offset = alignment + size_t.sizeof * 2 - 1; // unaligned chunk void* basePtr = malloc(size + offset); if (!basePtr) return null; // get aligned location within the chunk void* alignedPtr = cast(void**)((cast(size_t)(basePtr) + offset) & ~(alignment - 1)); // write the header before the aligned pointer AlignInfo!()* head = AlignInfo!()(alignedPtr); head.basePtr = basePtr; head.size = size; return alignedPtr; } private void* _aligned_realloc()(void* ptr, size_t size, size_t alignment) { import core.stdc.string : memcpy; if (!ptr) return _aligned_malloc(size, alignment); // gets the header from the existing pointer AlignInfo!()* head = AlignInfo!()(ptr); // gets a new aligned pointer void* alignedPtr = _aligned_malloc(size, alignment); if (!alignedPtr) { //to https://msdn.microsoft.com/en-us/library/ms235462.aspx //see Return value: in this case the original block is unchanged return null; } // copy existing data memcpy(alignedPtr, ptr, head.size); free(head.basePtr); return alignedPtr; } private void _aligned_free()(void *ptr) { if (!ptr) return; AlignInfo!()* head = AlignInfo!()(ptr); free(head.basePtr); } } // DMD Win 64 bit, uses microsoft standard C library which implements them else { private extern(C) void* _aligned_free(void *); private extern(C) void* _aligned_malloc(size_t, size_t); private extern(C) void* _aligned_realloc(void *, size_t, size_t); } } /** Uses $(HTTP man7.org/linux/man-pages/man3/posix_memalign.3.html, $(D posix_memalign)) on Posix and $(HTTP msdn.microsoft.com/en-us/library/8z34s9c6(v=vs.80).aspx, $(D __aligned_malloc)) on Windows. */ version(Posix) @trusted void* alignedAllocate()(size_t bytes, uint a) { import core.stdc.errno : ENOMEM, EINVAL; assert(a.isGoodDynamicAlignment); void* result; auto code = posix_memalign(&result, a, bytes); if (code == ENOMEM) return null; else if (code == EINVAL) { assert(0, "AlignedMallocator.alignment is not a power of two " ~"multiple of (void*).sizeof, according to posix_memalign!"); } else if (code != 0) assert (0, "posix_memalign returned an unknown code!"); else return result; } else version(Windows) @trusted void* alignedAllocate()(size_t bytes, uint a) { return _aligned_malloc(bytes, a); } else static assert(0); /** Calls $(D free(b.ptr)) on Posix and $(HTTP msdn.microsoft.com/en-US/library/17b5h8td(v=vs.80).aspx, $(D __aligned_free(b.ptr))) on Windows. */ version (Posix) { alias alignedFree = free; } else version (Windows) @system void alignedFree()(void* b) { _aligned_free(b); } else static assert(0); /** On Posix, uses $(D alignedAllocate) and copies data around because there is no realloc for aligned memory. On Windows, calls $(HTTP msdn.microsoft.com/en-US/library/y69db7sx(v=vs.80).aspx, $(D __aligned_realloc(b.ptr, newSize, a))). */ version (Windows) @system void alignedReallocate()(ref void* b, size_t s, uint a) { if (!s) { alignedFree(b); b = null; return; } auto p = cast(ubyte*) _aligned_realloc(b, s, a); if (!p) return; b = p; } /// unittest { auto buffer = alignedAllocate(1024 * 1024 * 4, 128); alignedFree(buffer); //... } version (CRuntime_DigitalMars) version(unittest) private size_t addr(ref void* ptr) { return cast(size_t) ptr; } version(CRuntime_DigitalMars) unittest { void* m; m = _aligned_malloc(16, 0x10); if (m) { assert((m.addr & 0xF) == 0); _aligned_free(m); } m = _aligned_malloc(16, 0x100); if (m) { assert((m.addr & 0xFF) == 0); _aligned_free(m); } m = _aligned_malloc(16, 0x1000); if (m) { assert((m.addr & 0xFFF) == 0); _aligned_free(m); } m = _aligned_malloc(16, 0x10); if (m) { assert((cast(size_t)m & 0xF) == 0); m = _aligned_realloc(m, 32, 0x10000); if (m) assert((m.addr & 0xFFFF) == 0); _aligned_free(m); } m = _aligned_malloc(8, 0x10); if (m) { *cast(ulong*) m = 0X01234567_89ABCDEF; m = _aligned_realloc(m, 0x800, 0x1000); if (m) assert(*cast(ulong*) m == 0X01234567_89ABCDEF); _aligned_free(m); } } mir-core-1.0.2/source/mir/internal/utility.d000066400000000000000000000016411353705753200210160ustar00rootroot00000000000000/// module mir.internal.utility; private alias AliasSeq(T...) = T; /// alias Iota(size_t j) = Iota!(0, j); /// template Iota(size_t i, size_t j) { static assert(i <= j, "Iota: i should be less than or equal to j"); static if (i == j) alias Iota = AliasSeq!(); else alias Iota = AliasSeq!(i, Iota!(i + 1, j)); } /// template realType(C) if (__traits(isFloating, C) || isComplex!C) { import std.traits: Unqual; static if (isComplex!C) alias realType = typeof(Unqual!C.init.re); else alias realType = Unqual!C; } /// enum isComplex(C : creal) = true; /// ditto enum isComplex(C : cdouble) = true; /// ditto enum isComplex(C : cfloat) = true; /// ditto enum isComplex(C) = false; /// enum isFloatingPoint(C : real) = true; /// ditto enum isFloatingPoint(C : double) = true; /// ditto enum isFloatingPoint(C : float) = true; /// ditto enum isFloatingPoint(C) = false; mir-core-1.0.2/source/mir/math/000077500000000000000000000000001353705753200162615ustar00rootroot00000000000000mir-core-1.0.2/source/mir/math/common.d000066400000000000000000000554001353705753200177220ustar00rootroot00000000000000/++ Common floating point math functions. This module has generic LLVM-oriented API compatible with all D compilers. License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0). Copyright: Copyright © 2016-, Ilya Yaroshenko Authors: Ilya Yaroshenko, Phobos Team +/ module mir.math.common; import mir.internal.utility: isComplex, isFloatingPoint; version(LDC) { static import ldc.attributes; private alias AliasSeq(T...) = T; /++ Functions attribute, an alias for `AliasSeq!(llvmFastMathFlag("contract"));`. $(UL $(LI 1. Allow floating-point contraction (e.g. fusing a multiply followed by an addition into a fused multiply-and-add). ) ) Note: Can be used with all compilers. +/ alias fmamath = AliasSeq!(ldc.attributes.llvmFastMathFlag("contract")); /++ Functions attribute, an alias for `AliasSeq!(llvmAttr("unsafe-fp-math", "false"), llvmFastMathFlag("fast"))`. It is similar to $(LREF fastmath), but does not allow unsafe-fp-math. This flag does NOT force LDC to use the reciprocal of an argument rather than perform division. This flag is default for string lambdas. Note: Can be used with all compilers. +/ alias optmath = AliasSeq!(ldc.attributes.llvmFastMathFlag("fast")); /++ Functions attribute, an alias for `ldc.attributes.fastmath = AliasSeq!(llvmAttr("unsafe-fp-math", "true"), llvmFastMathFlag("fast"))` . $(UL $(LI 1. Enable optimizations that make unsafe assumptions about IEEE math (e.g. that addition is associative) or may not work for all input ranges. These optimizations allow the code generator to make use of some instructions which would otherwise not be usable (such as fsin on X86). ) $(LI 2. Allow optimizations to assume the arguments and result are not NaN. Such optimizations are required to retain defined behavior over NaNs, but the value of the result is undefined. ) $(LI 3. Allow optimizations to assume the arguments and result are not +$(BACKTICK)-inf. Such optimizations are required to retain defined behavior over +$(BACKTICK)-Inf, but the value of the result is undefined. ) $(LI 4. Allow optimizations to treat the sign of a zero argument or result as insignificant. ) $(LI 5. Allow optimizations to use the reciprocal of an argument rather than perform division. ) $(LI 6. Allow floating-point contraction (e.g. fusing a multiply followed by an addition into a fused multiply-and-add). ) $(LI 7. Allow algebraically equivalent transformations that may dramatically change results in floating point (e.g. reassociate). ) ) Note: Can be used with all compilers. +/ alias fastmath = ldc.attributes.fastmath; } else enum { /++ Functions attribute, an alias for `AliasSeq!(llvmFastMathFlag("contract"));`. $(UL $(LI Allow floating-point contraction (e.g. fusing a multiply followed by an addition into a fused multiply-and-add). ) ) Note: Can be used with all compilers. +/ fmamath, /++ Functions attribute, an alias for `AliasSeq!(llvmAttr("unsafe-fp-math", "false"), llvmFastMathFlag("fast"))`. It is similar to $(LREF fastmath), but does not allow unsafe-fp-math. This flag does NOT force LDC to use the reciprocal of an argument rather than perform division. This flag is default for string lambdas. Note: Can be used with all compilers. +/ optmath, /++ Functions attribute, an alias for `ldc.attributes.fastmath = AliasSeq!(llvmAttr("unsafe-fp-math", "true"), llvmFastMathFlag("fast"))` . $(UL $(LI Enable optimizations that make unsafe assumptions about IEEE math (e.g. that addition is associative) or may not work for all input ranges. These optimizations allow the code generator to make use of some instructions which would otherwise not be usable (such as fsin on X86). ) $(LI Allow optimizations to assume the arguments and result are not NaN. Such optimizations are required to retain defined behavior over NaNs, but the value of the result is undefined. ) $(LI Allow optimizations to assume the arguments and result are not +$(BACKTICK)-inf. Such optimizations are required to retain defined behavior over +$(BACKTICK)-Inf, but the value of the result is undefined. ) $(LI Allow optimizations to treat the sign of a zero argument or result as insignificant. ) $(LI Allow optimizations to use the reciprocal of an argument rather than perform division. ) $(LI Allow floating-point contraction (e.g. fusing a multiply followed by an addition into a fused multiply-and-add). ) $(LI Allow algebraically equivalent transformations that may dramatically change results in floating point (e.g. reassociate). ) ) Note: Can be used with all compilers. +/ fastmath } version(LDC) { nothrow @nogc pure @safe: pragma(LDC_intrinsic, "llvm.sqrt.f#") /// T sqrt(T)(in T val) if (isFloatingPoint!T); pragma(LDC_intrinsic, "llvm.sin.f#") /// T sin(T)(in T val) if (isFloatingPoint!T); pragma(LDC_intrinsic, "llvm.cos.f#") /// T cos(T)(in T val) if (isFloatingPoint!T); pragma(LDC_intrinsic, "llvm.powi.f#") /// T powi(T)(in T val, int power) if (isFloatingPoint!T); pragma(LDC_intrinsic, "llvm.pow.f#") /// T pow(T)(in T val, in T power) if (isFloatingPoint!T); pragma(LDC_intrinsic, "llvm.exp.f#") /// T exp(T)(in T val) if (isFloatingPoint!T); pragma(LDC_intrinsic, "llvm.log.f#") /// T log(T)(in T val) if (isFloatingPoint!T); pragma(LDC_intrinsic, "llvm.fma.f#") /// T fma(T)(T vala, T valb, T valc) if (isFloatingPoint!T); pragma(LDC_intrinsic, "llvm.fabs.f#") /// T fabs(T)(in T val) if (isFloatingPoint!T); pragma(LDC_intrinsic, "llvm.floor.f#") /// T floor(T)(in T val) if (isFloatingPoint!T); pragma(LDC_intrinsic, "llvm.exp2.f#") /// T exp2(T)(in T val) if (isFloatingPoint!T); pragma(LDC_intrinsic, "llvm.log10.f#") /// T log10(T)(in T val) if (isFloatingPoint!T); pragma(LDC_intrinsic, "llvm.log2.f#") /// T log2(T)(in T val) if (isFloatingPoint!T); pragma(LDC_intrinsic, "llvm.ceil.f#") /// T ceil(T)(in T val) if (isFloatingPoint!T); pragma(LDC_intrinsic, "llvm.trunc.f#") /// T trunc(T)(in T val) if (isFloatingPoint!T); pragma(LDC_intrinsic, "llvm.rint.f#") /// T rint(T)(in T val) if (isFloatingPoint!T); pragma(LDC_intrinsic, "llvm.nearbyint.f#") /// T nearbyint(T)(in T val) if (isFloatingPoint!T); pragma(LDC_intrinsic, "llvm.copysign.f#") /// T copysign(T)(in T mag, in T sgn) if (isFloatingPoint!T); pragma(LDC_intrinsic, "llvm.round.f#") /// T round(T)(in T val) if (isFloatingPoint!T); pragma(LDC_intrinsic, "llvm.fmuladd.f#") /// T fmuladd(T)(in T vala, in T valb, in T valc) if (isFloatingPoint!T); pragma(LDC_intrinsic, "llvm.minnum.f#") /// T fmin(T)(in T vala, in T valb) if (isFloatingPoint!T); pragma(LDC_intrinsic, "llvm.maxnum.f#") /// T fmax(T)(in T vala, in T valb) if (isFloatingPoint!T); } else version(GNU) { static import gcc.builtins; // Calls GCC builtin for either float (suffix "f"), double (no suffix), or real (suffix "l"). private enum mixinGCCBuiltin(string fun) = `static if (T.mant_dig == float.mant_dig) return gcc.builtins.__builtin_`~fun~`f(x);`~ ` else static if (T.mant_dig == double.mant_dig) return gcc.builtins.__builtin_`~fun~`(x);`~ ` else static if (T.mant_dig == real.mant_dig) return gcc.builtins.__builtin_`~fun~`l(x);`~ ` else static assert(0);`; // As above but for two-argument function. private enum mixinGCCBuiltin2(string fun) = `static if (T.mant_dig == float.mant_dig) return gcc.builtins.__builtin_`~fun~`f(x, y);`~ ` else static if (T.mant_dig == double.mant_dig) return gcc.builtins.__builtin_`~fun~`(x, y);`~ ` else static if (T.mant_dig == real.mant_dig) return gcc.builtins.__builtin_`~fun~`l(x, y);`~ ` else static assert(0);`; /// T sqrt(T)(in T x) if (isFloatingPoint!T) { mixin(mixinGCCBuiltin!`sqrt`); } /// T sin(T)(in T x) if (isFloatingPoint!T) { mixin(mixinGCCBuiltin!`sin`); } /// T cos(T)(in T x) if (isFloatingPoint!T) { mixin(mixinGCCBuiltin!`cos`); } /// T pow(T)(in T x, in T power) if (isFloatingPoint!T) { alias y = power; mixin(mixinGCCBuiltin2!`pow`); } /// T powi(T)(in T x, int power) if (isFloatingPoint!T) { alias y = power; mixin(mixinGCCBuiltin2!`powi`); } /// T exp(T)(in T x) if (isFloatingPoint!T) { mixin(mixinGCCBuiltin!`exp`); } /// T log(T)(in T x) if (isFloatingPoint!T) { mixin(mixinGCCBuiltin!`log`); } /// T fabs(T)(in T x) if (isFloatingPoint!T) { mixin(mixinGCCBuiltin!`fabs`); } /// T floor(T)(in T x) if (isFloatingPoint!T) { mixin(mixinGCCBuiltin!`floor`); } /// T exp2(T)(in T x) if (isFloatingPoint!T) { mixin(mixinGCCBuiltin!`exp2`); } /// T log10(T)(in T x) if (isFloatingPoint!T) { mixin(mixinGCCBuiltin!`log10`); } /// T log2(T)(in T x) if (isFloatingPoint!T) { mixin(mixinGCCBuiltin!`log2`); } /// T ceil(T)(in T x) if (isFloatingPoint!T) { mixin(mixinGCCBuiltin!`ceil`); } /// T trunc(T)(in T x) if (isFloatingPoint!T) { mixin(mixinGCCBuiltin!`trunc`); } /// T rint(T)(in T x) if (isFloatingPoint!T) { mixin(mixinGCCBuiltin!`rint`); } /// T nearbyint(T)(in T x) if (isFloatingPoint!T) { mixin(mixinGCCBuiltin!`nearbyint`); } /// T copysign(T)(in T mag, in T sgn) if (isFloatingPoint!T) { alias y = sgn; mixin(mixinGCCBuiltin2!`copysign`); } /// T round(T)(in T x) if (isFloatingPoint!T) { mixin(mixinGCCBuiltin!`round`); } /// T fmuladd(T)(in T a, in T b, in T c) if (isFloatingPoint!T) { static if (T.mant_dig == float.mant_dig) return gcc.builtins.__builtin_fmaf(a, b, c); else static if (T.mant_dig == double.mant_dig) return gcc.builtins.__builtin_fma(a, b, c); else static if (T.mant_dig == real.mant_dig) return gcc.builtins.__builtin_fmal(a, b, c); else static assert(0); } version(mir_test) unittest { assert(fmuladd!double(2, 3, 4) == 2 * 3 + 4); } /// T fmin(T)(in T x, in T y) if (isFloatingPoint!T) { mixin(mixinGCCBuiltin2!`fmin`); } /// T fmax(T)(in T x, in T y) if (isFloatingPoint!T) { mixin(mixinGCCBuiltin2!`fmax`); } } else static if (__VERSION__ >= 2082) // DMD 2.082 onward. { static import std.math; static import core.stdc.math; // Calls either std.math or cmath function for either float (suffix "f") // or double (no suffix). std.math will always be used during CTFE or for // arguments with greater than double precision or if the cmath function // is impure. private enum mixinCMath(string fun) = `pragma(inline, true); static if (!is(typeof(std.math.`~fun~`(0.5f)) == float) && is(typeof(() pure => core.stdc.math.`~fun~`f(0.5f)))) if (!__ctfe) { static if (T.mant_dig == float.mant_dig) return core.stdc.math.`~fun~`f(x); else static if (T.mant_dig == double.mant_dig) return core.stdc.math.`~fun~`(x); } return std.math.`~fun~`(x);`; // As above but for two-argument function (both arguments must be floating point). private enum mixinCMath2(string fun) = `pragma(inline, true); static if (!is(typeof(std.math.`~fun~`(0.5f, 0.5f)) == float) && is(typeof(() pure => core.stdc.math.`~fun~`f(0.5f, 0.5f)))) if (!__ctfe) { static if (T.mant_dig == float.mant_dig) return core.stdc.math.`~fun~`f(x, y); else static if (T.mant_dig == double.mant_dig) return core.stdc.math.`~fun~`(x, y); } return std.math.`~fun~`(x, y);`; // Some std.math functions have appropriate return types (float, // double, real) without need for a wrapper. We can alias them // directly but we leave the templates afterwards for documentation // purposes and so explicit template instantiation still works. // The aliases will always match before the templates. // Note that you cannot put any "static if" around the aliases or // compilation will fail due to conflict with the templates! alias sqrt = std.math.sqrt; alias sin = std.math.sin; alias cos = std.math.cos; alias exp = std.math.exp; //alias fabs = std.math.fabs; alias floor = std.math.floor; alias exp2 = std.math.exp2; alias ceil = std.math.ceil; alias rint = std.math.rint; /// T sqrt(T)(in T x) if (isFloatingPoint!T) { return std.math.sqrt(x); } /// T sin(T)(in T x) if (isFloatingPoint!T) { return std.math.sin(x); } /// T cos(T)(in T x) if (isFloatingPoint!T) { return std.math.cos(x); } /// T pow(T)(in T x, in T power) if (isFloatingPoint!T) { alias y = power; mixin(mixinCMath2!`pow`); } /// T powi(T)(in T x, int power) if (isFloatingPoint!T) { alias y = power; mixin(mixinCMath2!`pow`); } /// T exp(T)(in T x) if (isFloatingPoint!T) { return std.math.exp(x); } /// T log(T)(in T x) if (isFloatingPoint!T) { mixin(mixinCMath!`log`); } /// T fabs(T)(in T x) if (isFloatingPoint!T) { return std.math.fabs(x); } /// T floor(T)(in T x) if (isFloatingPoint!T) { return std.math.floor(x); } /// T exp2(T)(in T x) if (isFloatingPoint!T) { return std.math.exp2(x); } /// T log10(T)(in T x) if (isFloatingPoint!T) { mixin(mixinCMath!`log10`); } /// T log2(T)(in T x) if (isFloatingPoint!T) { mixin(mixinCMath!`log2`); } /// T ceil(T)(in T x) if (isFloatingPoint!T) { return std.math.ceil(x); } /// T trunc(T)(in T x) if (isFloatingPoint!T) { mixin(mixinCMath!`trunc`); } /// T rint(T)(in T x) if (isFloatingPoint!T) { return std.math.rint(x); } /// T nearbyint(T)(in T x) if (isFloatingPoint!T) { mixin(mixinCMath!`nearbyint`); } /// T copysign(T)(in T mag, in T sgn) if (isFloatingPoint!T) { alias x = mag; alias y = sgn; mixin(mixinCMath2!`copysign`); } /// T round(T)(in T x) if (isFloatingPoint!T) { mixin(mixinCMath!`round`); } /// T fmuladd(T)(in T a, in T b, in T c) if (isFloatingPoint!T) { return a * b + c; } version(mir_test) unittest { assert(fmuladd!double(2, 3, 4) == 2 * 3 + 4); } /// T fmin(T)(in T x, in T y) if (isFloatingPoint!T) { version (Windows) // https://issues.dlang.org/show_bug.cgi?id=19798 { version (CRuntime_Microsoft) mixin(mixinCMath2!`fmin`); else return std.math.fmin(x, y); } else mixin(mixinCMath2!`fmin`); } /// T fmax(T)(in T x, in T y) if (isFloatingPoint!T) { version (Windows) // https://issues.dlang.org/show_bug.cgi?id=19798 { version (CRuntime_Microsoft) mixin(mixinCMath2!`fmax`); else return std.math.fmax(x, y); } else mixin(mixinCMath2!`fmax`); } version (mir_test) @nogc nothrow pure @safe unittest { // Check the aliases are correct. static assert(is(typeof(sqrt(1.0f)) == float)); static assert(is(typeof(sin(1.0f)) == float)); static assert(is(typeof(cos(1.0f)) == float)); static assert(is(typeof(exp(1.0f)) == float)); static assert(is(typeof(fabs(1.0f)) == float)); static assert(is(typeof(floor(1.0f)) == float)); static assert(is(typeof(exp2(1.0f)) == float)); static assert(is(typeof(ceil(1.0f)) == float)); static assert(is(typeof(rint(1.0f)) == float)); auto x = sqrt!float(2.0f); // Explicit template instantiation still works. auto fp = &sqrt!float; // Can still take function address. // Test for DMD linker problem with fmin on Windows. static assert(is(typeof(fmin!float(1.0f, 1.0f)))); static assert(is(typeof(fmax!float(1.0f, 1.0f)))); } } else // DMD version prior to 2.082 { static import std.math; static import core.stdc.math; // Calls either std.math or cmath function for either float (suffix "f") // or double (no suffix). std.math will always be used during CTFE or for // arguments with greater than double precision or if the cmath function // is impure. private enum mixinCMath(string fun) = `pragma(inline, true); static if (!is(typeof(std.math.`~fun~`(0.5f)) == float) && is(typeof(() pure => core.stdc.math.`~fun~`f(0.5f)))) if (!__ctfe) { static if (T.mant_dig == float.mant_dig) return core.stdc.math.`~fun~`f(x); else static if (T.mant_dig == double.mant_dig) return core.stdc.math.`~fun~`(x); } return std.math.`~fun~`(x);`; // As above but for two-argument function (both arguments must be floating point). private enum mixinCMath2(string fun) = `pragma(inline, true); static if (!is(typeof(std.math.`~fun~`(0.5f, 0.5f)) == float) && is(typeof(() pure => core.stdc.math.`~fun~`f(0.5f, 0.5f)))) if (!__ctfe) { static if (T.mant_dig == float.mant_dig) return core.stdc.math.`~fun~`f(x, y); else static if (T.mant_dig == double.mant_dig) return core.stdc.math.`~fun~`(x, y); } return std.math.`~fun~`(x, y);`; // Some std.math functions have appropriate return types (float, // double, real) without need for a wrapper. alias sqrt = std.math.sqrt; /// T sqrt(T)(in T x) if (isFloatingPoint!T) { return std.math.sqrt(x); } /// T sin(T)(in T x) if (isFloatingPoint!T) { mixin(mixinCMath!`sin`); } /// T cos(T)(in T x) if (isFloatingPoint!T) { mixin(mixinCMath!`cos`); } /// T pow(T)(in T x, in T power) if (isFloatingPoint!T) { alias y = power; mixin(mixinCMath2!`pow`); } /// T powi(T)(in T x, int power) if (isFloatingPoint!T) { alias y = power; mixin(mixinCMath2!`pow`); } /// T exp(T)(in T x) if (isFloatingPoint!T) { mixin(mixinCMath!`exp`); } /// T log(T)(in T x) if (isFloatingPoint!T) { mixin(mixinCMath!`log`); } /// T fabs(T)(in T x) if (isFloatingPoint!T) { mixin(mixinCMath!`fabs`); } /// T floor(T)(in T x) if (isFloatingPoint!T) { mixin(mixinCMath!`floor`); } /// T exp2(T)(in T x) if (isFloatingPoint!T) { mixin(mixinCMath!`exp2`); } /// T log10(T)(in T x) if (isFloatingPoint!T) { mixin(mixinCMath!`log10`); } /// T log2(T)(in T x) if (isFloatingPoint!T) { mixin(mixinCMath!`log2`); } /// T ceil(T)(in T x) if (isFloatingPoint!T) { mixin(mixinCMath!`ceil`); } /// T trunc(T)(in T x) if (isFloatingPoint!T) { mixin(mixinCMath!`trunc`); } /// T rint(T)(in T x) if (isFloatingPoint!T) { mixin(mixinCMath!`rint`); } /// T nearbyint(T)(in T x) if (isFloatingPoint!T) { mixin(mixinCMath!`nearbyint`); } /// T copysign(T)(in T mag, in T sgn) if (isFloatingPoint!T) { alias x = mag; alias y = sgn; mixin(mixinCMath2!`copysign`); } /// T round(T)(in T x) if (isFloatingPoint!T) { mixin(mixinCMath!`round`); } /// T fmuladd(T)(in T a, in T b, in T c) if (isFloatingPoint!T) { return a * b + c; } version(mir_test) unittest { assert(fmuladd!double(2, 3, 4) == 2 * 3 + 4); } /// T fmin(T)(in T x, in T y) if (isFloatingPoint!T) { version (Windows) // https://issues.dlang.org/show_bug.cgi?id=19798 { version (CRuntime_Microsoft) mixin(mixinCMath2!`fmin`); else return std.math.fmin(x, y); } else mixin(mixinCMath2!`fmin`); } /// T fmax(T)(in T x, in T y) if (isFloatingPoint!T) { version (Windows) // https://issues.dlang.org/show_bug.cgi?id=19798 { version (CRuntime_Microsoft) mixin(mixinCMath2!`fmax`); else return std.math.fmax(x, y); } else mixin(mixinCMath2!`fmax`); } version (mir_test) @nogc nothrow pure @safe unittest { // Check the aliases are correct. static assert(is(typeof(sqrt(1.0f)) == float)); auto x = sqrt!float(2.0f); // Explicit template instantiation still works. auto fp = &sqrt!float; // Can still take function address. // Test for DMD linker problem with fmin on Windows. static assert(is(typeof(fmin!float(1.0f, 1.0f)))); static assert(is(typeof(fmax!float(1.0f, 1.0f)))); } } version (mir_test) @nogc nothrow pure @safe unittest { import mir.math: PI, feqrel; assert(feqrel(pow(2.0L, -0.5L), cos(PI / 4)) >= real.mant_dig - 1); } /// Overload for cdouble, cfloat and creal @optmath auto fabs(T)(in T x) if (isComplex!T) { return x.re * x.re + x.im * x.im; } /// unittest { assert(fabs(3 + 4i) == 25); } /++ Computes whether two values are approximately equal, admitting a maximum relative difference, and a maximum absolute difference. Params: lhs = First item to compare. rhs = Second item to compare. maxRelDiff = Maximum allowable difference relative to `rhs`. Defaults to `0.5 ^^ 20`. maxAbsDiff = Maximum absolute difference. Defaults to `0.5 ^^ 20`. Returns: `true` if the two items are equal or approximately equal under either criterium. +/ bool approxEqual(T)(const T lhs, const T rhs, const T maxRelDiff = T(0x1p-20f), const T maxAbsDiff = T(0x1p-20f)) { if (rhs == lhs) // infs return true; auto diff = fabs(lhs - rhs); if (diff <= maxAbsDiff) return true; diff /= fabs(rhs); return diff <= maxRelDiff; } /// @safe pure nothrow @nogc unittest { assert(approxEqual(1.0, 1.0000001)); assert(approxEqual(1.0f, 1.0000001f)); assert(approxEqual(1.0L, 1.0000001L)); assert(approxEqual(10000000.0, 10000001)); assert(approxEqual(10000000f, 10000001f)); assert(!approxEqual(100000.0L, 100001L)); } /// ditto bool approxEqual(T : cfloat)(const T lhs, const T rhs, float maxRelDiff = 0x1p-20f, float maxAbsDiff = 0x1p-20f) { return approxEqual(lhs.re, rhs.re, maxRelDiff, maxAbsDiff) && approxEqual(lhs.im, rhs.im, maxRelDiff, maxAbsDiff); } /// ditto bool approxEqual(T : cdouble)(const T lhs, const T rhs, double maxRelDiff = 0x1p-20f, double maxAbsDiff = 0x1p-20f) { return approxEqual(lhs.re, rhs.re, maxRelDiff, maxAbsDiff) && approxEqual(lhs.im, rhs.im, maxRelDiff, maxAbsDiff); } /// ditto bool approxEqual(T : creal)(const T lhs, const T rhs, real maxRelDiff = 0x1p-20f, real maxAbsDiff = 0x1p-20f) { return approxEqual(lhs.re, rhs.re, maxRelDiff, maxAbsDiff) && approxEqual(lhs.im, rhs.im, maxRelDiff, maxAbsDiff); } /// Complex types works as `approxEqual(l.re, r.re) && approxEqual(l.im, r.im)` @safe pure nothrow @nogc unittest { assert(approxEqual(1.0 + 1i, 1.0000001 + 1.0000001i)); assert(!approxEqual(100000.0L + 0i, 100001L + 0i)); } mir-core-1.0.2/source/mir/math/constant.d000066400000000000000000000030721353705753200202610ustar00rootroot00000000000000/// Math constants /// Authors: Phobos Team module mir.math.constant; enum real E = 0x1.5bf0a8b1457695355fb8ac404e7a8p+1L; /++ e = 2.718281... +/ enum real LOG2T = 0x1.a934f0979a3715fc9257edfe9b5fbp+1L; /++ $(SUB log, 2)10 = 3.321928... +/ enum real LOG2E = 0x1.71547652b82fe1777d0ffda0d23a8p+0L; /++ $(SUB log, 2)e = 1.442695... +/ enum real LOG2 = 0x1.34413509f79fef311f12b35816f92p-2L; /++ $(SUB log, 10)2 = 0.301029... +/ enum real LOG10E = 0x1.bcb7b1526e50e32a6ab7555f5a67cp-2L; /++ $(SUB log, 10)e = 0.434294... +/ enum real LN2 = 0x1.62e42fefa39ef35793c7673007e5fp-1L; /++ ln 2 = 0.693147... +/ enum real LN10 = 0x1.26bb1bbb5551582dd4adac5705a61p+1L; /++ ln 10 = 2.302585... +/ enum real PI = 0x1.921fb54442d18469898cc51701b84p+1L; /++ π = 3.141592... +/ enum real PI_2 = PI/2; /++ $(PI) / 2 = 1.570796... +/ enum real PI_4 = PI/4; /++ $(PI) / 4 = 0.785398... +/ enum real M_1_PI = 0x1.45f306dc9c882a53f84eafa3ea69cp-2L; /++ 1 / $(PI) = 0.318309... +/ enum real M_2_PI = 2*M_1_PI; /++ 2 / $(PI) = 0.636619... +/ enum real M_2_SQRTPI = 0x1.20dd750429b6d11ae3a914fed7fd8p+0L; /++ 2 / $(SQRT)$(PI) = 1.128379... +/ enum real SQRT2 = 0x1.6a09e667f3bcc908b2fb1366ea958p+0L; /++ $(SQRT)2 = 1.414213... +/ enum real SQRT1_2 = SQRT2 / 2; /++ $(SQRT)$(HALF) = 0.707106... +/ /++ Exponent of minus Euler–Mascheroni constant. +/ enum real ExpMEuler = 0x0.8fbbcf07f2e5f2c56894d7014c3086p0; mir-core-1.0.2/source/mir/math/ieee.d000066400000000000000000001100521353705753200173340ustar00rootroot00000000000000/** * Base floating point routines. * * Macros: * TABLE_SV = * * $0
Special Values
* SVH = $(TR $(TH $1) $(TH $2)) * SV = $(TR $(TD $1) $(TD $2)) * TH3 = $(TR $(TH $1) $(TH $2) $(TH $3)) * TD3 = $(TR $(TD $1) $(TD $2) $(TD $3)) * TABLE_DOMRG = * $(SVH Domain X, Range Y) $(SV $1, $2) *
* DOMAIN=$1 * RANGE=$1 * NAN = $(RED NAN) * SUP = $0 * GAMMA = Γ * THETA = θ * INTEGRAL = ∫ * INTEGRATE = $(BIG ∫$(SMALL $1)$2) * POWER = $1$2 * SUB = $1$2 * BIGSUM = $(BIG Σ $2$(SMALL $1)) * CHOOSE = $(BIG () $(SMALL $1)$(SMALL $2) $(BIG )) * PLUSMN = ± * INFIN = ∞ * PLUSMNINF = ±∞ * PI = π * LT = < * GT = > * SQRT = √ * HALF = ½ * * Copyright: Copyright The D Language Foundation 2000 - 2011. * License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). * Authors: $(HTTP digitalmars.com, Walter Bright), Don Clugston, Ilya Yaroshenko */ module mir.math.ieee; import mir.internal.utility: isFloatingPoint; /********************************* * Return 1 if sign bit of e is set, 0 if not. */ int signbit(T)(const T x) @nogc @trusted pure nothrow { mixin floatTraits!T; static if (realFormat == RealFormat.ieeeSingle) { return ((*cast(uint*)&x) & 0x8000_0000) != 0; } else static if (realFormat == RealFormat.ieeeDouble) { return ((*cast(ulong*)&x) & 0x8000_0000_0000_0000) != 0; } else static if (realFormat == RealFormat.ieeeQuadruple) { return ((cast(ulong*)&x)[MANTISSA_MSB] & 0x8000_0000_0000_0000) != 0; } else static if (realFormat == RealFormat.ieeeExtended) { version (LittleEndian) auto mp = cast(ubyte*)&x + 9; else auto mp = cast(ubyte*)&x; return (*mp & 0x80) != 0; } else static assert(0, "signbit is not implemented."); } /// @nogc @safe pure nothrow unittest { assert(!signbit(float.nan)); assert(signbit(-float.nan)); assert(!signbit(168.1234f)); assert(signbit(-168.1234f)); assert(!signbit(0.0f)); assert(signbit(-0.0f)); assert(signbit(-float.max)); assert(!signbit(float.max)); assert(!signbit(double.nan)); assert(signbit(-double.nan)); assert(!signbit(168.1234)); assert(signbit(-168.1234)); assert(!signbit(0.0)); assert(signbit(-0.0)); assert(signbit(-double.max)); assert(!signbit(double.max)); assert(!signbit(real.nan)); assert(signbit(-real.nan)); assert(!signbit(168.1234L)); assert(signbit(-168.1234L)); assert(!signbit(0.0L)); assert(signbit(-0.0L)); assert(signbit(-real.max)); assert(!signbit(real.max)); } /************************************** * To what precision is x equal to y? * * Returns: the number of mantissa bits which are equal in x and y. * eg, 0x1.F8p+60 and 0x1.F1p+60 are equal to 5 bits of precision. * * $(TABLE_SV * $(TR $(TH x) $(TH y) $(TH feqrel(x, y))) * $(TR $(TD x) $(TD x) $(TD real.mant_dig)) * $(TR $(TD x) $(TD $(GT)= 2*x) $(TD 0)) * $(TR $(TD x) $(TD $(LT)= x/2) $(TD 0)) * $(TR $(TD $(NAN)) $(TD any) $(TD 0)) * $(TR $(TD any) $(TD $(NAN)) $(TD 0)) * ) */ int feqrel(T)(const T x, const T y) @trusted pure nothrow @nogc if (isFloatingPoint!T) { /* Public Domain. Author: Don Clugston, 18 Aug 2005. */ mixin floatTraits!T; static if (realFormat == RealFormat.ieeeSingle || realFormat == RealFormat.ieeeDouble || realFormat == RealFormat.ieeeExtended || realFormat == RealFormat.ieeeQuadruple) { import mir.math.common: fabs; if (x == y) return T.mant_dig; // ensure diff != 0, cope with IN auto diff = fabs(x - y); int a = ((cast(U*)& x)[idx] & exp_mask) >>> exp_shft; int b = ((cast(U*)& y)[idx] & exp_mask) >>> exp_shft; int d = ((cast(U*)&diff)[idx] & exp_mask) >>> exp_shft; // The difference in abs(exponent) between x or y and abs(x-y) // is equal to the number of significand bits of x which are // equal to y. If negative, x and y have different exponents. // If positive, x and y are equal to 'bitsdiff' bits. // AND with 0x7FFF to form the absolute value. // To avoid out-by-1 errors, we subtract 1 so it rounds down // if the exponents were different. This means 'bitsdiff' is // always 1 lower than we want, except that if bitsdiff == 0, // they could have 0 or 1 bits in common. int bitsdiff = ((a + b - 1) >> 1) - d; if (d == 0) { // Difference is subnormal // For subnormals, we need to add the number of zeros that // lie at the start of diff's significand. // We do this by multiplying by 2^^real.mant_dig diff *= norm_factor; return bitsdiff + T.mant_dig - int(((cast(U*)&diff)[idx] & exp_mask) >>> exp_shft); } if (bitsdiff > 0) return bitsdiff + 1; // add the 1 we subtracted before // Avoid out-by-1 errors when factor is almost 2. if (bitsdiff == 0 && (a ^ b) == 0) return 1; else return 0; } else { static assert(false, "Not implemented for this architecture"); } } /// @safe pure unittest { assert(feqrel(2.0, 2.0) == 53); assert(feqrel(2.0f, 2.0f) == 24); assert(feqrel(2.0, double.nan) == 0); // Test that numbers are within n digits of each // other by testing if feqrel > n * log2(10) // five digits assert(feqrel(2.0, 2.00001) > 16); // ten digits assert(feqrel(2.0, 2.00000000001) > 33); } @safe pure nothrow @nogc unittest { void testFeqrel(F)() { // Exact equality assert(feqrel(F.max, F.max) == F.mant_dig); assert(feqrel!(F)(0.0, 0.0) == F.mant_dig); assert(feqrel(F.infinity, F.infinity) == F.mant_dig); // a few bits away from exact equality F w=1; for (int i = 1; i < F.mant_dig - 1; ++i) { assert(feqrel!(F)(1.0 + w * F.epsilon, 1.0) == F.mant_dig-i); assert(feqrel!(F)(1.0 - w * F.epsilon, 1.0) == F.mant_dig-i); assert(feqrel!(F)(1.0, 1 + (w-1) * F.epsilon) == F.mant_dig - i + 1); w*=2; } assert(feqrel!(F)(1.5+F.epsilon, 1.5) == F.mant_dig-1); assert(feqrel!(F)(1.5-F.epsilon, 1.5) == F.mant_dig-1); assert(feqrel!(F)(1.5-F.epsilon, 1.5+F.epsilon) == F.mant_dig-2); // Numbers that are close assert(feqrel!(F)(0x1.Bp+84, 0x1.B8p+84) == 5); assert(feqrel!(F)(0x1.8p+10, 0x1.Cp+10) == 2); assert(feqrel!(F)(1.5 * (1 - F.epsilon), 1.0L) == 2); assert(feqrel!(F)(1.5, 1.0) == 1); assert(feqrel!(F)(2 * (1 - F.epsilon), 1.0L) == 1); // Factors of 2 assert(feqrel(F.max, F.infinity) == 0); assert(feqrel!(F)(2 * (1 - F.epsilon), 1.0L) == 1); assert(feqrel!(F)(1.0, 2.0) == 0); assert(feqrel!(F)(4.0, 1.0) == 0); // Extreme inequality assert(feqrel(F.nan, F.nan) == 0); assert(feqrel!(F)(0.0L, -F.nan) == 0); assert(feqrel(F.nan, F.infinity) == 0); assert(feqrel(F.infinity, -F.infinity) == 0); assert(feqrel(F.max, -F.max) == 0); assert(feqrel(F.min_normal / 8, F.min_normal / 17) == 3); const F Const = 2; immutable F Immutable = 2; auto Compiles = feqrel(Const, Immutable); } assert(feqrel(7.1824L, 7.1824L) == real.mant_dig); testFeqrel!(float)(); testFeqrel!(double)(); testFeqrel!(real)(); } /++ +/ enum RealFormat { /// ieeeHalf, /// ieeeSingle, /// ieeeDouble, /// x87 80-bit real ieeeExtended, /// x87 real rounded to precision of double. ieeeExtended53, /// IBM 128-bit extended ibmExtended, /// ieeeQuadruple, } /** * Calculate the next largest floating point value after x. * * Return the least number greater than x that is representable as a real; * thus, it gives the next point on the IEEE number line. * * $(TABLE_SV * $(SVH x, nextUp(x) ) * $(SV -$(INFIN), -real.max ) * $(SV $(PLUSMN)0.0, real.min_normal*real.epsilon ) * $(SV real.max, $(INFIN) ) * $(SV $(INFIN), $(INFIN) ) * $(SV $(NAN), $(NAN) ) * ) */ T nextUp(T)(const T x) @trusted pure nothrow @nogc if (isFloatingPoint!T) { mixin floatTraits!T; static if (realFormat == RealFormat.ieeeSingle) { uint s = *cast(uint*)&x; if ((s & 0x7F80_0000) == 0x7F80_0000) { // First, deal with NANs and infinity if (x == -x.infinity) return -x.max; return x; // +INF and NAN are unchanged. } if (s > 0x8000_0000) // Negative number { --s; } else if (s == 0x8000_0000) // it was negative zero { s = 0x0000_0001; // change to smallest subnormal } else { // Positive number ++s; } R: return *cast(T*)&s; } else static if (realFormat == RealFormat.ieeeDouble) { ulong s = *cast(ulong*)&x; if ((s & 0x7FF0_0000_0000_0000) == 0x7FF0_0000_0000_0000) { // First, deal with NANs and infinity if (x == -x.infinity) return -x.max; return x; // +INF and NAN are unchanged. } if (s > 0x8000_0000_0000_0000) // Negative number { --s; } else if (s == 0x8000_0000_0000_0000) // it was negative zero { s = 0x0000_0000_0000_0001; // change to smallest subnormal } else { // Positive number ++s; } R: return *cast(T*)&s; } else static if (realFormat == RealFormat.ieeeQuadruple) { auto e = exp_mask & (cast(U *)&x)[idx]; if (e == exp_mask) { // NaN or Infinity if (x == -real.infinity) return -real.max; return x; // +Inf and NaN are unchanged. } auto ps = cast(ulong *)&x; if (ps[MANTISSA_MSB] & 0x8000_0000_0000_0000) { // Negative number if (ps[MANTISSA_LSB] == 0 && ps[MANTISSA_MSB] == 0x8000_0000_0000_0000) { // it was negative zero, change to smallest subnormal ps[MANTISSA_LSB] = 1; ps[MANTISSA_MSB] = 0; return x; } if (ps[MANTISSA_LSB] == 0) --ps[MANTISSA_MSB]; --ps[MANTISSA_LSB]; } else { // Positive number ++ps[MANTISSA_LSB]; if (ps[MANTISSA_LSB] == 0) ++ps[MANTISSA_MSB]; } return x; } else static if (realFormat == RealFormat.ieeeExtended) { // For 80-bit reals, the "implied bit" is a nuisance... auto pe = cast(U*)&x + idx; version (LittleEndian) auto ps = cast(ulong*)&x; else auto ps = cast(ulong*)((cast(ushort*)&x) + 1); if ((*pe & exp_mask) == exp_mask) { // First, deal with NANs and infinity if (x == -real.infinity) return -real.max; return x; // +Inf and NaN are unchanged. } if (*pe & 0x8000) { // Negative number -- need to decrease the significand --*ps; // Need to mask with 0x7FF.. so subnormals are treated correctly. if ((*ps & 0x7FFF_FFFF_FFFF_FFFF) == 0x7FFF_FFFF_FFFF_FFFF) { if (*pe == 0x8000) // it was negative zero { *ps = 1; *pe = 0; // smallest subnormal. return x; } --*pe; if (*pe == 0x8000) return x; // it's become a subnormal, implied bit stays low. *ps = 0xFFFF_FFFF_FFFF_FFFF; // set the implied bit return x; } return x; } else { // Positive number -- need to increase the significand. // Works automatically for positive zero. ++*ps; if ((*ps & 0x7FFF_FFFF_FFFF_FFFF) == 0) { // change in exponent ++*pe; *ps = 0x8000_0000_0000_0000; // set the high bit } } return x; } else // static if (realFormat == RealFormat.ibmExtended) { assert(0, "nextUp not implemented"); } } /// @safe @nogc pure nothrow unittest { assert(nextUp(1.0 - 1.0e-6).feqrel(0.999999) > 16); assert(nextUp(1.0 - real.epsilon).feqrel(1.0) > 16); } /** * Calculate the next smallest floating point value before x. * * Return the greatest number less than x that is representable as a real; * thus, it gives the previous point on the IEEE number line. * * $(TABLE_SV * $(SVH x, nextDown(x) ) * $(SV $(INFIN), real.max ) * $(SV $(PLUSMN)0.0, -real.min_normal*real.epsilon ) * $(SV -real.max, -$(INFIN) ) * $(SV -$(INFIN), -$(INFIN) ) * $(SV $(NAN), $(NAN) ) * ) */ T nextDown(T)(const T x) @safe pure nothrow @nogc { return -nextUp(-x); } /// @safe pure nothrow @nogc unittest { assert( nextDown(1.0 + real.epsilon) == 1.0); } @safe pure nothrow @nogc unittest { import std.math: NaN, isIdentical; static if (floatTraits!(real).realFormat == RealFormat.ieeeExtended) { // Tests for 80-bit reals assert(isIdentical(nextUp(NaN(0xABC)), NaN(0xABC))); // negative numbers assert( nextUp(-real.infinity) == -real.max ); assert( nextUp(-1.0L-real.epsilon) == -1.0 ); assert( nextUp(-2.0L) == -2.0 + real.epsilon); // subnormals and zero assert( nextUp(-real.min_normal) == -real.min_normal*(1-real.epsilon) ); assert( nextUp(-real.min_normal*(1-real.epsilon)) == -real.min_normal*(1-2*real.epsilon) ); assert( isIdentical(-0.0L, nextUp(-real.min_normal*real.epsilon)) ); assert( nextUp(-0.0L) == real.min_normal*real.epsilon ); assert( nextUp(0.0L) == real.min_normal*real.epsilon ); assert( nextUp(real.min_normal*(1-real.epsilon)) == real.min_normal ); assert( nextUp(real.min_normal) == real.min_normal*(1+real.epsilon) ); // positive numbers assert( nextUp(1.0L) == 1.0 + real.epsilon ); assert( nextUp(2.0L-real.epsilon) == 2.0 ); assert( nextUp(real.max) == real.infinity ); assert( nextUp(real.infinity)==real.infinity ); } double n = NaN(0xABC); assert(isIdentical(nextUp(n), n)); // negative numbers assert( nextUp(-double.infinity) == -double.max ); assert( nextUp(-1-double.epsilon) == -1.0 ); assert( nextUp(-2.0) == -2.0 + double.epsilon); // subnormals and zero assert( nextUp(-double.min_normal) == -double.min_normal*(1-double.epsilon) ); assert( nextUp(-double.min_normal*(1-double.epsilon)) == -double.min_normal*(1-2*double.epsilon) ); assert( isIdentical(-0.0, nextUp(-double.min_normal*double.epsilon)) ); assert( nextUp(0.0) == double.min_normal*double.epsilon ); assert( nextUp(-0.0) == double.min_normal*double.epsilon ); assert( nextUp(double.min_normal*(1-double.epsilon)) == double.min_normal ); assert( nextUp(double.min_normal) == double.min_normal*(1+double.epsilon) ); // positive numbers assert( nextUp(1.0) == 1.0 + double.epsilon ); assert( nextUp(2.0-double.epsilon) == 2.0 ); assert( nextUp(double.max) == double.infinity ); float fn = NaN(0xABC); assert(isIdentical(nextUp(fn), fn)); float f = -float.min_normal*(1-float.epsilon); float f1 = -float.min_normal; assert( nextUp(f1) == f); f = 1.0f+float.epsilon; f1 = 1.0f; assert( nextUp(f1) == f ); f1 = -0.0f; assert( nextUp(f1) == float.min_normal*float.epsilon); assert( nextUp(float.infinity)==float.infinity ); assert(nextDown(1.0L+real.epsilon)==1.0); assert(nextDown(1.0+double.epsilon)==1.0); f = 1.0f+float.epsilon; assert(nextDown(f)==1.0); } /++ Return the value that lies halfway between x and y on the IEEE number line. Formally, the result is the arithmetic mean of the binary significands of x and y, multiplied by the geometric mean of the binary exponents of x and y. x and y must not be NaN. Note: this function is useful for ensuring O(log n) behaviour in algorithms involving a 'binary chop'. Params: xx = x value yy = y value Special cases: If x and y not null and have opposite sign bits, then `copysign(T(0), y)` is returned. If x and y are within a factor of 2 and have the same sign, (ie, feqrel(x, y) > 0), the return value is the arithmetic mean (x + y) / 2. If x and y are even powers of 2 and have the same sign, the return value is the geometric mean, ieeeMean(x, y) = sgn(x) * sqrt(fabs(x * y)). +/ T ieeeMean(T)(const T xx, const T yy) @trusted pure nothrow @nogc in { assert(xx == xx && yy == yy); } do { import mir.math.common: copysign; T x = xx; T y = yy; if (x == 0) { x = copysign(T(0), y); } else if (y == 0) { y = copysign(T(0), x); } else if (signbit(x) != signbit(y)) { return copysign(T(0), y); } // The implementation is simple: cast x and y to integers, // average them (avoiding overflow), and cast the result back to a floating-point number. mixin floatTraits!(T); T u = 0; static if (realFormat == RealFormat.ieeeExtended) { // There's slight additional complexity because they are actually // 79-bit reals... ushort *ue = cast(ushort *)&u + idx; int ye = (cast(ushort *)&y)[idx]; int xe = (cast(ushort *)&x)[idx]; version (LittleEndian) { ulong *ul = cast(ulong *)&u; ulong xl = *cast(ulong *)&x; ulong yl = *cast(ulong *)&y; } else { ulong *ul = cast(ulong *)(cast(short *)&u + 1); ulong xl = *cast(ulong *)(cast(short *)&x + 1); ulong yl = *cast(ulong *)(cast(short *)&y + 1); } // Ignore the useless implicit bit. (Bonus: this prevents overflows) ulong m = (xl & 0x7FFF_FFFF_FFFF_FFFFL) + (yl & 0x7FFF_FFFF_FFFF_FFFFL); int e = ((xe & exp_mask) + (ye & exp_mask)); if (m & 0x8000_0000_0000_0000L) { ++e; m &= 0x7FFF_FFFF_FFFF_FFFFL; } // Now do a multi-byte right shift const uint c = e & 1; // carry e >>= 1; m >>>= 1; if (c) m |= 0x4000_0000_0000_0000L; // shift carry into significand if (e) *ul = m | 0x8000_0000_0000_0000L; // set implicit bit... else *ul = m; // ... unless exponent is 0 (subnormal or zero). *ue = cast(ushort) (e | (xe & 0x8000)); // restore sign bit } else static if (realFormat == RealFormat.ieeeQuadruple) { // This would be trivial if 'ucent' were implemented... ulong *ul = cast(ulong *)&u; ulong *xl = cast(ulong *)&x; ulong *yl = cast(ulong *)&y; // Multi-byte add, then multi-byte right shift. import core.checkedint: addu; bool carry; ulong ml = addu(xl[MANTISSA_LSB], yl[MANTISSA_LSB], carry); ulong mh = carry + (xl[MANTISSA_MSB] & 0x7FFF_FFFF_FFFF_FFFFL) + (yl[MANTISSA_MSB] & 0x7FFF_FFFF_FFFF_FFFFL); ul[MANTISSA_MSB] = (mh >>> 1) | (xl[MANTISSA_MSB] & 0x8000_0000_0000_0000); ul[MANTISSA_LSB] = (ml >>> 1) | (mh & 1) << 63; } else static if (realFormat == RealFormat.ieeeDouble) { ulong *ul = cast(ulong *)&u; ulong *xl = cast(ulong *)&x; ulong *yl = cast(ulong *)&y; ulong m = (((*xl) & 0x7FFF_FFFF_FFFF_FFFFL) + ((*yl) & 0x7FFF_FFFF_FFFF_FFFFL)) >>> 1; m |= ((*xl) & 0x8000_0000_0000_0000L); *ul = m; } else static if (realFormat == RealFormat.ieeeSingle) { uint *ul = cast(uint *)&u; uint *xl = cast(uint *)&x; uint *yl = cast(uint *)&y; uint m = (((*xl) & 0x7FFF_FFFF) + ((*yl) & 0x7FFF_FFFF)) >>> 1; m |= ((*xl) & 0x8000_0000); *ul = m; } else { assert(0, "Not implemented"); } return u; } @safe pure nothrow @nogc unittest { assert(ieeeMean(-0.0,-1e-20)<0); assert(ieeeMean(0.0,1e-20)>0); assert(ieeeMean(1.0L,4.0L)==2L); assert(ieeeMean(2.0*1.013,8.0*1.013)==4*1.013); assert(ieeeMean(-1.0L,-4.0L)==-2L); assert(ieeeMean(-1.0,-4.0)==-2); assert(ieeeMean(-1.0f,-4.0f)==-2f); assert(ieeeMean(-1.0,-2.0)==-1.5); assert(ieeeMean(-1*(1+8*real.epsilon),-2*(1+8*real.epsilon)) ==-1.5*(1+5*real.epsilon)); assert(ieeeMean(0x1p60,0x1p-10)==0x1p25); static if (floatTraits!(real).realFormat == RealFormat.ieeeExtended) { assert(ieeeMean(1.0L,real.infinity)==0x1p8192L); assert(ieeeMean(0.0L,real.infinity)==1.5); } assert(ieeeMean(0.5*real.min_normal*(1-4*real.epsilon),0.5*real.min_normal) == 0.5*real.min_normal*(1-2*real.epsilon)); } /********************************************************************* * Separate floating point value into significand and exponent. * * Returns: * Calculate and return $(I x) and $(I exp) such that * value =$(I x)*2$(SUPERSCRIPT exp) and * .5 $(LT)= |$(I x)| $(LT) 1.0 * * $(I x) has same sign as value. * * $(TABLE_SV * $(TR $(TH value) $(TH returns) $(TH exp)) * $(TR $(TD $(PLUSMN)0.0) $(TD $(PLUSMN)0.0) $(TD 0)) * $(TR $(TD +$(INFIN)) $(TD +$(INFIN)) $(TD int.max)) * $(TR $(TD -$(INFIN)) $(TD -$(INFIN)) $(TD int.min)) * $(TR $(TD $(PLUSMN)$(NAN)) $(TD $(PLUSMN)$(NAN)) $(TD int.min)) * ) */ T frexp(T)(const T value, ref int exp) @trusted pure nothrow @nogc if (isFloatingPoint!T) { import mir.utility: _expect; with(floatTraits!T) static if ( realFormat == RealFormat.ieeeExtended || realFormat == RealFormat.ieeeQuadruple || realFormat == RealFormat.ieeeDouble || realFormat == RealFormat.ieeeSingle) { T vf = value; S u = (cast(U*)&vf)[idx]; int e = (u & exp_mask) >>> exp_shft; if (_expect(e, true)) // If exponent is non-zero { if (_expect(e == exp_msh, false)) goto R; exp = e + (T.min_exp - 1); } else { static if (realFormat == RealFormat.ieeeExtended) { version (LittleEndian) auto mp = cast(ulong*)&vf; else auto mp = cast(ulong*)((cast(ushort*)&vf) + 1); auto m = u & man_mask | *mp; } else { auto m = u & man_mask; static if (T.sizeof > U.sizeof) m |= (cast(U*)&vf)[MANTISSA_LSB]; } if (!m) { exp = 0; goto R; } vf *= norm_factor; u = (cast(U*)&vf)[idx]; e = (u & exp_mask) >>> exp_shft; exp = e + (T.min_exp - T.mant_dig); } u &= ~exp_mask; u ^= exp_nrm; (cast(U*)&vf)[idx] = cast(U)u; R: return vf; } else // static if (realFormat == RealFormat.ibmExtended) { static assert(0, "frexp not implemented"); } } /// @safe unittest { import mir.math.common: pow, approxEqual; alias isNaN = x => x != x; int exp; real mantissa = frexp(123.456L, exp); assert(approxEqual(mantissa * pow(2.0L, cast(real) exp), 123.456L)); exp = 1234; // random number assert(isNaN(frexp(-real.nan, exp)) && exp == 1234); assert(isNaN(frexp(real.nan, exp)) && exp == 1234); assert(frexp(-real.infinity, exp) == -real.infinity && exp == 1234); assert(frexp(real.infinity, exp) == real.infinity && exp == 1234); assert(frexp(-0.0, exp) == -0.0 && exp == 0); assert(frexp(0.0, exp) == 0.0 && exp == 0); } @safe @nogc nothrow unittest { import mir.math.common: pow; int exp; real mantissa = frexp(123.456L, exp); assert(mantissa * pow(2.0L, cast(real) exp) == 123.456L); } @safe unittest { import std.meta : AliasSeq; import std.typecons : tuple, Tuple; static foreach (T; AliasSeq!(float, double, real)) {{ enum randomNumber = 12345; Tuple!(T, T, int)[] vals = // x,frexp,exp [ tuple(T(0.0), T( 0.0 ), 0), tuple(T(-0.0), T( -0.0), 0), tuple(T(1.0), T( .5 ), 1), tuple(T(-1.0), T( -.5 ), 1), tuple(T(2.0), T( .5 ), 2), tuple(T(float.min_normal/2.0f), T(.5), -126), tuple(T.infinity, T.infinity, randomNumber), tuple(-T.infinity, -T.infinity, randomNumber), tuple(T.nan, T.nan, randomNumber), tuple(-T.nan, -T.nan, randomNumber), // Phobos issue #16026: tuple(3 * (T.min_normal * T.epsilon), T( .75), (T.min_exp - T.mant_dig) + 2) ]; foreach (i, elem; vals) { T x = elem[0]; T e = elem[1]; int exp = elem[2]; int eptr = randomNumber; T v = frexp(x, eptr); assert(e == v || (e != e && v != v)); assert(exp == eptr); } static if (floatTraits!(T).realFormat == RealFormat.ieeeExtended) { static T[3][] extendedvals = [ // x,frexp,exp [0x1.a5f1c2eb3fe4efp+73L, 0x1.A5F1C2EB3FE4EFp-1L, 74], // normal [0x1.fa01712e8f0471ap-1064L, 0x1.fa01712e8f0471ap-1L, -1063], [T.min_normal, .5, -16381], [T.min_normal/2.0L, .5, -16382] // subnormal ]; foreach (elem; extendedvals) { T x = elem[0]; T e = elem[1]; int exp = cast(int) elem[2]; int eptr; T v = frexp(x, eptr); assert(e == v); assert(exp == eptr); } } }} } @safe unittest { import std.meta : AliasSeq; void foo() { static foreach (T; AliasSeq!(real, double, float)) {{ int exp; const T a = 1; immutable T b = 2; auto c = frexp(a, exp); auto d = frexp(b, exp); }} } } /******************************************* * Returns: n * 2$(SUPERSCRIPT exp) * See_Also: $(LERF frexp) */ T ldexp(T)(const T n, int exp) @nogc @trusted pure nothrow if (isFloatingPoint!T) { import mir.math.common: copysign; import mir.checkedint: adds, subs; import mir.utility: _expect; enum norm_factor = 1 / T.epsilon; T vf = n; mixin floatTraits!T; version(LDC) { static if (realFormat == RealFormat.ieeeExtended) { if (!__ctfe) { import core.math: ldexp; return ldexp(n, exp); } } } static if (realFormat == RealFormat.ieeeExtended || realFormat == RealFormat.ieeeQuadruple || realFormat == RealFormat.ieeeDouble || realFormat == RealFormat.ieeeSingle) { auto u = (cast(U*)&vf)[idx]; int e = (u & exp_mask) >> exp_shft; if (_expect(e != exp_msh, true)) { if (_expect(e == 0, false)) // subnormals input { bool overflow; vf *= norm_factor; u = (cast(U*)&vf)[idx]; e = int((u & exp_mask) >> exp_shft) - (T.mant_dig - 1); } bool overflow; exp = adds(exp, e, overflow); if (_expect(overflow || exp >= exp_msh, false)) // infs { static if (realFormat == RealFormat.ieeeExtended) { return vf * T.infinity; } else { u &= sig_mask; u ^= exp_mask; static if (realFormat == RealFormat.ieeeExtended) { version (LittleEndian) auto mp = cast(ulong*)&vf; else auto mp = cast(ulong*)((cast(ushort*)&vf) + 1); *mp = 0; } else static if (T.sizeof > U.sizeof) { (cast(U*)&vf)[MANTISSA_LSB] = 0; } } } else if (_expect(exp > 0, true)) // normal { u = cast(U)((u & ~exp_mask) ^ (cast(typeof(U.init + 0))exp << exp_shft)); } else // subnornmal output { exp = 1 - exp; static if (realFormat != RealFormat.ieeeExtended) { auto m = u & man_mask; if (exp > T.mant_dig) { exp = T.mant_dig; static if (T.sizeof > U.sizeof) (cast(U*)&vf)[MANTISSA_LSB] = 0; } } u &= sig_mask; static if (realFormat == RealFormat.ieeeExtended) { version (LittleEndian) auto mp = cast(ulong*)&vf; else auto mp = cast(ulong*)((cast(ushort*)&vf) + 1); if (exp >= ulong.sizeof * 8) *mp = 0; else *mp >>>= exp; } else { m ^= intPartMask; static if (T.sizeof > U.sizeof) { int exp2 = exp - U.sizeof * 8; if (exp2 < 0) { (cast(U*)&vf)[MANTISSA_LSB] = ((cast(U*)&vf)[MANTISSA_LSB] >> exp) ^ (m << (U.sizeof * 8 - exp)); m >>>= exp; u ^= cast(U) m; } else { exp = exp2; (cast(U*)&vf)[MANTISSA_LSB] = (exp < U.sizeof * 8) ? m >> exp : 0; } } else { m >>>= exp; u ^= cast(U) m; } } } (cast(U*)&vf)[idx] = u; } return vf; } else { static assert(0, "ldexp not implemented"); } } /// @nogc @safe pure nothrow unittest { import std.meta : AliasSeq; static foreach (T; AliasSeq!(float, double, real)) {{ T r = ldexp(cast(T) 3.0, cast(int) 3); assert(r == 24); T n = 3.0; int exp = 3; r = ldexp(n, exp); assert(r == 24); }} } @safe pure nothrow @nogc unittest { import mir.math.common; { assert(ldexp(1.0, -1024) == 0x1p-1024); assert(ldexp(1.0, -1022) == 0x1p-1022); int x; double n = frexp(0x1p-1024L, x); assert(n == 0.5); assert(x==-1023); assert(ldexp(n, x)==0x1p-1024); } static if (floatTraits!(real).realFormat == RealFormat.ieeeExtended || floatTraits!(real).realFormat == RealFormat.ieeeQuadruple) { assert(ldexp(1.0L, -16384) == 0x1p-16384L); assert(ldexp(1.0L, -16382) == 0x1p-16382L); int x; real n = frexp(0x1p-16384L, x); assert(n == 0.5L); assert(x==-16383); assert(ldexp(n, x)==0x1p-16384L); } } /* workaround Issue 14718, float parsing depends on platform strtold @safe pure nothrow @nogc unittest { assert(ldexp(1.0, -1024) == 0x1p-1024); assert(ldexp(1.0, -1022) == 0x1p-1022); int x; double n = frexp(0x1p-1024, x); assert(n == 0.5); assert(x==-1023); assert(ldexp(n, x)==0x1p-1024); } @safe pure nothrow @nogc unittest { assert(ldexp(1.0f, -128) == 0x1p-128f); assert(ldexp(1.0f, -126) == 0x1p-126f); int x; float n = frexp(0x1p-128f, x); assert(n == 0.5f); assert(x==-127); assert(ldexp(n, x)==0x1p-128f); } */ @safe @nogc nothrow unittest { import std.meta: AliasSeq; static F[3][] vals(F) = // value,exp,ldexp [ [ 0, 0, 0], [ 1, 0, 1], [ -1, 0, -1], [ 1, 1, 2], [ 123, 10, 125952], [ F.max, int.max, F.infinity], [ F.max, -int.max, 0], [ F.min_normal, -int.max, 0], ]; static foreach(F; AliasSeq!(double, real)) {{ int i; for (i = 0; i < vals!F.length; i++) { F x = vals!F[i][0]; int exp = cast(int) vals!F[i][1]; F z = vals!F[i][2]; F l = ldexp(x, exp); assert(feqrel(z, l) >= 23); } }} } package(mir): // Constants used for extracting the components of the representation. // They supplement the built-in floating point properties. template floatTraits(T) { // EXPMASK is a ushort mask to select the exponent portion (without sign) // EXPSHIFT is the number of bits the exponent is left-shifted by in its ushort // EXPBIAS is the exponent bias - 1 (exp == EXPBIAS yields ×2^-1). // EXPPOS_SHORT is the index of the exponent when represented as a ushort array. // SIGNPOS_BYTE is the index of the sign when represented as a ubyte array. // RECIP_EPSILON is the value such that (smallest_subnormal) * RECIP_EPSILON == T.min_normal enum norm_factor = 1 / T.epsilon; static if (T.mant_dig == 24) { enum realFormat = RealFormat.ieeeSingle; } else static if (T.mant_dig == 53) { static if (T.sizeof == 8) { enum realFormat = RealFormat.ieeeDouble; } else static assert(false, "No traits support for " ~ T.stringof); } else static if (T.mant_dig == 64) { enum realFormat = RealFormat.ieeeExtended; } else static if (T.mant_dig == 113) { enum realFormat = RealFormat.ieeeQuadruple; } else static assert(false, "No traits support for " ~ T.stringof); static if (realFormat == RealFormat.ieeeExtended) { alias S = int; alias U = ushort; enum sig_mask = U(1) << (U.sizeof * 8 - 1); enum exp_shft = 0; enum man_mask = 0; version (LittleEndian) enum idx = 4; else enum idx = 0; } else { static if (realFormat == RealFormat.ieeeQuadruple || realFormat == RealFormat.ieeeDouble && double.sizeof == size_t.sizeof) { alias S = long; alias U = ulong; } else { alias S = int; alias U = uint; } static if (realFormat == RealFormat.ieeeQuadruple) alias M = ulong; else alias M = U; enum sig_mask = U(1) << (U.sizeof * 8 - 1); enum uint exp_shft = T.mant_dig - 1 - (T.sizeof > U.sizeof ? U.sizeof * 8 : 0); enum man_mask = (U(1) << exp_shft) - 1; enum idx = T.sizeof > U.sizeof ? MANTISSA_MSB : 0; } enum exp_mask = (U.max >> (exp_shft + 1)) << exp_shft; enum int exp_msh = exp_mask >> exp_shft; enum intPartMask = man_mask + 1; enum exp_nrm = S(exp_msh - T.max_exp - 1) << exp_shft; } // These apply to all floating-point types version (LittleEndian) { enum MANTISSA_LSB = 0; enum MANTISSA_MSB = 1; } else { enum MANTISSA_LSB = 1; enum MANTISSA_MSB = 0; } mir-core-1.0.2/source/mir/math/package.d000066400000000000000000000006541353705753200200260ustar00rootroot00000000000000/++ $(H1 Math Functionality) $(BOOKTABLE $(H2 ,Math modules), $(TR $(TH Module) $(TH Math kind)) $(T2M common, Common math functions) $(T2M constant, Constants) ) Macros: SUBREF = $(REF_ALTTEXT $(TT $2), $2, mir, math, $1)$(NBSP) T2M=$(TR $(TDNW $(MREF mir,math,$1)) $(TD $+)) T2=$(TR $(TDNW $(LREF $1)) $(TD $+)) +/ module mir.math; public import mir.math.common; public import mir.math.constant; public import mir.math.ieee; mir-core-1.0.2/source/mir/primitives.d000066400000000000000000000170621353705753200176760ustar00rootroot00000000000000/++ Templates used to check primitives and range primitives for arrays with multi-dimensional like API support. Note: UTF strings behaves like common arrays in Mir. `std.uni.byCodePoint` can be used to create a range of characters. License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0). Copyright: Copyright © 2017-, Ilya Yaroshenko Authors: Ilya Yaroshenko +/ module mir.primitives; import mir.internal.utility; import mir.math.common: optmath; import std.traits; @optmath: /++ Returns: `true` if `R` has a `length` member that returns an integral type implicitly convertible to `size_t`. `R` does not have to be a range. +/ enum bool hasLength(R) = is(typeof( (const R r, inout int = 0) { size_t l = r.length; })); /// @safe version(mir_test) unittest { static assert(hasLength!(char[])); static assert(hasLength!(int[])); static assert(hasLength!(inout(int)[])); struct B { size_t length() const { return 0; } } struct C { @property size_t length() const { return 0; } } static assert(hasLength!(B)); static assert(hasLength!(C)); } /++ Returns: `true` if `R` has a `shape` member that returns an static array type of size_t[N]. +/ enum bool hasShape(R) = is(typeof( (const R r, inout int = 0) { auto l = r.shape; alias F = typeof(l); import std.traits; static assert(isStaticArray!F); static assert(is(ForeachType!F == size_t)); })); /// @safe version(mir_test) unittest { static assert(hasShape!(char[])); static assert(hasShape!(int[])); static assert(hasShape!(inout(int)[])); struct B { size_t length() const { return 0; } } struct C { @property size_t length() const { return 0; } } static assert(hasShape!(B)); static assert(hasShape!(C)); } /// auto shape(Range)(scope const auto ref Range range) @property if (hasLength!Range || hasShape!Range) { static if (__traits(hasMember, Range, "shape")) { return range.shape; } else { size_t[1] ret; ret[0] = range.length; return ret; } } /// version(mir_test) unittest { static assert([2, 2, 2].shape == [3]); } /// template DimensionCount(T) { import mir.ndslice.slice: Slice, SliceKind; /// Extracts dimension count from a $(LREF Slice). Alias for $(LREF isSlice). static if(is(T : Slice!(Iterator, N, kind), Iterator, size_t N, SliceKind kind)) enum size_t DimensionCount = N; else static if (hasShape!T) enum size_t DimensionCount = typeof(T.init.shape).length; else enum size_t DimensionCount = 1; } package(mir) bool anyEmptyShape(size_t N)(scope const auto ref size_t[N] shape) @property { foreach (i; Iota!N) if (shape[i] == 0) return true; return false; } /// bool anyEmpty(Range)(scope const auto ref Range range) @property if (hasShape!Range || __traits(hasMember, Range, "anyEmpty")) { static if (__traits(hasMember, Range, "anyEmpty")) { return range.anyEmpty; } else static if (__traits(hasMember, Range, "shape")) { return anyEmptyShape(range.shape); } else { return range.empty; } } /// size_t elementCount(Range)(scope const auto ref Range range) @property if (hasShape!Range || __traits(hasMember, Range, "elementCount")) { static if (__traits(hasMember, Range, "elementCount")) { return range; } else { auto sh = range.shape; size_t ret = sh[0]; foreach(i; Iota!(1, sh.length)) { ret *= sh[i]; } return ret; } } deprecated("use elementCount instead") alias elementsCount = elementCount; /++ Returns the element type of a struct with `.DeepElement` inner alias or a type of common array. Returns `ForeachType` if struct does not have `.DeepElement` member. +/ template DeepElementType(S) if (is(S == struct) || is(S == class) || is(S == interface)) { static if (__traits(hasMember, S, "DeepElement")) alias DeepElementType = S.DeepElement; else alias DeepElementType = ForeachType!S; } /// ditto alias DeepElementType(S : T[], T) = T; /+ ARRAY PRIMITIVES +/ pragma(inline, true): /// bool empty(size_t dim = 0, T)(scope const T[] ar) if (!dim) { return !ar.length; } /// version(mir_test) unittest { assert((int[]).init.empty); assert(![1].empty!0); // Slice-like API } /// ref inout(T) front(size_t dim = 0, T)(scope return inout(T)[] ar) if (!dim && !is(Unqual!T[] == void[])) { assert(ar.length, "Accessing front of an empty array."); return ar[0]; } /// version(mir_test) unittest { assert(*&[3, 4].front == 3); // access be ref assert([3, 4].front!0 == 3); // Slice-like API } /// ref inout(T) back(size_t dim = 0, T)(scope return inout(T)[] ar) if (!dim && !is(Unqual!T[] == void[])) { assert(ar.length, "Accessing back of an empty array."); return ar[$ - 1]; } /// version(mir_test) unittest { assert(*&[3, 4].back == 4); // access be ref assert([3, 4].back!0 == 4); // Slice-like API } /// void popFront(size_t dim = 0, T)(scope ref inout(T)[] ar) if (!dim && !is(Unqual!T[] == void[])) { assert(ar.length, "Evaluating popFront() on an empty array."); ar = ar[1 .. $]; } /// version(mir_test) unittest { auto ar = [3, 4]; ar.popFront; assert(ar == [4]); ar.popFront!0; // Slice-like API assert(ar == []); } /// void popBack(size_t dim = 0, T)(scope ref inout(T)[] ar) if (!dim && !is(Unqual!T[] == void[])) { assert(ar.length, "Evaluating popBack() on an empty array."); ar = ar[0 .. $ - 1]; } /// version(mir_test) unittest { auto ar = [3, 4]; ar.popBack; assert(ar == [3]); ar.popBack!0; // Slice-like API assert(ar == []); } /// size_t popFrontN(size_t dim = 0, T)(scope ref inout(T)[] ar, size_t n) if (!dim && !is(Unqual!T[] == void[])) { n = ar.length < n ? ar.length : n; ar = ar[n .. $]; return n; } /// version(mir_test) unittest { auto ar = [3, 4]; ar.popFrontN(1); assert(ar == [4]); ar.popFrontN!0(10); // Slice-like API assert(ar == []); } /// size_t popBackN(size_t dim = 0, T)(scope ref inout(T)[] ar, size_t n) if (!dim && !is(Unqual!T[] == void[])) { n = ar.length < n ? ar.length : n; ar = ar[0 .. $ - n]; return n; } /// version(mir_test) unittest { auto ar = [3, 4]; ar.popBackN(1); assert(ar == [3]); ar.popBackN!0(10); // Slice-like API assert(ar == []); } /// void popFrontExactly(size_t dim = 0, T)(scope ref inout(T)[] ar, size_t n) if (!dim && !is(Unqual!T[] == void[])) { assert(ar.length >= n, "Evaluating *.popFrontExactly(n) on an array with length less then n."); ar = ar[n .. $]; } /// version(mir_test) unittest { auto ar = [3, 4, 5]; ar.popFrontExactly(2); assert(ar == [5]); ar.popFrontExactly!0(1); // Slice-like API assert(ar == []); } /// void popBackExactly(size_t dim = 0, T)(scope ref inout(T)[] ar, size_t n) if (!dim && !is(Unqual!T[] == void[])) { assert(ar.length >= n, "Evaluating *.popBackExactly(n) on an array with length less then n."); ar = ar[0 .. $ - n]; } /// version(mir_test) unittest { auto ar = [3, 4, 5]; ar.popBackExactly(2); assert(ar == [3]); ar.popBackExactly!0(1); // Slice-like API assert(ar == []); } /// size_t length(size_t d : 0, T)(in T[] array) if (d == 0) { return array.length; } /// version(mir_test) unittest { assert([1, 2].length!0 == 2); assert([1, 2].elementCount == 2); } /// inout(T)[] save(T)(scope return inout(T)[] array) { return array; } /// version(mir_test) unittest { auto a = [1, 2]; assert(a is a.save); } mir-core-1.0.2/source/mir/qualifier.d000066400000000000000000000065351353705753200174670ustar00rootroot00000000000000/++ Copyright: Ilya Yaroshenko 2018-. License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: Ilya Yaroshenko Macros: NDSLICE = $(REF_ALTTEXT $(TT $2), $2, mir, ndslice, $1)$(NBSP) +/ module mir.qualifier; import std.traits; /++ +/ template LightScopeOf(T) { static if (isPointer!T) { alias LightScopeOf = T; } else { static if (__traits(hasMember, T, "lightScope")) alias LightScopeOf = typeof(T.init.lightScope()); else static if (is(T == immutable)) alias LightScopeOf = LightImmutableOf!T; else static if (is(T == const)) alias LightScopeOf = LightConstOf!T; else alias LightScopeOf = T; } } /++ +/ template LightConstOf(T) { static if (isPointer!T) { alias LightConstOf = const(PointerTarget!T)*; } else { alias LightConstOf = typeof(const(T).init.lightConst()); } } /// ditto template LightImmutableOf(T) { static if (isPointer!T) { alias LightImmutableOf = immutable(PointerTarget!T)*; } else { alias LightImmutableOf = typeof(immutable(T).init.lightImmutable()); } } @property: /++ Tries to strip a reference counting handles from the value. This funciton should be used only when the result never skips the current scope. This function is used by some algorithms to optimise work with reference counted types. +/ auto ref lightScope(T)(auto ref return T v) if (!is(T : P*, P) && __traits(hasMember, T, "lightScope")) { return v.lightScope; } /// ditto auto ref lightScope(T)(auto return ref T v) if (is(T : P*, P) || !__traits(hasMember, T, "lightScope")) { static if (is(T == immutable)) return lightImmutable(v); else static if (is(T == const)) return lightConst(v); else return v; } /// auto lightImmutable(T)(auto ref immutable T v) if (!is(T : P*, P) && __traits(hasMember, immutable T, "lightImmutable")) { return v.lightImmutable; } /// ditto T lightImmutable(T)(auto ref immutable T e) if (!isDynamicArray!T && isImplicitlyConvertible!(immutable T, T) && !__traits(hasMember, immutable T, "lightImmutable")) { return e; } /// ditto auto lightImmutable(T)(immutable(T)[] e) { return e; } /// ditto auto lightImmutable(T)(immutable(T)* e) { return e; } /// auto lightConst(T)(auto ref const T v) if (!is(T : P*, P) && __traits(hasMember, const T, "lightConst")) { return v.lightConst; } /// ditto auto lightConst(T)(auto ref immutable T v) if (!is(T : P*, P) && __traits(hasMember, immutable T, "lightConst")) { return v.lightConst; } /// ditto T lightConst(T)(auto ref const T e) if (!isDynamicArray!T && isImplicitlyConvertible!(const T, T) && !__traits(hasMember, const T, "lightConst")) { return e; } /// ditto T lightConst(T)(auto ref immutable T e) if (!isDynamicArray!T && isImplicitlyConvertible!(immutable T, T) && !__traits(hasMember, immutable T, "lightConst")) { return e; } /// ditto auto lightConst(T)(const(T)[] e) { return e; } /// ditto auto lightConst(T)(immutable(T)[] e) { return e; } /// ditto auto lightConst(T)(const(T)* e) { return e; } /// ditto auto lightConst(T)(immutable(T)* e) { return e; } /// auto trustedImmutable(T)(auto ref const T e) @trusted { return lightImmutable(*cast(immutable) &e); } mir-core-1.0.2/source/mir/utility.d000066400000000000000000000233421353705753200172040ustar00rootroot00000000000000/++ Generic utilities. $(BOOKTABLE Cheat Sheet, $(TR $(TH Function Name) $(TH Description)) $(T2 swap, Swaps two values.) $(T2 extMul, Extended unsigned multiplications.) $(T2 min, Minimum value.) $(T2 max, Maximum value.) ) Copyright: Andrei Alexandrescu 2008-2016, Ilya Yaroshenko 2016-. License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: Ilya Yaroshenko, $(HTTP erdani.com, Andrei Alexandrescu) (original std.* modules), Macros: T2=$(TR $(TDNW $(LREF $1)) $(TD $+)) +/ module mir.utility; import std.traits; import mir.math.common: optmath; version(LDC) pragma(LDC_inline_ir) R inlineIR(string s, R, P...)(P) @safe pure nothrow @nogc; @optmath: version(LDC) { /// public import ldc.intrinsics: _expect = llvm_expect; } else version(GNU) { import gcc.builtins: __builtin_expect, __builtin_clong; /// T _expect(T)(in T val, in T expected_val) if (__traits(isIntegral, T)) { static if (T.sizeof <= __builtin_clong.sizeof) return cast(T) __builtin_expect(val, expected_val); else return val; } } else { /// T _expect(T)(in T val, in T expected_val) if (__traits(isIntegral, T)) { return val; } } public import std.algorithm.mutation: swap; void swapStars(I1, I2)(auto ref I1 i1, auto ref I2 i2) { static if (__traits(compiles, swap(*i1, *i2))) { swap(*i1, *i2); } else { import mir.functional: unref; auto e = unref(*i1); i1[0] = *i2; i2[0] = e; } } /++ Iterates the passed arguments and returns the minimum value. Params: args = The values to select the minimum from. At least two arguments must be passed, and they must be comparable with `<`. Returns: The minimum of the passed-in values. +/ auto min(T...)(T args) if (T.length >= 2) { //Get "a" static if (T.length <= 2) alias a = args[0]; else auto a = min(args[0 .. ($+1)/2]); alias T0 = typeof(a); //Get "b" static if (T.length <= 3) alias b = args[$-1]; else auto b = min(args[($+1)/2 .. $]); alias T1 = typeof(b); static assert (is(typeof(a < b)), "Invalid arguments: Cannot compare types " ~ T0.stringof ~ " and " ~ T1.stringof ~ "."); static if ((isFloatingPoint!T0 && isNumeric!T1) || (isFloatingPoint!T1 && isNumeric!T0)) { import mir.math.common: fmin; return fmin(a, b); } else { static if (isIntegral!T0 && isIntegral!T1) static assert(isSigned!T0 == isSigned!T1, "mir.utility.min is not defined for signed + unsigned pairs because of security reasons." ~ "Please unify type or use a Phobos analog."); //Do the "min" proper with a and b return a < b ? a : b; } } @safe version(mir_test) unittest { int a = 5; short b = 6; double c = 2; auto d = min(a, b); static assert(is(typeof(d) == int)); assert(d == 5); auto e = min(a, b, c); static assert(is(typeof(e) == double)); assert(e == 2); } /++ `min` is not defined for arguments of mixed signedness because of security reasons. Please unify type or use a Phobos analog. +/ version(mir_test) unittest { int a = -10; uint b = 10; static assert(!is(typeof(min(a, b)))); } /++ Iterates the passed arguments and returns the minimum value. Params: args = The values to select the minimum from. At least two arguments must be passed, and they must be comparable with `<`. Returns: The minimum of the passed-in values. +/ auto max(T...)(T args) if (T.length >= 2) { //Get "a" static if (T.length <= 2) alias a = args[0]; else auto a = max(args[0 .. ($+1)/2]); alias T0 = typeof(a); //Get "b" static if (T.length <= 3) alias b = args[$-1]; else auto b = max(args[($+1)/2 .. $]); alias T1 = typeof(b); static assert (is(typeof(a < b)), "Invalid arguments: Cannot compare types " ~ T0.stringof ~ " and " ~ T1.stringof ~ "."); static if ((isFloatingPoint!T0 && isNumeric!T1) || (isFloatingPoint!T1 && isNumeric!T0)) { import mir.math.common: fmax; return fmax(a, b); } else { static if (isIntegral!T0 && isIntegral!T1) static assert(isSigned!T0 == isSigned!T1, "mir.utility.max is not defined for signed + unsigned pairs because of security reasons." ~ "Please unify type or use a Phobos analog."); //Do the "max" proper with a and b return a > b ? a : b; } } /// @safe version(mir_test) unittest { int a = 5; short b = 6; double c = 2; auto d = max(a, b); static assert(is(typeof(d) == int)); assert(d == 6); auto e = min(a, b, c); static assert(is(typeof(e) == double)); assert(e == 2); } /++ `max` is not defined for arguments of mixed signedness because of security reasons. Please unify type or use a Phobos analog. +/ version(mir_test) unittest { int a = -10; uint b = 10; static assert(!is(typeof(max(a, b)))); } /++ Return type for $(LREF extMul); +/ struct ExtMulResult(I) if (isIntegral!I) { /// Lower I.sizeof * 8 bits I low; /// Higher I.sizeof * 8 bits I high; } /++ Extended unsigned multiplications. Performs U x U multiplication and returns $(LREF ExtMulResult)!U that contains extended result. Params: a = unsigned integer b = unsigned integer Returns: 128bit result if U is ulong or 256bit result if U is ucent. Optimization: Algorithm is optimized for LDC (LLVM IR, any target) and for DMD (X86_64). +/ ExtMulResult!U extMul(U)(in U a, in U b) @nogc nothrow pure @safe if(isUnsigned!U && U.sizeof >= ulong.sizeof) { static if (is(U == ulong)) alias H = uint; else alias H = ulong; enum hbc = H.sizeof * 8; static if (is(U == ulong) && __traits(compiles, ucent.init)) { auto ret = ucent(a) * b; return typeof(return)(cast(ulong) ret, cast(ulong)(ret >>> 64)); } else { if (!__ctfe) { static if (size_t.sizeof == 4) { // https://github.com/ldc-developers/ldc/issues/2391 } else version(LDC) { // LLVM IR by n8sh pragma(inline, true); static if (is(U == ulong)) { auto r = inlineIR!(` %a = zext i64 %0 to i128 %b = zext i64 %1 to i128 %m = mul i128 %a, %b %n = lshr i128 %m, 64 %h = trunc i128 %n to i64 %l = trunc i128 %m to i64 %agg1 = insertvalue [2 x i64] undef, i64 %l, 0 %agg2 = insertvalue [2 x i64] %agg1, i64 %h, 1 ret [2 x i64] %agg2`, ulong[2])(a, b); return ExtMulResult!U(r[0], r[1]); } else static if (false) { auto r = inlineIR!(` %a = zext i128 %0 to i256 %b = zext i128 %1 to i256 %m = mul i256 %a, %b %n = lshr i256 %m, 128 %h = trunc i256 %n to i128 %l = trunc i256 %m to i128 %agg1 = insertvalue [2 x i128] undef, i128 %l, 0 %agg2 = insertvalue [2 x i128] %agg1, i128 %h, 1 ret [2 x i128] %agg2`, ucent[2])(a, b); return ExtMulResult!U(r[0], r[1]); } } else version(D_InlineAsm_X86_64) { static if (is(U == ulong)) { version(Windows) { ulong[2] r = extMul_X86_64(a, b); return ExtMulResult!ulong(r[0], r[1]); } else { return extMul_X86_64(a, b); } } } } U al = cast(H)a; U ah = a >>> hbc; U bl = cast(H)b; U bh = b >>> hbc; U p0 = al * bl; U p1 = al * bh; U p2 = ah * bl; U p3 = ah * bh; H cy = cast(H)(((p0 >>> hbc) + cast(H)p1 + cast(H)p2) >>> hbc); U lo = p0 + (p1 << hbc) + (p2 << hbc); U hi = p3 + (p1 >>> hbc) + (p2 >>> hbc) + cy; return typeof(return)(lo, hi); } } /// unittest { immutable a = 0x93_8d_28_00_0f_50_a5_56; immutable b = 0x54_c3_2f_e8_cc_a5_97_10; enum c = extMul(a, b); // Compile time algorithm assert(extMul(a, b) == c); // Fast runtime algorithm static assert(c.high == 0x30_da_d1_42_95_4a_50_78); static assert(c.low == 0x27_9b_4b_b4_9e_fe_0f_60); } version(D_InlineAsm_X86_64) { version(Windows) private ulong[2] extMul_X86_64()(ulong a, ulong b) { asm @safe pure nothrow @nogc { naked; mov RAX, RCX; mul RDX; ret; } } else private ExtMulResult!ulong extMul_X86_64()(ulong a, ulong b) { asm @safe pure nothrow @nogc { naked; mov RAX, RDI; mul RSI; ret; } } } version(LDC) {} else version(D_InlineAsm_X86_64) @nogc nothrow pure @safe version(mir_test) unittest { immutable a = 0x93_8d_28_00_0f_50_a5_56; immutable b = 0x54_c3_2f_e8_cc_a5_97_10; version(Windows) { immutable ulong[2] r = extMul_X86_64(a, b); immutable ExtMulResult!ulong c = ExtMulResult!ulong(r[0], r[1]); } else { immutable ExtMulResult!ulong c = extMul_X86_64(a, b); } assert(c.high == 0x30_da_d1_42_95_4a_50_78); assert(c.low == 0x27_9b_4b_b4_9e_fe_0f_60); } mir-core-1.0.2/test_examples.sh000077500000000000000000000004071353705753200164560ustar00rootroot00000000000000#!/bin/bash set -euo pipefail dub fetch dtools # extract examples dub run dtools:tests_extractor -- -i source -o out # compile the examples for file in $(find out -name "*.d") ; do echo "Testing: $file" $DMD -de -unittest -Isource -c -o- "$file" done