From 012fc3b21fc67d9864c4d862a2811ff4704ad0fa Mon Sep 17 00:00:00 2001 From: mlemanczyk Date: Fri, 13 Jan 2023 19:45:22 +0100 Subject: [PATCH] RecyclableArrayList.AddRange added. Smaller perf improvements. --- .../ListVsLinkedListBenchmarks.cs | 4 +- Recyclable.Collections.Benchmarks/Program.cs | 4 +- .../RecyclableCollectionsBenchmarks.List.cs | 27 ++++++++-- ...llectionsBenchmarks.RecyclableArrayList.cs | 27 ++++++++-- ...bleCollectionsBenchmarks.RecyclableList.cs | 10 ++-- Recyclable.Collections/RecyclableArrayList.cs | 51 +++++++++++++++--- .../RecyclableArrayList_CreateBenchmarks.png | Bin 0 -> 25262 bytes .../RecyclableArrayListTests.cs | 36 ++++++++++++- 8 files changed, 134 insertions(+), 25 deletions(-) create mode 100644 Recyclable.Collections/RecyclableArrayList_CreateBenchmarks.png diff --git a/Recyclable.Collections.Benchmarks/ListVsLinkedListBenchmarks.cs b/Recyclable.Collections.Benchmarks/ListVsLinkedListBenchmarks.cs index 108f96b..52d8471 100644 --- a/Recyclable.Collections.Benchmarks/ListVsLinkedListBenchmarks.cs +++ b/Recyclable.Collections.Benchmarks/ListVsLinkedListBenchmarks.cs @@ -29,11 +29,11 @@ //public class ListVsLinkedListBenchmarks //{ // [Benchmark] - // public void RecyclableBlockList() + // public void RecyclableArrayList() // { // var data = TestObjects; // var dataCount = TestObjectCount; - // using var list = new RecyclableBlockList(initialCapacity: dataCount); + // using var list = new RecyclableArrayList(initialCapacity: dataCount); // for (long i = 0; i < dataCount; i++) // { // list.Add(data[i]); diff --git a/Recyclable.Collections.Benchmarks/Program.cs b/Recyclable.Collections.Benchmarks/Program.cs index b55ba7a..fdc21ac 100644 --- a/Recyclable.Collections.Benchmarks/Program.cs +++ b/Recyclable.Collections.Benchmarks/Program.cs @@ -5,7 +5,9 @@ using Recyclable.Collections.Benchmarks; BenchmarkRunner.Run(); -//var test = new RecyclableCollectionsBenchmarks(); +//var benchmark = new RecyclableCollectionsBenchmarks(); +//benchmark.RecyclableArrayList_Add(); +//benchmark.RecyclableArrayList_Add_WithCapacity(); //BenchmarkRunner.Run(); diff --git a/Recyclable.Collections.Benchmarks/RecyclableCollectionsBenchmarks.List.cs b/Recyclable.Collections.Benchmarks/RecyclableCollectionsBenchmarks.List.cs index 9766fc0..e7f3324 100644 --- a/Recyclable.Collections.Benchmarks/RecyclableCollectionsBenchmarks.List.cs +++ b/Recyclable.Collections.Benchmarks/RecyclableCollectionsBenchmarks.List.cs @@ -6,28 +6,28 @@ namespace Recyclable.Collections.Benchmarks { private readonly List _testList; - [Benchmark(Baseline = true)] + //[Benchmark(Baseline = true)] public void List_Create() { var list = new List(); DoNothing(list); } - [Benchmark] + //[Benchmark] public void List_Create_0Capacity() { var list = new List(0); DoNothing(list); } - [Benchmark] + //[Benchmark] public void List_Create_WithCapacity() { var list = new List(TestObjectCount); DoNothing(list); } - //[Benchmark] + [Benchmark] public void List_Add() { var data = TestObjects; @@ -39,7 +39,7 @@ namespace Recyclable.Collections.Benchmarks } } - //[Benchmark] + [Benchmark(Baseline = true)] public void List_Add_WithCapacity() { var data = TestObjects; @@ -51,6 +51,23 @@ namespace Recyclable.Collections.Benchmarks } } + [Benchmark] + public void List_AddRange() + { + var data = TestObjects; + var list = new List(); + list.AddRange(data); + } + + [Benchmark] + public void List_AddRange_WithCapacity() + { + var data = TestObjects; + var dataCount = TestObjectCount; + var list = new List(dataCount); + list.AddRange(data); + } + //[Benchmark] public void List_GetItem() { diff --git a/Recyclable.Collections.Benchmarks/RecyclableCollectionsBenchmarks.RecyclableArrayList.cs b/Recyclable.Collections.Benchmarks/RecyclableCollectionsBenchmarks.RecyclableArrayList.cs index 400b3f0..11a8a33 100644 --- a/Recyclable.Collections.Benchmarks/RecyclableCollectionsBenchmarks.RecyclableArrayList.cs +++ b/Recyclable.Collections.Benchmarks/RecyclableCollectionsBenchmarks.RecyclableArrayList.cs @@ -20,28 +20,28 @@ namespace Recyclable.Collections.Benchmarks _testRecyclableList?.Dispose(); } - [Benchmark] + //[Benchmark] public void RecyclableArrayList_Create() { using var list = new RecyclableArrayList(); DoNothing(list); } - [Benchmark] + //[Benchmark] public void RecyclableArrayList_Create_0Capacity() { using var list = new RecyclableArrayList(0); DoNothing(list); } - [Benchmark] + //[Benchmark] public void RecyclableArrayList_Create_WithCapacity() { using var list = new RecyclableArrayList(TestObjectCount); DoNothing(list); } - //[Benchmark] + [Benchmark] public void RecyclableArrayList_Add() { var data = TestObjects; @@ -53,7 +53,7 @@ namespace Recyclable.Collections.Benchmarks } } - //[Benchmark] + [Benchmark] public void RecyclableArrayList_Add_WithCapacity() { var data = TestObjects; @@ -65,6 +65,23 @@ namespace Recyclable.Collections.Benchmarks } } + [Benchmark] + public void RecyclableArrayList_AddRange() + { + var data = TestObjects; + using var list = new RecyclableArrayList(); + list.AddRange(data); + } + + [Benchmark] + public void RecyclableArrayList_AddRange_WithCapacity() + { + var data = TestObjects; + var dataCount = TestObjectCount; + using var list = new RecyclableArrayList(dataCount); + list.AddRange(data); + } + //[Benchmark] public void RecyclableArrayList_GetItem() { diff --git a/Recyclable.Collections.Benchmarks/RecyclableCollectionsBenchmarks.RecyclableList.cs b/Recyclable.Collections.Benchmarks/RecyclableCollectionsBenchmarks.RecyclableList.cs index 57c760e..27ff894 100644 --- a/Recyclable.Collections.Benchmarks/RecyclableCollectionsBenchmarks.RecyclableList.cs +++ b/Recyclable.Collections.Benchmarks/RecyclableCollectionsBenchmarks.RecyclableList.cs @@ -6,28 +6,28 @@ namespace Recyclable.Collections.Benchmarks { private readonly RecyclableList _testRecyclableList; - [Benchmark] + //[Benchmark] public void RecyclableList_Create() { using var list = new RecyclableList(); DoNothing(list); } - [Benchmark] + //[Benchmark] public void RecyclableList_Create_0Capacity() { using var list = new RecyclableList(totalItemsCount: 0); DoNothing(list); } - [Benchmark] + //[Benchmark] public void RecyclableList_Create_WithCapacity() { using var list = new RecyclableList(totalItemsCount: TestObjectCount); DoNothing(list); } - //[Benchmark] + [Benchmark] public void RecyclableList_Add() { var data = TestObjects; @@ -39,7 +39,7 @@ namespace Recyclable.Collections.Benchmarks } } - //[Benchmark] + [Benchmark] public void RecyclableList_Add_WithCapacity() { var data = TestObjects; diff --git a/Recyclable.Collections/RecyclableArrayList.cs b/Recyclable.Collections/RecyclableArrayList.cs index f68b870..81ab4dc 100644 --- a/Recyclable.Collections/RecyclableArrayList.cs +++ b/Recyclable.Collections/RecyclableArrayList.cs @@ -1,4 +1,5 @@ -using System.Collections; +using System.Buffers; +using System.Collections; namespace Recyclable.Collections { @@ -36,7 +37,7 @@ namespace Recyclable.Collections } } - protected void EnsureCapacity(in int requestedCapacity) + protected ref int EnsureCapacity(in int requestedCapacity) { int newCapacity; switch (_capacity > 0) @@ -56,7 +57,9 @@ namespace Recyclable.Collections } _memory = SetNewLength(_memory, newCapacity); - _capacity = _memory.Length; + newCapacity = _memory.Length; + _capacity = newCapacity; + return ref _capacity; } #pragma warning disable CS8618 // _memory will be initialized when the 1st item is added @@ -107,6 +110,7 @@ namespace Recyclable.Collections } } } + public int Count { get; set; } public bool IsReadOnly { get; } = false; @@ -115,13 +119,48 @@ namespace Recyclable.Collections int requestedCapacity = Count + 1; if (_capacity < requestedCapacity) { - EnsureCapacity(requestedCapacity); + _ = EnsureCapacity(requestedCapacity); } _memory[Count] = item; Count++; } + public void AddRange(in T[] items) + { + int sourceItemsCount = items.Length; + int targetCapacity = Count + sourceItemsCount; + if (_capacity < targetCapacity) + { + _ = EnsureCapacity(targetCapacity); + } + + Span itemsSpan = items.AsSpan(); + for (int sourceItemIdx = 0, targetItemIdx = Count; sourceItemIdx < sourceItemsCount;) + { + _memory[targetItemIdx++] = itemsSpan[sourceItemIdx++]; + } + + Count = targetCapacity; + } + + public void AddRange(in List items) + { + var sourceItemsCount = items.Count; + var targetCapacity = Count + sourceItemsCount; + if (_capacity < targetCapacity) + { + _ = EnsureCapacity(targetCapacity); + } + + for (int sourceItemIdx = 0, targetItemIdx = Count; sourceItemIdx < sourceItemsCount;) + { + _memory[targetItemIdx++] = items[sourceItemIdx++]; + } + + Count = targetCapacity; + } + public void Clear() { Count = 0; @@ -159,9 +198,9 @@ namespace Recyclable.Collections public void Insert(int index, T item) { int requestedCapacity = Count + 1; - if (Capacity < requestedCapacity) + if (_capacity < requestedCapacity) { - EnsureCapacity(requestedCapacity); + _ = EnsureCapacity(requestedCapacity); } for (var toMoveIdx = Count - 1; toMoveIdx >= index; toMoveIdx--) diff --git a/Recyclable.Collections/RecyclableArrayList_CreateBenchmarks.png b/Recyclable.Collections/RecyclableArrayList_CreateBenchmarks.png new file mode 100644 index 0000000000000000000000000000000000000000..ed3622aa14e7832123c302fce83832e470b6c9cb GIT binary patch literal 25262 zcmd?Rc|4SV`#xMLS};j6)~U3J(AcuhkV2_Yb}};AO@*v8LsFIulkC~45XQbQlQ1Lu zzDJQI`!<7N#&fC9eczw&@B7@Z*XMa&&wtM!2wmfSo!9w3&*M0c<2^w-cQx3K@*dr{ zZy(!D&FlB}?K|`y`1iZR%)n=Zx7wq?m;EmHG_LI4dPjBNzI^<#ori~j z?~gpyGl3Fy#ev`_~nCF{OEgYsRrWsu#ZAS**r^;#!g#Te!kh z7nP<**Wipv1Y^<=iGz~B|N1oLh&he=A3r$p|F0j&LNs@mc6ZtlyL94irKt@L`qAGd zv-|)#_Ultz3@f>jo{w)M^X4Mi`t$uAjEMb6h*FXewropc?% z^SAjGkN{^a*KyO|Kg@mbO1t-syJMdKig=cp=e|qe5`AS`)zmPPcyz}pLc8N_@%pTF z_GWS~d^W}|z89g&4_Txt%6!4)jNHy^B-J|-FPa79aU$bf=Mx(Fq0-m5hl zz+(yD6Oiw}kvHEIh;5gRBWskprZW7VM-^gTo^tOO9u9C~h;Gjiwx9c1ZUs5?ece97 zB7mXN9B-5#p?C1GZP+@wv$c2OWsvwXCemzi)^ZTXiXeEyX>@hJH|di%uGMT= zs6_8>jc#a4;@p5l7V&7Gx89Dh#9ueMYX`G1Bf9JeLNxi1kC}pugWhrTnp>8Q(mGi3Z5zpNh88R}HZpZfWm%zQ7zm;Kex zizJ6(y)8YqVfXoJ1;Q-35*`pZ@QZGtwPm%Qa5@Xlx3~VPFDy9>?X~?AlJ4KO6Y5xi zzs{G!a!{f|$--l+S1VVL_uONFeFwILYi2U5ZXi1n19*}m*4_$0G^Msb%V2v9QTm96 z^7Ytkl5mEygWy>3-6EldYo8@%hO_R+@2hEuUKPrJ(~Cr&(uic}^9ybN(CXA& zYg!BRUQfrhQ$4@9@*(ZXl*{Vtrq?l_Bo;0?tlc3gk~OoOvUDX7S*QjwDoz$}(;h5h zv!%IKQK(*sJ-i;Y7Ep%&6#rr6sBJ5)PQ`#70hc4#OAgpb;EAFsd8vq( z6w%S)3Xvp2iVBOjR)yhJq&|GA!7JAENvjB?6>E@Wcd#W%UZ0l$PVKcuV{lYPdlTN5!nm*)F$3|Oww+I?L@H@wbRl4+6&pn(y1Lm~9-SSy2 zNK!feIloNP{RlEQ*qN8^+Aagy_f0Blo(zO;;dh1sRY3)3pT z7i`rMR#3KR5H4%jVYA-GLI1L*E`NR~cl96}zE9%XRtDiH9d4|q!*1(x;}sWO?q_g& zk6YW7CS;^nlTCSOK2rJ3_PDYIU(8sPS&NYngfgYP)`{B-6UcqN_ORoPyp3N={IEB& zq!EAP)%Uk4%9csSsUPE&K5kPVHo0cwUAl^AlmCRG-Xm}lg=|_Km`lra>jvj zxx<0&VOkjGo@~snDIN>1Zt*@uZgl#74D){M*?u4tqCTVox1>_&KK{cilkeX;#IS5& z27esm>|bfNj&u*@kPai!EKkwfYa?KhhYvI!N8xMyeMR-eN zk}+>?^4JTcPieqelhXCsGi=6&J%J9h<)NO}DI$DZ7WLm`aFY=NDTtS=x(~Q$J_Y{# z@f7w$S=lohZKvI@*qrXKXS&y6QcQ?4R-V-LD?yo#6}%0WF#yf#LAG(2i2QyQW%|;T zA8uf5iGTO=UQHUlqLnBz@s2ymXiQS8CxU#vMMl=O-4*jS2rfV0n)@d#*`y2_S;Fmg zKNw^jZ{QT4z`_WG&34lAtqkyVUGaOy*2EXcpK@MX`%!2bb!hxp)3bKhb%~mEoRJQe zs`Rs&4>4d%jxM2oPX4l2f1tc6-2H`^oNZlWt@be$qp``$Zfbs4n!+-_fL7{>cq}HQN1CNGDNI8q^IR z6Rhr;eNTJqa(~0f@Yzby@)*WmN_<<>eN_#!$mVcgRz2j{Ah+?S;#{?iQqosHao#gL zSlBP7tk)lQ&bYW!OKM9LcDU?g&Z4KVMN-W`$ZqKg#Lvu$M1>(8$hM)AIQBw)*Dc&9 zxCF+m+aG){{@1J1f0bs)&tqFgZycUG2rz##!xnnQOs3x26$uTaC&y7GVP7Ddmj!8| zi5ij9Hvwd*yKRe(a5(7J3o^|oG%1n~^A^Isx!j4Rg8NZ5>dl*zC~8{@+VQ&Sr=*27 zvAqbfy7vJ+cOZTtO~l5o>Zk)U;e`*MU~LvAVy6YU`Vz=-?6MJ%5OH zC6x3wAqReLM~^LYI?<^ILg>QhgAtxL^DeBuUW^4TfYlsuSZhi)8#>J_z<)i2w>wIq zRlEF+>*Ll2DG2n*Y@P-W0Mx_=2?b=9mRI>E^dI7|3>8FQE}Bp*p5xRIP(fBN(tm)6 zREF{YV6sEDpiV!0tF(oiM8%$vp6p;0Y6(h5WC}(!enqSsni4YcSjxRaMR?GDf{bj^ zx%C0!UICXst4=wa;=G9DLH)Jqwz3YjPUe>UCy47VxOqQ%b8t20IQE=%d)mC`iESNi zB@1oJ^Ii3FX4~8f*(ds*(_q!;GWYk~CN5*m{S|nuIxN(RBjo1TprS@(A*QE|d-3C5 zo7b7VGNi%P*0p&!hOgc%*)MItIzrSadfmWuXhv{3>)FR8MSCECJz0q6zN(!}-cQ=i z`ZSK+mTEB@wjAZe$stipi9A*>X;Q&f<~?!Nzy;cZxvto|;yLO5J&f`6B2bnS85K54 zO^d5aIR)eZq2JJ7;&XYAneRl)BRTck{>Yz<0gY*72mpTPjOt{v$L8`uiS1#qbpXea zs`gFab2$_$75)PZ6)+f?rviuVosI>UgK-~ zFm;sQ1^~#G08ZW@!xSJ6RiQFwz(o(~=6LKfCUpJB6!3ul&Pl96dxi1eoP`8-IT8nY zzZD#@Q%p8bfRbW(|G}%K>}I6=!zFhBH3z(QAYQALORf!wK|K(PMLhNytj|Nhp$u4U z9j#h$`}-FEFSR|m*K+KsxQyXfeaBAn4(S&RE4~4#`Y;zl4^M2DV??Ko- zp7sAQwg>Awl6)BDrYxaS6aO{DhP3~zm&0u9i$!A4e_gTJuR1mM_q&u_A38;XxYPBD z>P`r#Y+vb~`?2V!_mp}yr`luigw(GzT0^xg`WTdyKc4NUlW zZ!hHhXKnCm!9^HZbQWpeQl=37g~Q<)-IJn|&w;!!@hx#MckfohfF~tujU2LGuFLEc-6dAy{rN1smz9#(Un|>8_?eV)r$?xcm*Il#Ig8Blei|S%S`C|x zb$Z5H$K`+lZV-=41Z|A(7Sw@}=Fk5DGo0B=UeEnNMjj44vkOOA|M&bc`&<5KJe@q| z=Xv43XV8cLR~htAcBhZ;iVt?bGapRqoHk7lg+^==tH z75@f;Up{l;B&7aUFJfJvc*?QMAKvraXY;2Z{04&lBkqYC-bZGM-)83#1I}P<-M6r>q-0>0bSXY#{zBO%A*USCr3Yc!ZRa%}vh{n|&i`|2Y zT8D42D!d{+D>*#=D`HG!jAV!7Ju z`$aU(S=(9vz;rMy$Y7z-@DtN{^Y7{S0o?~yj95BwV{^%h3hKKy-{Iq$0qrWgn`*}i zX-~>RH+sm_7FBfefs()nu%I)f0Pse(2Kr8Zi52TgsFVLvhaco%25Yr2-(+ZGB4afl zlWcZ!xLF)k=oQ&I({QtB8XUXUB=_STqiEtj1=_FEKje%X;g(hb21J3E{i*c>f$6kA z&*>*kR94+7+j%soe2Q}zr8s|2oA9F|r(I61PP>kmuyTZ^zi|mwQpNd3Xp{Z6`I)hq zs|9G3jhw$rM@Dp(jS|Ikua?0MpI}Fq8M5p=!@aBzwv~`yX^0Bo3#d?0o_UzgP)b&z z9ACh7lvOL74r_vW1{Obs5P#lptBZV;RnpV!KXq84!&)r=vFvV(H`jEROb2Lezl2(~ z#9glS(*~^j7&r-|%}cb``6pS5UJV{Y1k>z6mqso58>&BoMm@wU0d|?eb z1`w2$Qm;l9?<2b5f<{}1hpTtKPXqHt1i8SdjrQDO&~Eti=!Uo>#!K9|0f@;W4KeZ#RmCCe02rK;M%z?e2HY}dI~TF*gE~`$i)lUMs1_h&0+!hSG*cK zA8RKzvcEr6G7((ht%h@;%^ic!98bnt6v!qcwyz|%67Au2_;&jg^BBwQ|U> ziA(X?hJARi&HDIDM*b*Nk~!hSMz2#>pQ=Q^oO+^K7V6by{{ot==tL&Wr1$h3@OPd4 zNm*;bbWz!|bfu{M#5Wu+FXu@c5As(>UH$#tHB3S?HsvkZauBb6?_Fh+>Pc?W>jg;| z)W7tFy6tcl-x;6ft@qRavcQ_`NcRT)to1Awe`7$^4owY)VDG5QRLJ3_Ns9G|qQy0``+PFQuTYUwCPu z@aPiQMhc=w{Sn330V9hlWMf;UKpY@iBDMItL#fpjK$X%C>E`M<499&oto9bl zPN8H;4y8xBM+sKPKaZ+*kK;)K*O{uO*%MB!cy>hD<+jY~8~gxz((mf^vKyx9^(I2( zYY+=B!p)8k;`TF8+4BIO(&<7Lz7mZ&3-OgwQy~+>+x6AuZBy_<;-TrTiGl5gz|9X3 zy8cI|6v53bZZ({iv5a^g=R~x_XLZMm>f700DoMuMXLG*sBS=EE_7Y)5cP@7T+yJ#&5x9WP4Z}{qodf36 zn77{5*ow(-C9k|^xSKa$CFFQ10NeR+HQH4waZ_mzwL=ab36OZt|LI1=%V)U(TuJ$f z??1@Cz^Dvw<_UG`o*FjfOgM2Rpo^c@$*qWqB{6R(?G%Ofi6g@u^V9NOJsMrjxKW!S zP&(D22>Ncfg>ee#L4F8J$M5*WsE8k9C1#E7gWMwX*SBBuwE7w~+?65azuE-`Iu>eH zQ0jA7WO+%IL;OvNhA(~KMw-@=c})ap`6|{<&ByXA?P6BD1$)c=jnJ@#Dv`S;5S()e zKtPrsKX=kMr^C?&h5DIBZU`~86o%>H*r?T&)2r^j#bE>g^eDtnx;SJ~i4 zfa0z=7rk(wFt|IY*c@1r>)bxWVkpF4hx|`}O%|M=yQPeX8deZ!X>ihfr|_P0v5dm&XRSs)@vcANQ*wW{n(e_GpNSOCw`t1!`|AsKlz5p-E zIJ%ig{Ah=RPF?*cYv0vXTPs-(SoNAD1sak9|G_$dZnq}PSZ$U-SmqgWZ|&(LMU#bw zaKGJT>?GW7x0Fa<=wI@t{c7G^PKWqZt-}`)2|mnlw%@AFF_SS!&DNAV$~;H)l`$?p z=ZswRVgTga@%yhOEK$M40!GgSU+;#c*|vq=9?)ttz+RbyzxFL*o3!sHaSUbM9qHs= zN(^qpaqiIfK%@y|dq2ts`UUbz)dyBi1_1;+|Ad+`>m!PO;$oWNVz-EmJ*J*!C~bj? z&=@x{9ILEPpMEQp=kHKe=&gYv#-{wnlc65wR_)=v(`>)lYMe$b=?pX4l>?%gbT#qq zz~!(l6$NtnGk6vP7wYj)ar~k8AprDd!D1+o29;rd=VH5w!wdQs7iWS2sB1$y!l3%D zZx{Z5w+>k;r;3X=yPiD3t?mA@bqQa0z0yotDu(+-ZrLO&&rKZXHi8@x3w38<6KS#h zd7JH(%P;T1i-LXiQR8#%@ZAyAFtRVn@60&&SVkiFVq!0Rk*RmAHyXgYd-sskpn~(e z%r3+1sWb0+A)&RBbU2>p;%6Bcd7~&8n8K%M<2V-ewQqN5JNZ^C(#8{z=a4e~1>nZn zETut>+|hJ>VEU3l$+bPrmp08sHyEv~H|F&|(f2gOz3)khw&>Us$^RhTrnOt;nDxuR zwf_n=^I0I&8mgG3kQH;wv9qYA z%_6#I=WB|W$6U=fmIcAGJ;Ba!ZHH*Cm3?2hU+A8`ub)>a|g zrF4P^b^gbHU3;E>++Onw?XI+7>)$*_FYzXRO%}sG%T?kW)&mNJG4@Y}gvfOT0D~5M z>YbNjLshAFsvMo^vag4pew*V9l2yNQ3N;KJ_WGWFPw8CQ1*q`W)2CW*brh-ZW>s!7 zZGPo((=&|qvG!rc{;G@qV071~$r$l*e@oxKmLsUm_iVI|^dU&c3-6*@;y`!G=4EwB zHW@c1i)is`&lZcz05A+x-m2gwhuQlK32U!YRY#aa;yQz!0_pkkP5Pz)4m73ICNf_8 zCW2;$gN2&%Za)70u02Lk(#vTaoatf}-`Jnex~#pkUu+>2pAkIdQr*B^~V0LYMMDAF-%$8An9tD5cYSC7`Rezk;}gMi=FQ^cjoBS_=lvQEwyJ|ldtF0 zoHNu>zRo8kZJo=md7z+O&{AMT3WDWHiDzL7x`xV(W^3ixJkjK#ke$;4FNFJ1yYvvr zGujC|Z|(LK$~>P66bre*N7JWe-KMR6Ag%%uKCv-!Gd8PIv$Ezfg1gWg0DEoc|{oU?lUNZ+kUN zc{KKBR8zWoS8tCz&5s|Lv`SK|*M0G^H4&W4PdZRCp_S-e8RS4)YtVH)=h-y$sJ-I3 z_k!Oe+1*ccLEZaPASGNz8b47_=6NUY5PIj_wuqmu&(zD0`Kb2(^fgk(?b4CbVfy~vF*Io^*4yNHxKm(w9h&l56au;U=P%;E84Lkj9`Kz(@bR=8Io zIyQm;gzcf_vv>(_Wh$pOA=FPyt&N)2r;bWbu(BD zZDCAPvA=UilxmYKfHJMt3uOy|7Dngz&h?RtbdCGqB?-{DIZd^WGc`00tre9NV0P^^ z^TB?}w>bk|Ln5xQ@K*v`s@ij?%!I%T+ z#dMRL9hRw(5%JK^ArWH6ggBnOs%H5V7vCHOo(XGEF~}`As!i#B0R)8>lIP!-+Z45QmCH+hzt}J$^si9pyA%hu`<2{A zTkXBtU&)g9aOnDg-m9={%HTx*uj$o8GtHAuG{ETr6NN_n6$fgk=*F*8fAtI%V_f-VcB`@SpI*RdB}UTXKwJBJyX5pf@P|8 z_`OrZ23IrRvao!@)Fw-~ZJrHeTf8}9qUI2tfAi!(=KwABi>nzYY7>=CEzPvv3raHO zA>T}JbquF9@6&{w{iXwYeDgphM$Aoz%YNQ`m(-NUfx3Zckv`azNyg)HR>iKkPj_L3 zsmsUuQLIOs0`VnEbM3`DqPu>p*GE{YmEWkEI?g0I4C?WeObomWC+^VwK7oYi8dUla zUK@#5SAA*sNUrV7R;%aBaoe&>_+`^AQ!M4L45XX+_L zM<3K#JPQcl=RPnGKy7mD<0cUE5K|WjXe*FQ5_o&b~8zDM`yDH7adY2kpwc~s!d%e4W}u);Bi=zLy+ z;wMe(&$olqHV8QF_VXG*hyOiK{8SNTFYdSvW%f+(ck@Sj++Kh9p2D#}RRW1pxcFYxd?Z=#$ z*QEug+3fzua#XLJ z>DVXipHj%~mwW-{<;w9Q5j@1XqcTL;Fdft<*JPDNiDfQi%;YHiYL~I9%M^B)iD*z`in~@ROjkzRlAYJuVHYF7E<8CK?fY7tw7G? ztCiuG9csO1C1DiS+ILp~^^ADFU!@NoT|KuXHziK=0?4qQ(Tb|N8KlUmf3(yQ0OGIlz79=#xdm!2-W$=shIoPl_EkRky)yFftvF3rR*b5E!_SJGCA*Vf zXEjEY)xnC?iHhR1;`T%qE(i|D!M*JFcO+5Mux}c4n6Vq1K=z9j^k(^u^6~`3M9WVo zYdDoOu<)Q|02`84sTB52NZ0}s)I^PoHfpRk$P)=kNs_@lW|btyDCT{bKC)(wO*1Po z$(4*O<<*;?yH8oi&wc%TYWn2BLw?LDkYQH#riEyyMum+)wcNs5QZ$Z6;;- zukW1S@&;Z1i_pDo^ia6{o6xBRd@yrhGjk9#YschSdE?GQ8sx2c>uw8mfCp09hPwT| zBN-y$yPJ=^&BzS2^l5eJtCU(pCvW|jXiO0cP3m#(<6~aO)!A-5VO1_0KNcvBuV{Jm zpbuo0Ryw<4Sd{Bl!Ht$~oFba!7Vu=>*cK+4j?6U$*fTY~GL;i;>rkDuNYqI{d_3bY z`A++pj-w657R@wqiHSAb6yms#=s%Vo18wLTc|byy2!ksqrhF z+V_;`pWA_7nHfeWJ}P%CPILg<=`2W4e_jhYX8T!g#na@~);y)wpu^X5)|^Hef12el zX1tp%h;R-;Sh>u(w+zxk^CZC2!h7?1e&*WSnDyDSPEsW2@mpUL)M`4_)cLZ3{SZPb ztFAa)Qtad#@@ZuT!dd#(GY)6W*CBC1H3pDmhyl+gdD(dUBnhU(46&qqe(SZgst5QJ zkbeCT-~5!~!BJ69YG21(JJX4zhLUQd)FnYS&2d}aC1jPJaq9=&4M4`4wUg#m!@gWZ zn^3u6I`8TO?oHO;^RGZ*{WZP}E z2BxF|D}I^|$*6)*zqi$Dl_&FWXA{o&QHq?d?Hc(^gM&2V#Ma&`uib;JGFfE<{>pDB z{ATgmUKHgLTx}H~&!jKiPRsT_i2Nq69-~#FT{yiT`DDdKt1l_P4ANjMOB8#wZE;GC zCmW?r6zV7Q1HN3&1zs7!B(%$UR93s6a=GSwuUyyK3KuM+${l*K*lt7hCzlhi{QWx7 zbtZ?+7VvwCiPa-3o~e}O!DgV@m}!`>l~BjF%}=51S`zWr7RX#sNix_nQ6#S6hXI>u z0fTFMHMm0=E8T{3Oal7MA3}HK@KjEmOjM!orsW|=ouQdvJx7h5g`nEbGO>YB#PUnp z#+z2RaJ9df?acDKmws4`uUkYhuYGpnx6U2Cep(FL(Mh>bR5HX1*`aP_ygT4VGG}{V zNaM&_3D)77lH*Og)`LAnHQH8VhVn59bUep4)9gwoKYV<}z+EI-ggbmsVOs!M8~olv z@U##o!f>%Lq|N!^p?N_8o0gCQxg>LAl4e~jc8IAz68tM{5RXF7;pZQy6+u(EFFJ`2 zR65{_T2^m^>^^YYs`5;@P{(w5=bdbOzK^S7@3|v}i<{mCLl1Or-#Lh@}ORSI|8yOu@hpLq#(9>v~;W?V@Zf7iPL%^nMfUFGuQraABq=d6Tk*ua;l z4Oor?9(2|in45IEAM1VciqZK*V*vh}4Fz;EZy%Obsa)~OGu}Mg`}oB86Kz&Yzxs&t zcO3D3wPpi=hMOaLA@(mmt>QBk`WSP-DyL5h(lVvtnH56%uFzeU%F&+>mn|mT@*&yK zDm zz*071ap_m?FD$;oOwGiX=N)jvhZc^)a4;N7bY1!YVFOuCT9w`epi;?_`sDux z4f>_4Oo&Zu=l0TGEQh(5A-ZI>C#?M#Gf>9A{=u>7SFSF0aI#R&)KjoF3`Wu}!jFkb z7Eo?b2mYP)ZU^4I6zF8`u6}zE5Zl-?WnUPjp)dn^L6?FTvTnZE{2;-SsH8I!EFgPM zw(MfQy+Fp{}=(10B`#zZi?q zv+ADeSEz|f&|uZ#unR4^Yjdqm(gB0up61dXrw1WIA&B0mzYCa2Ugyvc@7yF)MKmTR zB&j#JbJMa2l&2V+0+`439wZG>`(hfLO4J*2hC-ylA!FAn&37+zTLA^k6yDDT>3IAR zj>7-Nmvi3A0tI(b^coCnKJi zYdrtvmZ%d__sKtkLRIa9XW0lwNcqeLmL?{tPu#yt?4*67O8sWetq=3cy^c#oddXfl zO@9v|KkS~_f7;_PNmgng+3B*Z6jE6Ax^(Gbt94zzsZ@pY9{-XKlWIrb5C zg685|LEAYOM!GLVg-CxC?+%0tcbi1$SyiSwWu5swVfe&+ATHtw_V6*%aJbe7tz(SG z!$C%Zz&ILXh5Qa$wByEhOY#zXqm5!0e)O^T&+`4U`^<~vd9;SeX-`Jrt`hdgi8!o1 zl;Ac1puw`?T;1qSUN;{x^$gl{8-9AxV=#w^%0~CYdWkEbHM5=D%6uEY0G*lbPCk?&&lc1LyN@*1W-;N`+<-PS*+ZImB5%AWi6} zwoda2WwrO|Oxp1#ra%CXDH|dMawW+vbYV@n*$S9eu!)pEdm`R5;KYvWcThwE&~SnO zh75a3>X|i2&cg>=TIfT-H$gA1MBWDM&po_f^>fFxgnDfvI|Xe({nEoO;-W z*3_3%j200$&z!7mnBtUIY?I_?+8_g7RC56#E|_vCVL42uW*1hb*!L80diqn)%1hsw z;2``O;C*Nv{#<)HphS7S{bXWGWv=!c#NxZ}ov}$5Rypkiue)!3wFFI(wHG#aWJh#u z*{c;?*mAwC6`2?DfE!ck$G6??iJ7Ai?$`MRmaztg8kLyDI zfIK!30LQGg7K9X9+)bls)X*8*5~!{DUYq5lk=z}PjrwoyaQeDF8BX7v_~0XF;mY6w z25xnbdn#~Pxdu7MWcB_7hRTQWU~HBG;nMvbj$o+ZKtGOqLW&Al-uMAGi9rm7Jm$0W zBOsTOk2toX;*%JQAyxFso7YxOry7!OMrGx_xha zE<3G$GRc(win?x-%ZX50NBUUeC1+3ijNI3Ny_Z}%dMNa>qUX{LSGv(@w!1NLYCjZ!n`Q3 z9Oo#KMvl)7rrBR=2-}G(bBM{y|F%+8yJS!C(q^+YJzrFHI4IUZm6#t;r-qu`^&0lU zPNLh;e@dg_;k!FoX!C2rLUs*qx$0km*%uw>7NTr0&%~1Mh#{ScT_37?-9*Db=g+^Y zT@=Jg_?HiGTUF80c*B(5;FriP@@+2QH0_6JrM5>hnI?O+Xsvut3XKIx6)?Qy=oOrSlO^jxmv zBggv1LEZM+vjK(c_rJVm3C_V%AcH!5vb?U<(XJs({LG~Rzao&@a97Lt%>&F*+gxmU zU&{*8%I5?#Yy{1^1^M=lcFkqkwz#f49dj)J+s>c7%_NT>j;aF)6LKK5Av)?|`31aG!$&Su+PBGB+dKxRk!kG*p~0V&hJ z54FX98$G`)*n-VnU?o3ovnOy31TA3;nzvZ`F(>%)wO{>_N+V+)J%6tr>uv8pcEt9? zamu+fH9HwZc9tNH*{z;vp#upuE6X6o&KertF$25v-a!} zW0W;jifx_mPyshtgNafb+NbGL)HZ9CBx&1k*csz6|EcB%HDA?~fK*yz}f! z89&nhxPPse__KhcA)+1|pF_tkwe1h-C^sxUw1Z1}CQAp zgrHr=t=Dpg+V{-TUSx@zQa;7?0~h>@5SO|~zlS@+eBFe$>tD=MX3-X+Q-?zQ5(d=K zsG@cei_%Z6_cJ!1lA;(nh_exCIXh`a9iXgFNE~2bjSogXYWoB#S$~2R5{{b`NqkVm zQDJktI2JfL5gLZK(X+Ib*-JvbPFvu5GzKjHM_5&r*$dgXFuc0n4u8IX-;;x0xKa7{ z56^4kY=@gJEP?YMkS>yz4LS~^(60JkW4c?Dm76eO2&pjSFGW!l`c?S(5tBu(Y~_Xzv^t zlmu{!VXx7KP?5nPN4;O)!J^LSZv&z74W9ZuA;XegntR^Ik7saGh@X`0X#XqWBSLx?Jqi~=aO;v=!n|v+atfC1NPxs^g+QhQpBjX-38p=2CZiu0_1?$;S5z-TC z*8%h0?C=HcNb>b&52*RD43&nPXPT5^%UDvqr^7cTHN2iiYoh7NcExND4p@Fved!84 zg__WEcw)|#r^^2bB>S6os>6m-f7mjlwoNSq*+2Z#3DBp1Yl|9oSAy#*?Kf`%fOAxz2%KxPC!~nc8YJ1P z{v*p;wbZ2DgKaO~`%fYEt@a#=@qnMmi%O1JKG|f zF>qnYaRmbOis^e4=$;X?7kpfss{0XO&ntach4ITFc$3}N%*Onq59+k{Tp>4U`E6x= z_5>bPg!6MMaek$`qTl-^(xYWok!3O`$Gy%Mt)sQUKCar|MUwT^ zm20)-i-=!``Z&Mm3ks(ZqN`>Q`L!3`3cv=dBIZtW#F$p4n`56t!C4!UG6f(ZHgK?W zF=tPq%}hG%g=BH_>>1OfjuF$4-jW*=>$579s^k(^g|gs@rRjM!qMBjz5YxW(z5vGS)yhm4%{2 zJK6!YJ6q9S*aXu3SerG6^c;|L7mKtt{*rS~2iIM+-Mj>(BY%cqF zD7ST`@^2V`aJv%<-`!cuVdU|#Ae_9>>|bUA7=Si5UkA85tp`c5S8~Ic!=4a#8Cs?= zG(~C?G-SvKcN<@b+eVSL1VM1A& z#HccNg22T>v(FS^b&>KZam?!4Q6KtB0HlVblG}>Q-kn{${l_e<4|)Cju#qTli!&E+ zm|wdV*o$p6{ltr+d5N1vCJHQGiQ>g7ZCG5(C zhkHlzm&@vHJvt*Y(XjpFufgF=3~aBm6Hvjxu)U7}QXoW+<=qr$V*S z_N=jHYKVl=OWJR^z4i{jkdvE7%}hNd^jT-BIjNYd0N;J$db)MwSvymNq^z0ahJA!E zz&_e-`v;H>u&1_~9g^&PDg9HCdeTO(Hb?m;7Cy36w>)S70H@{~r9jJA_GC(3lA>*1 zQ!MZ6%Bil4&)w?d7fWebt@uuJiGa7&r4nCI8VI5g4#hvto ziLu$xept`VlVH_jFU z&J~}T<08G-`!=0b;Ha|A^C<$zJ_My&;`BA-zJS_=hYFJe-P*Uo7i*M0w|HC82OgOX zc8<7$dgin^7xKe^_xUKP$#~Ke>@fHq7t{oGng1l4)1 zVDIdV_B^Bhm|E>&OL_Vw8*D7|n+AE8YkV-fZjxso#CrSbDWO<@=-pn8iuEa|U%nAC zx2@$NNMoVQyz>M?81!8mI5rStWbe~>B8V<}rC*kGhBSWJ5C!EH*fBU*zE&i31Ue-)hwaO7mM z>BB{2_OZJ1rM;@%X53nQKyjs7+ik=9Du)Jb8Odm7M``kZVNPX>3ygLj{Qe;kmL28= z1I~S<&G3N|@;J#c6hjEXjDi5W!ypq4E*5TC~E%SW#%n&#QigwlM%orDH z&FlqS6Dw7skBh^0rJ^#4P6=?FhmvW zWtiP(uIJl^=)vu~`!2!C`;54Lv!?r$wLoRMoth~j=+F?!?8EeZjDO&*-%$^sy8H>c z{J1Ao53(?56DCH-FaPM|g_JX@c^$v%yZ0=2|1r52P6NZ2{X<7bmGdUtU%RLXJzMNW z{a=lpi$Bxt|Hl$7|_+%T8G#jct;>lVJyJ}aVMZ_5_LjjRvf;sX>q%E$Om}H zl+;S6-cud?bdC3Uth3oyT^6 zsJbVn0}}PvSS?DxPsTFuuw08ZWaf)D=pOYa^n_et4O>J1BB}A-`7CZcVAp)lt3K@J zr&Y%btC%}RU#}c;ohTAvH!6#TSZ4-3Q7_>lpSrabG;O`6RPo-^;(;%|w9?oAZVqmw zq+B1B-v09kN7?uV!`vxdf~?m!5o|f%Dx8#^An;S6&~XJ8Pi3}KS;|nUbZtvV>wf6`)YJD>b}au zybAG;ZH}bJu$hP4yXvH1rFNR{;GXgY6<4NNN=KA+H@`^S00vpX)PEO&cH?KswR67Y z0t$m~=dP>hbl;+p?QSj`e(Br%y_kAYRi^@t?>Y+My43&381MB>FvWi^NbfpZm|Bxi z!CX%Q8K)68FOIZjp)=O++T+~(=X2d*<=w`~D8+`e!7R69wG^k{ujS`xvpfhjDA=08 zDt4o1Ia0kD#D-q+rIq8r8KesEd_gFA97cvot1dEE>KWhP7Yl3yzDw9$qv^UH{YU-8VU zgBNnE1fYa8Q?Pm<94oI0JUz}~A3rR0?L7*Rn4q5|z1kv$%9LJQZT{f?Wmu$QS}h$G^zh->+I%!KYP zGrA_aP(?|)@@CAsqRG124uT1gUnaT{eEBsynG}ROm5Fq6jlpLhZ>q4VVRZCDrnI|t zZtd!_uEwP3q|Fo;AVMybMLT@>LheTtI){(N2wIdqSNE}YdLeN+;EAiwW=OO^e9*vw z(VU{u9Wsjrb+1od!n(|t>^{!wGf|D&iR`0*iP9ydDH`fI;}5reP=y|93+gP+KIGhl zF0$i34$eS6GnXqHr*dIav6}_COTb$*aIz%t0?YhyXR6=bGiJTfq4{-`t~58Q6)h*t zjgpfk`hSA8TF~*W0q6B+rdyXXCyC~T@2>@rTdJmp1fiL!WmxUgL}13O?PM^zIPXyu zcA~Uv3TtF0OakKyiriLOEuPdN?al5s@fma$?^ZC8B*8ocapAQp{28mwuk|t;=BTi< z73w4fpSW+_KFA-d3TI%|DH4NS!jt9@o$HpdVU9>MjUjbO9T0Bdqa`!IlniFP7b?f33|J|N) zg69(*uu|G>20R_H>Z8U+u=M;%SdPon_TZa!Tb;(BtC3usT#S|(Psitt@EGAJO2tWz z@!qEwO4D{U^j39?s?BMtS2oVm7?$^%mOM!Y)kFyh?k>~qKEw-)9vS9Nu^v?LwomM( z6Wr>k(>*$Vlu zqc~p{`xM06X=V=b`Wx)|7pUK)e{=N?pV37Zse|JNXhg?Ct z8X(DQ--M9~^4A@h9KEPF`LXMZLP#s8o_`e9{Y@f>kV=%E?VH5ZO*>XdvTE{3a(bRF zgFxkZRl@lB-v@f#dH&kyi7op0zvZ4Z0=|P>3uCqXYj)VwI^w5y^Q)6FH!t+`$pj-- zh@16ENHLy`4OrV) zcAzZ|nnS_C&qm7X$NRf;kIh6Q0usbv5>y0~g3M?n^o1s}I(Qr3P#e-h5#p zPrLAy6(IQ}n~bC)tc)XJv^YqWXn$bUj0Oy-{fy)Z%Ay7K%nw>3Cw> z654pL?8@`LLi9wVxyYH;!*nK=uL$=kSwLew&zEzlKm(;C-5!f~>65l|zYLv)?^&~K zVPq8mTdIKgH7h>wMEBDZ@vpH%ZkStdOM=pQZQ-8y-r-h@Qf^H58owAOv{5$l8dSqv zyg(z~7Jv{KsTrr(dNzT>^^Z_*nFdKxCr-zR8{s0Y!eCDm#9mf@El)nF&z#=0w5GE3 zcU=3Ir8Raioc)tV`uwnHJwL761Vwc=sK}P~aYZaA^qp=<5#xSy9B6}-u9~Nonpl+S-OFjnGFD1__zm9 zN1}WQn!V3;8a8PbWvR`b%EDU4hb|CzE6t}wThf180?u%$-KCdxg7Y%40LUZu;sI`B z(Je!HhnWR6oD&cKFt9miaXTX_6ksi!i8p1kvau#32rHls>G7;EP6u{Z-4_|xCZxv@ zO`2s@qjldjdb2=x$9KcBcH~B<)LQ@a_#@Sr&!~9caFOwupA+T-ha+Kuccw$N0=+vD zP*D!+e-^B2UE8(B~Hy zzy7AhAO2jJqNClT%AE@gc-k3t^zOzd5@;%6XZv~bv=KHUfjfI^RAvhY?-t?d#`%EJr`w}Fqqa<4bo>DPYig|TA=jC8? zUSZ{9l0&msbJdD|9~c3S*L#%hP_`!Fa8)%0K;8-+HeUA|2!c_T97boN_!p%%`g8nC zk2#cagqm%qlx%h1o$sa@BlQ5Rb^LpU#ocRvJ95lS7~jSH63>l1gN(4(J2$O#fF5n+ zreB)D8IF$b)TzJzt6Q=s!1P-9==5=+QekS%3dfMg4& z^1+FL2us0LpRxo%aU?h z+>(@w74`^2687S@cy}GMBm0l53~3g!uWZAXf6vM~CLmsIf;tp~y;ic1GBfj8&f>H( z+@Q2fa|mURZb0sN{3RV2A4y?J7di^P$+9VYKLcuYWKCN3lPrfTweh{Rj76~qZ6dtr za>l%5;BQSRT$GHPyV3bUyQ{!;v+4u%Hmuo)6P+P$6jiTu@nxdS_mCW;r)7L%*L{d z*#Lwef4xDPI;jHKE??<8;{p^mjv8((9O?_HvoL*odX0|=Ij(%cbtk+7ljHu$&;uH} zm_e)m1Ky-d+GjheiR${LHtSr~ZR11X#&C^~C4|4ef`^(jRl@CA7m1&xk1J@MeqA9a z`pxwFo5)nh61FT{hRPS4UNJ@qjX?+DU<4S_sVp)#QM6D+a8YbEuN*#8RQvC@;OZVb zta1lBRWmq)GDL*JTcm=rb)?ph`K6WLsCxVREU5oBCTy4+-g_FBVhwc=W4=q@pN({o zwh;G=+nRj1_P!VN*nVK1?2_Nx3hUW&qDdgb;nNq@XtA_`?0^?r9G=*O{oAJ7h^IEX z1SXQ^Y|(hFYkCa9;x3M2h1;avNk|+&*@_0&D7#^z*Eg$@ALHG$ZirASZ*OE)1du%W zeFz_9e{bcVVOB{Up^qNg!A{Eow2ltfw=x}%c$6IeA(gK5?$_HjuJ};oC z0zwO#(cRJ((b-D1;6qwAii4@bt04$m6K64^LiXV^c@lf|(E!;Y8>*0xV_s-rG1kr- z=e=IP7>JPo*be`eG>qCJgji#j_PtB_?GVp7qKWFh=WL2XPx*%b)aZpd37y+I1FcOl zF}G%E>aTW{kNz*GZ_4=Fui^na%=hypYRaZWwb1&&+*V-WBeYQesqDyRUX`3O_BIz! z!tHZ?#zo%H?A~Pz7$?L7yjOLvV%0liN-PZt)Kc9f;*2fSD^{%#<74!~++Bp0gY7^u zimk%1(973jfXC$?CrE?d69}q@d=X`mmEzT(mSyAC4xRPLs;pP+GZ@}Ry3DK0_H)*x zNlyYa%F*#gkR1LN1MG%Sw(|pXk#%B zSZ5fRI1RPNO2cqJ7SONn8R&|pkUP1tH`j7XOksNo==nW+zb`cJM_JC151Q`tayh&w zI#*B5?}c?%_qpHKE(=1IVU~mHq5_SXY(3lC?JxO!l!3($`%Azo=jFcxHvt2@1B80M zd__cly+UInpGx7%KJT*jW)}6Ejr6Lh#){o|n`88bWKVn)m=3;efHmEH9pxdW_Me== zlb8OKuabjV-kb8(MF${8g0^uqeSf1%D!Y|~ae~mNT)}Ax_a&0{62SZ@e(4P^blJxl zRDm4XxiHmy3?h6LEoLyn9#_qT_%u&$P4*zFkdy@r{YQ)JMMzxL)0Q$?)LvjBqznuVeSslb0aWrI6whhQta+x|cJOAVa#KZhAv(h*1 z#WKFVm_;*yTV$Z5#qS4YqnJEbYk?N~Gt?*p50X0l${6TWN#O#z+ zaR#APMjJBGqCGCOy|3*tv4l)ib;ZuOlKp6R@r+C4x5k^kqP0thbrOv3DpriMR9`D) zHJqbYawADyHHbvgMPvolI9(FQdMC8#goXAUHS{2dD$zbl>E^?`x2vKkS}B|I%BSnx z#&aU0b)p5Lkxazqsr_oY#;(nV_j%aSDrDf{V@Zhq4Ab(ui4G-P$bz(TFD*}#XAl&*2K~0J_yM=+2b9a80B1L}#*_2Du1R{ii;P>FI^3Kxb_IT7X5^mQ zI^c6|kyVW@hA^jH9|3bxv8Ho}{%GCs2^CN()eaZ(Ieq2W!*0#7CU^;fs`DP4Uz~jZ za4X@6aCD7(;}qxC^0Yp_fw0QlX0uZ5MV#3$9iq1Id!%2x&pE*Ra!(;{=J3N2m zqpv3FwViu{Z+)kK>CV3PCVmWx{_#uXQ%wA^l_NuL`tSI;Cfn2u&W8g;yysm@2Vniy zG7MzQ4^>cd(AJdD^Utd7ky}ZA>GyG zbXjXF#SeAwVfes0hOHU7jWZQzfw)|>_DAK1f%QFZw|4$DE*g0ZXkH__r6D%wg0q^1 zXp;*VFnYcH;2j7+*<-{z2L85v`+BBQ1#FjD`U+u+STf>i0CveX{Jtw@QAXep*;2UQA@10B*816Q{B>#@A}t*b36rC-`#GkRuPvKl z&KAv@YAdfVsBew^e@j381iGZ5ZE3-oUW(h_xvL(eqy;~8@ysu-`oR%@XO=I1mmB24 vqv`+Mqy0nDss5#Z?tSV&xvfP!DE5lfRfXMIufTsy2>fDn;dJ4tYxn*K=`_{| literal 0 HcmV?d00001 diff --git a/Recyclable.CollectionsTests/RecyclableArrayListTests.cs b/Recyclable.CollectionsTests/RecyclableArrayListTests.cs index 6390a78..6fcc043 100644 --- a/Recyclable.CollectionsTests/RecyclableArrayListTests.cs +++ b/Recyclable.CollectionsTests/RecyclableArrayListTests.cs @@ -6,7 +6,7 @@ namespace Recyclable.CollectionsTests public class RecyclableArrayListTests { private readonly static IEnumerable _testData = Enumerable.Range(1, 20); - + [Fact] public void AddCountShouldSucceed() { @@ -28,6 +28,40 @@ namespace Recyclable.CollectionsTests .And.BeEquivalentTo(testData); } + [Fact] + public void AddRangeShouldAddItemsInCorrectOrderWhenSourceIsArray() + { + // Prepare + var testData = _testData.ToArray(); + var list = new RecyclableArrayList(); + + // Act + list.AddRange(testData); + + // Validate + _ = list.Capacity.Should().Be(20, "when capacity == 0, then we allocate as much memory as needed, only"); + _ = list.Should().HaveCount(testData.Length) + .And.ContainInConsecutiveOrder(testData) + .And.BeEquivalentTo(testData); + } + + [Fact] + public void AddRangeShouldAddItemsInCorrectOrderWhenSourceIsList() + { + // Prepare + var testData = _testData.ToList(); + var list = new RecyclableArrayList(); + + // Act + list.AddRange(testData); + + // Validate + _ = list.Capacity.Should().Be(20, "when capacity == 0, then we allocate as much memory as needed, only"); + _ = list.Should().HaveCount(testData.Count) + .And.ContainInConsecutiveOrder(testData) + .And.BeEquivalentTo(testData); + } + [Fact] public void InsertAtTheBeginningShouldMoveItems() {