From 86994bc7919c5d6ff48600fef026f33561df829d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E7=86=99=E6=9D=A5?= <617064818@qq.com> Date: Mon, 16 Dec 2024 20:54:18 +0800 Subject: [PATCH 1/5] update functional.h --- MyTinySTL/README.md | 2 + MyTinySTL/doc/MyTinySTL+泛读报告.docx | Bin 0 -> 12229 bytes MyTinySTL/doc/MyTinySTL.png | Bin 0 -> 113417 bytes MyTinySTL/src/MyTinySTL-master.zip | Bin 0 -> 132332 bytes .../MyTinySTL-master/.gitattributes | 63 + .../MyTinySTL-master/.gitignore | 253 ++ .../MyTinySTL-master/.travis.yml | 72 + .../MyTinySTL-master/CMakeLists.txt | 35 + .../MyTinySTL-master/License.txt | 11 + .../MSVC/MyTinySTL_VS2015.sln | 28 + .../MSVC/MyTinySTL_VS2015.vcxproj | 201 ++ .../MSVC/MyTinySTL_VS2015.vcxproj.filters | 162 + .../MyTinySTL-master/MyTinySTL/algo.h | 2744 +++++++++++++++++ .../MyTinySTL-master/MyTinySTL/algobase.h | 520 ++++ .../MyTinySTL-master/MyTinySTL/algorithm.h | 18 + .../MyTinySTL-master/MyTinySTL/alloc.h | 264 ++ .../MyTinySTL-master/MyTinySTL/allocator.h | 113 + .../MyTinySTL-master/MyTinySTL/astring.h | 18 + .../MyTinySTL-master/MyTinySTL/basic_string.h | 2075 +++++++++++++ .../MyTinySTL-master/MyTinySTL/construct.h | 85 + .../MyTinySTL-master/MyTinySTL/deque.h | 1426 +++++++++ .../MyTinySTL-master/MyTinySTL/exceptdef.h | 26 + .../MyTinySTL-master/MyTinySTL/functional.h | 285 ++ .../MyTinySTL-master/MyTinySTL/hashtable.h | 1609 ++++++++++ .../MyTinySTL-master/MyTinySTL/heap_algo.h | 227 ++ .../MyTinySTL-master/MyTinySTL/iterator.h | 366 +++ .../MyTinySTL-master/MyTinySTL/list.h | 1210 ++++++++ .../MyTinySTL-master/MyTinySTL/map.h | 549 ++++ .../MyTinySTL-master/MyTinySTL/memory.h | 208 ++ .../MyTinySTL-master/MyTinySTL/numeric.h | 155 + .../MyTinySTL-master/MyTinySTL/queue.h | 364 +++ .../MyTinySTL-master/MyTinySTL/rb_tree.h | 1738 +++++++++++ .../MyTinySTL-master/MyTinySTL/set.h | 477 +++ .../MyTinySTL-master/MyTinySTL/set_algo.h | 253 ++ .../MyTinySTL-master/MyTinySTL/stack.h | 173 ++ .../MyTinySTL-master/MyTinySTL/type_traits.h | 45 + .../MyTinySTL/uninitialized.h | 256 ++ .../MyTinySTL/unordered_map.h | 563 ++++ .../MyTinySTL/unordered_set.h | 534 ++++ .../MyTinySTL-master/MyTinySTL/util.h | 297 ++ .../MyTinySTL-master/MyTinySTL/vector.h | 936 ++++++ .../MyTinySTL-master/README.md | 101 + .../MyTinySTL-master/Test/CMakeLists.txt | 4 + .../Test/Lib/redbud/io/color.h | 351 +++ .../Test/Lib/redbud/platform.h | 108 + .../MyTinySTL-master/Test/README.md | 51 + .../Test/algorithm_performance_test.h | 108 + .../MyTinySTL-master/Test/algorithm_test.h | 1180 +++++++ .../MyTinySTL-master/Test/deque_test.h | 102 + .../MyTinySTL-master/Test/list_test.h | 118 + .../MyTinySTL-master/Test/map_test.h | 202 ++ .../MyTinySTL-master/Test/queue_test.h | 186 ++ .../MyTinySTL-master/Test/set_test.h | 166 + .../MyTinySTL-master/Test/stack_test.h | 103 + .../MyTinySTL-master/Test/string_test.h | 207 ++ .../MyTinySTL-master/Test/test.cpp | 52 + .../MyTinySTL-master/Test/test.h | 717 +++++ .../Test/unordered_map_test.h | 203 ++ .../Test/unordered_set_test.h | 191 ++ .../MyTinySTL-master/Test/vector_test.h | 114 + .../MyTinySTL-master/appveyor.yml | 21 + 61 files changed, 22646 insertions(+) create mode 100644 MyTinySTL/README.md create mode 100644 MyTinySTL/doc/MyTinySTL+泛读报告.docx create mode 100644 MyTinySTL/doc/MyTinySTL.png create mode 100644 MyTinySTL/src/MyTinySTL-master.zip create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/.gitattributes create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/.gitignore create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/.travis.yml create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/CMakeLists.txt create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/License.txt create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MSVC/MyTinySTL_VS2015.sln create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MSVC/MyTinySTL_VS2015.vcxproj create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MSVC/MyTinySTL_VS2015.vcxproj.filters create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/algo.h create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/algobase.h create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/algorithm.h create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/alloc.h create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/allocator.h create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/astring.h create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/basic_string.h create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/construct.h create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/deque.h create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/exceptdef.h create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/functional.h create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/hashtable.h create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/heap_algo.h create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/iterator.h create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/list.h create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/map.h create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/memory.h create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/numeric.h create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/queue.h create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/rb_tree.h create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/set.h create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/set_algo.h create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/stack.h create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/type_traits.h create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/uninitialized.h create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/unordered_map.h create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/unordered_set.h create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/util.h create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/vector.h create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/README.md create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/CMakeLists.txt create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/Lib/redbud/io/color.h create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/Lib/redbud/platform.h create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/README.md create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/algorithm_performance_test.h create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/algorithm_test.h create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/deque_test.h create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/list_test.h create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/map_test.h create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/queue_test.h create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/set_test.h create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/stack_test.h create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/string_test.h create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/test.cpp create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/test.h create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/unordered_map_test.h create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/unordered_set_test.h create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/vector_test.h create mode 100644 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/appveyor.yml diff --git a/MyTinySTL/README.md b/MyTinySTL/README.md new file mode 100644 index 0000000..fb400ca --- /dev/null +++ b/MyTinySTL/README.md @@ -0,0 +1,2 @@ +# https://bdgit.educoder.net/pfuc5ij8g/ciallo.git + diff --git a/MyTinySTL/doc/MyTinySTL+泛读报告.docx b/MyTinySTL/doc/MyTinySTL+泛读报告.docx new file mode 100644 index 0000000000000000000000000000000000000000..480511d65c4833bd671640ba2b60351167aa7f31 GIT binary patch literal 12229 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�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 o5cmBlzJ%m|6^A{$c6kG)FP~Xx5 zs)P8Sb*S;Fb}c{v0IQGy0Qmo@j?UcD#n8pY$=>fhMzi6_EqU_+?wqJdxwEhd{%YucOQVP&hxnz(_Y`2BP?~3y)C9~OE zrEM^Q#Ve8^j)OXYZJwQTwgmZh8?I!E5*I5dg8T`UOk!^9#u5WP%&G}*T2Og4Qaj|m zFjFIs1bFW$=w8ptB_@bjntKQh7k~vg&!Qo887*H>aBQ&7<=Z`Qee5cz&)YbS#7lxs6a_6e!w%D3OC7I)RuRo0Wp`&cTMRG9Dgn$mMG?VL8~O-fyl5rJS*o@IbrY^ z#?tCYbr6&WSR0q5yJVct^sGk>e4T{3yD*j4DD7hFlvh?B;>=9S`P|&LES|JeMP-@y zTJ)NfC95sUyaJ)4%CxQpqH8gVx}h!U<%F7TxF1h~o^hFsYsIZMU47u|O4qE2h2s3Y zn3B=(t;O>z3xtQ)ZtZY4G`*Uix3&&D{s_8GxplC^8tiB#yp(Rp=v8YrUrN2t<{_iO zm++`oIm5vQf^cuT$=k)l;IL!V#RCIzGhM~4L)qn2yyvj*~#&f5l{k7Y@ad??f|HWov@Aq@L zC*ov(=Cd4;SK%T|)%8~)W$SJzF|j(L9mQ|yg}hovH#t^_esr+ah_;=i2qv50P)n>3 zOK9Luc8L9ky5*M?0`8E}EMnfS-8v_FRP!}aC7xUv3Q=J2t}%X*WsX7Ka6fghcun7K zcBXa;5Wn}+<<&6C!~BT+%jBew4U~GOYVqj}BG>C6Z6LQJV>c??=JLo`MlSeI^HheE zm?o8)v+HZ;**0~oa`uC@LtBFEvUDYpxD&$~0`812mTPC2=cWzADhjFJ_93-cy~nUR zG@d$D?11eC$R7+H28LqI62c&{}QUVJRQnG8{TE||aB)@*~)qNDJRnG8>LE2%9}Bcj;4 zw3x?67dabe5VX|!1%pBOmQ87~y0xbCiQ9yl@h&_j=QH}>*WY?xpgOEhTf6Hnf?3n3q^}0D zE0HBG7_7CR4S#pWeH2oFQ~5BdAatd`v)#)L{(5$q)u>;3U~r?qRbF6Cjyjq+q`0Rv zKe1~?;2!o7;Gpt@VGdOn9p^vF(9%2&5*@`tTFW|2wl1^>q%)&leLBfD^GYz9^mRH_ zP4`~mP_&!+P1>)a0tUqazAmAwi__QCtzC?+%tlxLY+QV5 zWV8QKTVrINgDC0a>^E27YpOM`gTF)x4FAd{^3E3;b@0Ax?#au8%6#$OLJ;A`%ih)B z`31J|*~tFHqHs$B%^7&CfIUM$ZQP2$wX2!Hc1I`_Zqi6d5@5dM zj?eSu%^}P;q*{3&3W~37yvkS3QL(aD}`s{Ohh_r@D*3&k!S@}Kvrz=Yc{&< zONY+Q3cs)br|421sEOSN%nCO2_uvR%+oXPAJpFUmx?ang0LgH`@j%Hi z8c&}2R&1k&GJPmt&h;=@K02EOB-UxD*^TS?V9J0MoIy~wiP6?xIBsUzP8RK~;uz7_ zSwwgn6!x4YRGFiDvBJo=rLREvX*A?oQk|?(rL|6AbyMb~b38QP=-o*B3B>rzF%1`% zGYj<{qb=q*xPC6BAI^aKGGjIQtP~oRMvvQBx8ON=5rp#As+eh#FQw}NA5$J8ddM6O zlISZ_hDLw&%4i_8(B{+~AT?kob?a@CQv%KMM1h5tURw*Jo3p%GzH;26^h`@?g}lTt zpMSZ4+~YVEyG--!XC9!0f=xtk6l{$d+)Mibsw%K_@6hxYZ*nOFC=;GWw=54Plo$`D zG2?N6h2IYYC73^>9o;qc&3h0*z)(+_wmr)&M{fGtSm_y4OJn}G2aF9ye3k0w)!2lkf`j#6!f7* zJq7IO#P8z zleKqtY@-(DwSB$YwNmiK)Awx#clb{$emhZ-tvDP%Ln@WIjjBvTd^vaL6U_K5I&Bu9WiPTZp7T$lQtztAX8e6<3VbKD#aSw^>_31#4_AqE&DVL>_-XQ}Pq^aL<8|Z*;Rle^<)O!{ zq818M;|I z(|Ow3{7YMBRb-`s84><*lrYt2g(j*EwKPuzqrnB}h?Eg2ESal?8z!^jl@Y%?Hk+Hg zS_t=S^p9qGcs(M}%@Ia{s1s#|R}hCZSqKM*O+5V}s9f@^4EU+F0|(k9;Zc+ig+cp8 z@V7B5L>yY`Faa^kiiX-i4h?-kvSfA4UAs`dm+96Q)eb@6mekul?N?YM;G0H}&}VcH~Rh<(J)xjCk>j zp&s~hat1t^F%Kq#Ke5q+gmhrK=)wNSMjjE-hHIk@Z)Wb>8vTz+Rg^27Bi5FvFaBl3 zu2Vm90KA`i$nfSwDQM z34H|CUSeTc$SHwr@j+LETtJ-*d7J3}y?w>{=`+~>%mgC;wC_L81j4e0)}}I+&MwY$ zE*>ub>R_vito^0{0&loJBM~QtXjurAl4>RR8pm?w;If{Umlo{{R@*c9j&6BD#P6lrP-K%ZF!bgc(Y&BtTaTqaZbv?^ zr|)feu@s+NPXf=m%)<<7rUr*J;jnHE1@@eouYu?a{!Mp6vcy-*8<2Ti`O^vC`|LTA zJ_#{8MHrDqmXs=P9dh9m2a z=eoRdL=SpTk+8xaC!WtH;$P|^)VtQ+LH`|KD6cJpz5f7g0_4B&gN&uIshzXwzoAQ4 zNjiR$0ijQQ^OxbUg}QY9WnRjgIa0GGjKpb1DUOhFL^XnVOLL_EcHKlj6=DB=<`rw) zs{_l`3U_-A{_be&HDCY!5y6?N9TTZ{HRqHkOA@1tva;`eqFL7}88uVqea6KEMKj^@>ehHNi zPsKk$*<>OHP#qrzlYW3pr+4TH+!pBQS8TW%(HhFM4~ct-vH=MykH0yDjDeUm&m8e8 zL*rB%aD7mc>?NT-z{LA)wuuDjqkO-GhVXQNO>~N4RRgVjE5ua3VWg90+Zo$-elA{jhicfoZ2RP58g<*rXSj$*2D#uAl!b z9;*LZ{IC5VeKln!21ZsoXB)eJ5p}7utbLFG3Qu=`(0sJ4NpmzcT{s>{A+LpTRO2|9 zDeD%2^&11$*6(g96j3Ao1*F;T6~pZ{Fw8p*T4YA~R0w${K9yb;s18LQL~}~Cgrnz# zRuuJNDLpHVoDE1TlPpcO$gj$6X&~2joM+4P7;vj9pgpp@cn9!W z^Q=_Y-_~4VN>Sald79-`*2Np6*^Bndzgiu}8FZ|X!hEXxB7=kw9x$WJ@Pfv_Pb8$u z?9qxFL|KobXrG)Ip?+NH!qN{4)fuQn^A=AVEZROcFhtZRpNZvTiREF(`Wh2oA-HlX z3au}`RY3y6fB7ag<9#hI(wB)OsT+UU={4LyydSu&&HkXb^3k(3G2wwB?3f70GJEQI zF0a-%R*`qjS2%@}SIXVKKs6iJZPi#UQN3Aj@nmYuUe&YGvMJPEMvYRMoBvdh}KrY;AC(0uU=nkZ8;IKBly0m zD=5nu@@EXPHEv*-S;MY7g6dE0KSQgg%(E0+%~+@{dJt~-XyQFczK1^P7&357+?To? zp{vI(mv^6@xkwv*z2^I`?8@tuJAex@-K@m!C~Z&#hQgsbI|N90 zaI}t`jV4EHX5*;*V4I)qV`6v{)VjVeO4XQ|1;yYkz`0hJaYp8G`3U5QD&~RBwE5Yq zR};XJzI`#4be7_D^&KEv3s#tyQJDS^o`2>qLk4{WG48 zzbi43lZc|;dg)vU6=}M&zWuQ-(KU&xcyzt%xk`Z5r!Vy(J1H){NRc63F`n9#8HFY9 z=uF*ix24bCzKFg~w|Y6+$)~`wC^{{;SUL^sR?eq^@3Uvf;-#mc#)3O+MC%%s0`#$94V@X<( zZ3M}SXwGhY8_?%Fk>IAZK4aQ1nwm>5Ep@4W++)>c52T8C9-ZWhJE7bRea>|cBYW#b z3mH_egV#VJlziL+cm&tktP5&$&}L9?kIy%K4ue7S=zfR);EoTuqmF2sBU^^%f#I|s zr9e|^MhA((P-(LEkoXIwof)v5lN4^MSrSE3R{1ACyEHWIcWkMj{enGi^?Ys*URwIk zkKvOu5}5Cyv(=DxwrBnw8p!~tJR`)HGA1V*pU&?Tv! zdj@*x9ZQxa2kgzqOyI_eIzVjrRes<)K@+C)^D-?Wp55j3-5M74M|XU9@;`WDa+k7X zk_0=eHQVLy8L2ctRZ2*T-iVgIe7Q36zpdD_!QIQjd&W*j&z*L=JPWTyec4j{E6rP) z$TjO`4D+N+v~tDR`9R-*QhNl04a21zX>CmSjr7Mj;!l`TvGN^2Iw>DQp65ZJq1gv)NQXc+3KY{`d$)>ww{JPo%ynPcEHi=G*M8ut4h`f)-`J?98f*T6TtRf? zl^DE<0~Kt6Wv)~v;Dc(0&G^!S;No?SMqfqRx?;8h-~dQa{SAg?K-lE(C=RX)#zbS( z7hhZjxs!O{qN&zJ5E^pbSte9F2CpHA?!vfUGC;Zx9T`^yz5O5qEmXu-9oztnr&Ivi zh`%49va;^)MRRp4kWZJIvcB6nAcj&G=Nw!y2;lO3ZD21qi-qc`F8PMNbZnm0F7e4g&Y`6G>)b$sUk_`!e&7`P|y1! zyCwXlkY1U_>ykPpsyADtIH~zxTuU$7gN1*m_>9>cxa7_w5L= zMF(=jPJXPHR+7!H&x7q(r17psgrU^OR(+PYhw=g%D!mKj;>u@3I<-u~x-$Gr_pmcE7s-%8bO7`Ji+WsApvVsNBVNA$#h6f(>{5k8*>uvGS11N6DKU0 z$FG@uKmJ#|o;R?2AM--oD<omXVI!k3I+GwHH5=Q4++^F8#-Q9I@n)J`;@|e8PW=$M3zDcubW+YTU zk)|sj$s__j+CNA8KAl>4mM)^y?k>2sZroa|Ds8RUIX5wH1}9?AS^ShdTDfJ0U0F#> zEb)>kWssBKB!q%^VCI%M$Aea`B@Q<%&Qm)FA_?q42B6mcH|@<@QXP{%+2cTiNt<`Zd?G;MmofEoMqPlza#{ zhi~{`-u8m=BnNZ0YOmXeiVaBYSZZicNQhy=xYgW_5#u><~FK> zF#C)u16{KM!QzGkM9lle)|S;^@rRqwv>Ab$0>w|Tcz(37Mq|kPQou$&T4ViV!S0)k zE9t(|wU=lbvEzl%>KuSepaB?su$KsrC~xq8q>N*;J331!$%w{hK;weF>A(pod(!3-IG=T}klVJ^YjS=I(XQ&u+$2rn5@D72;SyBsfwg;E z5kLGz?pc;kTxO(3aeK z{hwz2KjuXLvfBU6u|wf;pD$Aa00eLW0ucU3CivfBExnM=%J=>kBEf!XoxB2n7ioSmC1rE*kCcB)jYpg|FZtw<0I02JC*tEo1b^pW(bwbMu! z+Dgt)#fi?>)!qo>M%motkU^1-_@w zuU~P+|C)aK_1v%a@;A3qy3}c|a_6U{iCO#8Zco2QbE`-5`vxpe*pG)j*)@0JUWqfh zjG2s|%3Jv+WBH6cbKB&=rtJ9VXFr&B zkNG66jQNO8#&KV`C2mmeyC>K%W%6V(6!J^^`A_poJ^qj55OvxVBzZbz>e0`a&T}-a z|92w)>+#zZvj2_L^=J3EI$YJ~Yh0dxctCib3cqe8jtvL%yUe|kSJ#{i;JzPyA@YDrEyDPYf6s(NxAt{KUMc=2r&E) z?4LJxi=kZ(D>gQVHiZdAhY=6s@E~EHfdEO1+|reC#5o-EA_W&C;`t3u$0!#p$FQ)8 zU=FJQY|c3LgAuuizD7Y0d~$l+^0PGaC{J^uWa>`hvyBtLADCc!ll^~!CSrd|C{Lcx zp*;_!Z!g?tY{I0q3?T@SE=fXHNRSA@LU<|WT=E1T!do^v0V;0ldiqd>geTOF#8?6nU`rJ@HS5pzui34itLWlkZt>T&YVCa7-kzWYeeXu~ zt+xs%2aV6GNaYN-=uD?Vj|&tp;AH^d<(sSJJX*xrAKB+IH~Y$?nRS85PkDA-Fob3D zhP_F6x!$rv$_!UM-)+nj`4T;Hi2Otwpm*->4U-wYa6WzDFH}FNF1GJ*I=Y+ZRDO(cABQ>725kSBd#vu#gE{aafqxa5Gk|cp-N%vE8 z%q@iiD1d*I?|4wf&v^WvJfF{b{SE8ex^zE1+N&kL`$G@^Szlg4%B++sTq%|>T4bRl@fEXYLnVC+5lVpjQ0$*a}@@BnCoXPm^##AEW9$P93 z+Hj`ZXxLB|>x#>G6roArn6dC|e9AOk?@T{DK63uaM)pd?L0s?LQU#Q=9;n56PV4wC zX!uUjp{!U7`6c_4rVsVeB_WH6b_3!NHr0My^McHX&c3z$QmT)*okE-V-_*S#Ajl)w`S_y2ukVVdv?* zpPX3q!6u^W=bVH5(yNb~N$h$#1@|E$2lfn+?g|mks>yR(SMYUKac~Q2515;Zgh#=4 zOjXj&KZD;Fhg@yUd9|P3)<1``eFp&Cq1os|4+gZ2_xHnl-{Wgv;Q3Ed@{DPGu`kh! zVIo$H0|ms)Y|Q+};sycxfjK?C(Lt2-w=qSul?0wEH2^>bE?}?~)j^E38w8RNQuFWt zlp9yrskRW_a)tK~a}C3g2|UjjsZe1L>-8=M@@!dUclftSylLidN+7`!#RgURi=9xy zrckf`>nk`0+jW6Ej`MC6U5uCY^+dcRZXyzjwl?bgd!t$xo5NFcP&xAp&d5v_?P@7vFKaGk zJbrNYOO3%u&Q6=u!NB~wb23~6o?1KRnD{p9BB_2wTGeTFZKPy1@}U|*^ags1GNL@keDo;;pOyH@k!Qc6H-!m(_h5_x8=FI5X2f$aY3hMAhJN|R^AA)Byg`CV5T4*Q zN_{NXhX{p5-V3y8I=e>8I^!62A$!OM^^O! zat5$Q0$Y$=K0)wUz-0yWBX+G6>qQgqMU;wy;vbZ7`caBE#mO@!^hvPHEfO5V2i%sM z8~frzShh$PvJ($sI2JJicfTAE(}*MLGae_46i_WSN^#)DD<5C<^2>-Xr>)1 zXAYE;l+>D^RN>)}t05VhG;}`_qYS%RO~2hm$Cn(%dc39h9jxyQU=jc#ek~waZ6Gpq zp2jr5)cn1TVL>B8_92}Jio7m!J`kk+?2}phDQl$WkeO()Jh6T*F?mM_%q6EUHyXs@ z1P=oDB~O|Vfgv`;egS}@@dOeVgdkx!>^*gqOV?RUM@q>v`sv4pW=S!Gw1cvdRg!=aRsUD4Rp1Q&Q!B=8)3vm~)u zBI@9o(9rNC=sPeWIRKOckaj&h2rs zo`usy(!+|j$Tdn9Bc$k&bvwV4c=IvcA5U1KWk(k*CFl`w11U!IcX{))1yK~co1MSz z`P3-@8!zDC&0g_+b-t~Djdp6rCp?Nl$tT0x@4_?S4g($UO4Ls$qcTf_D5u_Y+s;k3 zyE`18gxr(yQ%;oWx~g%pi0Dfmi4b)OiT1!9i#x6bqHqBZz=+EjE_CK)D`q!27>047 zuET4cRw4Io@%nH{^h3IJ4t(1)__Q+`#nYUL6+^ObYTmZ2U*4Q(JC^r)h_*r;7S+DD zdN0P3E-=sEh$cTa4+EhgU>Ex4_aS+|7vRr=;YT10|8DyzK%kG}l^-}~ZiBpdcOGvB z@g!5yXU}#b=^iPLA3ypptYKmsi(k&m@@lNTbj_0pek{S#CUUo2R^X5h&5+==44Q}f zrvw0m*J1y1!z3Sp{{TAb%>%NxZmKE~)aR;1W%{%+q|U{}cb6)W1ikZ~7cNA5SR_Py zj8=$xA;oG0ky|FfK)PU{RWv6=JiWImL@<*K_6srz_$KF$`y%tui_eFte_Md7&W9j<@~`Wke1E5NVTaISNkTg z!X{1qNo;pD5x0I=i|TrbJfh?BHZLp3Za(-1k52^ry;#3x#%p!$$?oL)J@K= zFa4HVoAx-1O)M>Z@m4pzq&Dtv&sXUpu)my$TRpZ1`Rqk?+!p=(t`Sdyi}3zQ?KSmx z#EWtBLoquJ&d3)I^SItf>hHrzy9qS`9W1WlM^fXSgj%?)PBXV)V=(=mtv2%8h`!z} z`7Vs~#L^L)5bgYN6pqjaMr z9K|o#u`>;K2A*~uBSI{(o+@ee5yw1I>Me$`jl=i7vF{(*JI1!C)h!uj+_tdiEMdNy zdd|ZIrw+8}eqBxJDPz`iRIx0~NwD7YTXEZ|=;aRdLhYS&KB3!;+u;e-Wm9| zW77BYYS@yz*X2pD!7Hbf`xWa9rG=R#1>y%uP&L*;>VOcdzFFlIg1SIg9zQ3c>-G^s z;qbGuio@qyHq(6wb&+a!d)R5`oeLdn;dzaw4erwW656-+26r~o1%o}Ax$3^zkF3`g zhXtI=$8^hdNeR86Sv!oicm$5)kc{oDLcU2YUCy42CzNHwoUsC1&JVg)&W!_G&=}-Jl*8{(@TZ35Mm7+?$ znAxnlmrJ5~Uq}df8JZ4&9hp@K!EE{!8N8A%!6MG^{85`XIs!oMO zPAT%D;`Va3FuLREXnGq>`{jKrg)q5=Q=p=u_RSmD!WelaF+h?vo+YS)9yl@{q0)Tj z=oIq9b#dH?DDa~&nH=*ej&a7X!2OoZ@)ch|Bs$LwCft8bawL^DSxAUsD?&=CI9FjC zG`yW~VMIiA7t9{HGXi?x1WE{rijONK0san*(XB#}wqs+m`l61OAWO*H>aobZs`g?U z(_>&-t5b!WfG|Zhs(I@-R4Om0LmcM=?h?Wcdbb2(TZ4&H0?dq#RVA>R>)jR$%zAjT zc{7NC!rF7&uVk-mw>o`1D*HY)heX0c@Z6Di00X7FYo3dVy^jZ-p&RoHJBM|@IW6TM z2p@iw-BBp!n9VT``T@)v6gKlV%pUBa{G#?q?74xs@=?UQE@1?7ryq+XpTh<53bSZP z!*7AHt3M-&3&uZQ3?dsEC%oz;mAN9YPJuSjpt#IAS$szdN-LqC!b0td1GLu$g&OT% z3t9w~LK)It$Y0jnG4*6Z0$|yLCn!m*>20yB98Lx#25oCMvl?bXy~;&_!vJf>C(+I6 zJ{6jjaxlrBA$*7_*Z95f=suK2RKAmtwn+CW!26GX-g`67!xM7+wNwMRHroXJut*9r zvfTGdb}kl_U^7H%0d6Sx&`jeMeisk11E)-nc=JiVYVBRMzZy+rTG77(y+v>r{8bO^ z#R@i&--w=z1Z@AaUj5`}h6Q&i^^_y^$Gf9{%E$UATJ!gwHAm9sR?zjt?|Kd{u9RHV z5i|S1z~>=O6b65f_tSieT%qZ3w*l zl7|_OGr4U=BBk@VTb|4`ga~O%5hZC|4ph!}cvMSZRthMIBOIFpQ(v#@w_m$k-Nh}R zxQqNHFTUS7|L38_0ryxz1?MLjqz zS;fz&HH6v%Tp$g&02+c-KAOlzg#bi21^z0}?s+B_b(eBzw4GNEgKwn6<qZDVl#3i121+$H-mXAy1;3oyzOs@T2(eWH|?*y z#0t3}*`AZFv?iv|7O@%4gqi49xDKxz;+0nB5sIn>DM=ok>>(xR6@KBm6%A5N~M}ghGv-v);VrS8H)8i%0JyE+n_Od2l(gAip3>d zOO0f(plY4#A)BONVN+V;3w9LB)km2uRp)Mv;sEIpuS!%%BIzLa0%Cd)RmgRbfwNMc zIq+_yD>d4(Y*;szDJS~O=FzieWmJn3myHYyQwzyo7)$WgpmmXa-SyNw$mi*+Tfi3D z=ZMc%nS|8?pg3)?R2&>pgKNYbRB^R5Jmd~f{p5Sg>X} zmthov@zFVp-$%&ud9@d@QKocU%O&mI9!Q@*#VUWg^*;oeH0)^#YMbq#fY4IwLYx*o}Qx`7aVY84+=g^=$=%Ev|2*q7AkPIPvW(?yO?gdfiFb1}y6T#Ofw9z{`E zfbu`v7Y-!9nw8CUiGG(^6a%zXLtUcpk_C&8NC0z6a|IBfvO{Qd9Eh#ewV^?qIwt2h zvdIP&Xn3xr=khpL85{AqOACKEWy3+K1h>hiJLJZAv1CZiNhH&rg-BR9BxH*``S@B$Ncj$X ziq0jJmR}IKlhRW|#qE8V?EZaL^*^z4eGK0`^3@6PwLE#7{sbPX{qob2{&SRI$3p`R zAu=CqtX=2}WHVj+*7Ko|{PK1OyVX1U=dUd% zgc92R7nb8(nk5za1IKy2L#BDo1SL8GXKXDc7ugB!m@?;#yl8Oh@tsC&M=4+oExG|7 z9kV{xpH54g-t>7I2*SUJacXN?K6gC- z+;&Gj#r{t`OMmg54hM+kxQ%h*l+GXENujVvnuTe@6{8W)LA`>~=<{^&7`k8-8yet* z%K;LLJQd1(wwjzSnk4k<8%krDtfp5qGr44ai&j%B2NVPe>tkF5Fw8zbxXgiIH?t6B zXDHAGO{m3{(Vp5!7(IsQ*eW<%T?R`TwfWx$48qXRF+3MO0(I--#Z6w*O^b!L^<{08 zW?-cP&}B#=9yoQ6rRr6t4AQl`QgRJ9Y2{{9BvYCtUPgkh2*>iubr^}StE<<(N3&bM z<-eXs`?|1;#u9$zCK(85Ide1L3p%HX09^=+rc%Q}3DFgZ&NoUV=~ol?a3;$ok{xXLxm$zV4~SY-2@A0@+2M2ga6oJ2hHi*A*# ze5I6bJ3b+kx|mRN7y`A-ougTzqIDhyl*}zlUyRVMyTF5h9%(JJjy1k9US>yW-903F z3SAT|P4t~|nnl^211nj%Lps_dnP`)i(I%UeFtU*`JJiH+`@xNYwl?z~>%e?+7{P=g zKcvo$TQJ!I=_l~Sw-LwH^WLH#!&)UKMLkfGvsx$4_j275VFn;wORm_fCP%=yc;%@gG-4=Dq>av@`tISI-9Z{9bXV$)Si3#z+dPqdk=7<%STv(v<k+JO@ikxbq>wcS>=rOBX*vU-qZuSl23V% zf;Hltj~L{qsb!GV(V;7-j34bXo;tL!9?sDH-1hfW=IkByMs)&&ErJ|<{+nxWqODef zPkaz2mEFs_D^_P&hR${A6~z?ooz0L6m-&~7yQ3|QecX_dJFiRKYzUR61#vduiKh@y z!h`if{-R((k&lHUwyaTWJIun*-x~cw|J`|SrEd%UmAHU)jfrSEz*|I~;5x9Ml_v%z z;*oF(wat0v@vR`-7Z2_M2cGbUCmJZRztStsIB#4|bpyacJQiJVqxWxpy^*Tq5OOL8 zGsYyt5S_DtC&oI@gdA77B7a@}#U{h>vYz&%0*F|JMdY3q>Ed0Mvu>g0gkm6=Btn1PgxX}2Jxd69P#+|0-~`>hnX)eUDDh;1R*p%cA;PrkmOeL^PJzREwg+qKd*7Dxf3y30!cz}Z zIsJdYNvZ`wMcA!>;CT}Y2@gQ9&R=^UI)`L9ecjBAhG^S}&lJ8uGKFo3jsqmWnMqGq z&Blc%5EkRYMFcqQIY+k6oYK`hRhj>6($i}iC#4vWEYk4u6`NQQ*h}4b5ayTGi)2(b zZIf`TE2_=PYri>-yz-GxEr@j>+Y%dLmBiZMV^X*==gHd9W0M3YQ&-+YHbm7%gan1AGd|hNa5k;H6yHkRpkX$p_e9cu~_^<Gb^w=a zHw_10?S9pvi-?qj01GE9Oh$4S&+=_xEuOD7m5~NFU2zv;NeWz6s?u$hNGM}#XNZ7h zmo{luHoYr4ow{jKpeHZZFPjik@P`;C*-2nZg7-kM>-d|z_XK~P^7?Nx+UTUPl$d;F z@cjhbuC|1(vE3enjlfd9(lWG)YsB(wR zx6gn$YyvF@3xdwiyl{4m?(@?flwSYutE^xkNVB-JnmzMNoi7R37DP;-EeWOM>%!yh z7r4GUzqhB0NBFR!S^R=BlRt=Z23PQ33Rt#XwjxL({#@Xo_x78wi^oPYQ4MsIz*ShB zH~2n4YZ<+TE(z`%Y82zvJzMfdC-N$IeaR`gt}# z&dyFyDHyJMPVYF*rhbHL_HO-Mec<(b1J^J3r;rvfopz($xz}P6nbh^1ohhecNKB<3 z`YUHZ*?s3)yP}q9pqBFpBikoXfmp+Vwv!fyZZo3F@w4e^1_#1clVoA0hdm@)&_w`rdPgw@R8#xY2Gu*R@C@+!QLwSl`wQ6j(w^CnTGxu`x^ zdoNb~Lz7ofd91Fg_DpJ+r6w{&XpW*vQX`gd;6W#1(&G{;Fw^qcJOcU}pUs@GP_|_8 z!i#WGH&OJGUURf~A28g*xyt|i^EhIR4DjQI26XaQGCj$wl6pJewdM1TK{ zv2m)JlAG0*|)eX1}A9^2Kx>YfhW?-(6V zLSUgy!5n7<>=JEwL8has6BFs_+lRxZ(D?cTl~C<&-i`(AGo*#-mn_daP6F*pWR>!g z`ez3QiS^a$PZ~&wcOouza3OdK&9CDm5y5;lE4gIHW%+4ikzXeTh6t2yJNayxd{@g) z(WW5KtKK{A&oSuyMVmj+XvA%j*XP8^{QdNwVjNS$FM^p!2)T*oFBZndK+12^IZs`5z zhG}5@#**={36$wi$dnl$u<7~+o#1J&I6Ehy-@bU|rA&1Q4&kMOXZi$|NO9znE09M|7C-M@meWudbx`W~NRj25)UA{1I=P$F|* z=+LH~U3p&<=3fFpL<_Z-SuAJj_?qOLxSe)OSErYoQKR8ms$wZe5V>uAMmWKfkGBsO z4sc7zbNOdIj?f{9568jtf!qXw50O?wa=tdwIpAkzPv7L8&AU5R8FuFYepkiO=W*_x zz2BW05eBDWDTqqaT+63V7dh>xloLsAF9LYSHEIzNIwDA5{r(4I@4zDp5N3(CZS%Hy z+qP}nwr$(CZQHhO+jj5W%)Vr1-sa6q{ev&5$~oUbDF-((HKB-EmK+;gg)Du{Po^ee z`fdOGRQJA~y{&K<@J%mMdp;#kL*qjycth$9_$NiVsiVWdOFAY82$yhC{1`)>S4;7* zjCG$pv6e$Y2TyUzM0AzNCSEy#DB%4iKtMZDPzf~2%bAxXPk}o$rdo(wgefnG+8Ar1 zgdQ$Tb^KZG#YiALJ>Hh0zdp7{+Av!PnA7QlsMj0EPmU=8#KKD|-clVLeDgn=_B+@N zTfcW4?-WSo7|VDZjs!QLin3b?ENN!tHw5?>d6O>XkTM4lyvA(KDIsC^*tUq|hrlP} zy~n4_leBj7pQf&~k)H_pE1l57hYp-Iv5Q(&KF|6ImD*(rf3w9PLzH^7*6=x8h>enDs#CFU^0%yQ zQ9Cxm$$Z?q<(?{Q=wRKZ^(BVSh6NF$@0XOlzR^WUhs(-_Y8l%RN~bDmFUe3%cZe^*pUh1N5Q9dtPoPXCTNhUZ z0tN21ooaM19dvB#{bE%EBK<-2?&~0ebq+Tm|42{*;J)C8H7Xgupt8p`fTqZM-JPQF zS#fR5qK~XDqSNyd$a(Y^i^|QP5oF&-C?QZBUw1qrzzXO-!RqM`N{hwKHfKnneWh?L z4JF;Z5Oikvgtw)$xO33(sNZ7oH!xV<<+C7H;NL#qERK`X6{WNSd-2{p%zehphjunP z9EvCZUzfONL4_V)@MW@lctyOms3Mq%vdAU?Qs7DLW%7vo^DrAt)9vU6 zTUu_=h<+b@+EU!7Vu*3obYV}H6olM7AFYZ*Rm)u^ovo05JK@mM*N!$39qud~6j{D&KAi&A|LxM~ zTYN5*0Qy_L$+IdoR8WXEVggBJl?W!XvbZg|CFv~#=>OET8?LAUch8R|UI{}XY!#OE zj*kjVppB1+qr#V%=4XpYv>?(oP#8#ld^Q1SjQ_;BL5WNuv0yZ-@`9)0q9O+@WE@iu za(Z^B@=PP+1t08y9gd_h@wW*vGsOZ5txe1atmp4x9Xk2RW*Ip~h(FU;!*$9#D(>q> z3UwI32Eai_9BhRKQU|SzkTE#((pZF+p zxr*03q0E)1hD9B#Qb=%0)Om*#v`cY|^iX!$Wz9u!R%Ap7>5~52z@KNKBW-VFV*n z1-7x_F3jt(*rGS|j#k9fScXG0&Gei*p&ASyDNHeZN^OALW_Lv#Wk+TJz`u<`pkeNd z6i8}DDQ!`&L2W+l1~vBRAMh|;$I^QnC+E9aKkgs9zW1O0ttFA^O%bq`8eA`uxS^20%d60h$U;xC%u|sMM2+ z-%2(TuH7g#Gu9%G>JR5SelP)wa=y?zRQ34%P{ibowuRu4>en3WJZIJ)y*=xeKDP%Q z9aN^p)bCPh6VQJ@hKr9(%VT*z7f*A&yv}3Gc}odT_o&sAv9_YM+5jv<;io3xS2nOe ze_$P7tCeZgC26O!G2=3qU_q7ebXs$+)+%W$d1*FlZ-og@jhL%Z7?Ch!E<;Ew4-2(6 z)z{;g=Ep31)7d7Q(O}j2sS%Z@#69?>B!xVWu!%E;2WP`|MQ2c%?77H*)xh|Youn4M!1QZw@(E7~t{)(nnh0KvuX3-GuUj(SeL)R~Uv?Jsn2K!bG zf1b#+vnVtC&750m4m7v4-p<(Y>{YF?w$8XcsrZ|Gagx>jwZi44wE3ZWeOJ@`(Dw0A zte!4lqxrSc)9PJe$Xukwj|h8YE4<_!hZ9}&SYhLLiLX9IgRSq z{)y*#Jh#&UZEduxPWP(%Ef_dEiuVHmDkKfXz2HOYk9Um8YJpG(kP+{DS8C>t6rRVQ zW<~46rcYR@KPWV)U+_dFl@asQM%S;M^d|^%qJ!eQLand9f!k1JC2!R-G;6QrM&4)6eiI~W^dfHS;*56{P3 z4^IInRHski@@UzyC?Cu#WMqLd`z{uWIn)V*!Ky2OF^Af*f&wWdV>`5mHcA~8Vma?-OYWRj^wg=qpaj>V}+!{cC+&Ug?SBS}_V3vBB|yvpxKd z-B>0#I32{~0+5;9Qza&xm%6|H2NqQbg&h~!aa2QT@AIMt9BbQ#_CRqmUgsfZW9DYE zY+~9!rAZ7T-Q)1Xa7F6@5oiyh@;JI~W9$^6q~vtFb7YnHU~vUrDj0u->f6Y!^jwr> zQ9QC^Tl3T|u{4TlBF}4UA~ZrA{8RLyJti*cO`){?syl)wPXboRHX;Hh9Yj`&ng~vn zT*82Q1N5H}8LRbQZ4!7no9AiSKVm5LWFGUw;)VdhoHVWW7(1x?4_Ci{$LZ<(? zg84fszOwW761pQ3yLNArh>T0mG^?ivF!`e>?12bbGbqm$!Q3r^JHBE%vT0c~=lZm)oa)m$`sR217OJ1F<4vMc6+dA2Cq$YNP<(7sVard8;Lj)Y{x!72e0qt6s)Tw zls}UoF>sGfQS1l(z$=r<7qThLX+kRX5id*1AsEA|H8QSTK`V`Fe8iNM-R#ukar1k$ z!pD@bdSL6N>Rmu>n8_jem(Wc?-fLex1YE##7U7in@1xZ?ETnt?+&k*GN6i|HqRS4f z#iUwTaQV6yhd+O95fYyd?uGH&4Z*(T>nSp0bnq!aT(8^hVpt8qjo?YURtIS_swu8h zEzKFHC~CEy;X)B(6G*l#KWkr}jL;SYNn)6Jl5E|m*p-`1VH(oxU)i&-*6)IA&sdMQ z;6`-JEN|f8eFa!{s?{{(61WIJWAithe)3gzX2-VWT(8zuYF6ERAXJwwZ{MieUNXM? z3f`|IHi;w7_u6SOUGWvKSO}ni8G9S7i%Zx~yw#Lk#%z%$Z1EumA2e zq~vI}PKr5|N(qgt_wOW4;*4@q&+Vr^x(81!8(SON3IE>P_68jfIkjbv+^ zY^@`cbUCl2{Y5N%1)R)hqH8E9kaWJcF%vEyBtyKcoMAL+1CGAdxQF2Z z!ZgfIBhh3!rWhf1QdChvQK({ZwVgKrap%{+mR7%fTv^e1MVCV4-I+nYf6l_yRjyI^#4?+liZ80FhahXi7; zL<_k^iqRuNE@P~|M96K2_bN`AR*|G?X_IsRDMmE*wD}2;NLpk)6E>*R_pDs4~#RxMCU{Z={u&B^YUV|ajp^tn+u0FBu3d?%~25@)FQ9Z`X+;KoQ}u(YfPv! zR_bjAhcW>Rd@2T|@=&mc2Xcd~|ASZ#?@6PGN%E59FKU`a>{6bVHjv&71R`E!02i`-t0MBCnfVAOn-(j)+6=1`8!~PG&hWujgH%9w2Faz zTgZe;eK&fs6Yi*F*VE2o4;iKfqjOj_C=L?1W!}G-xiG!}9E?0Eot|@CxOx&Of#}k?rloD!D6a6W9l} zNcuD8?qu@lhx0lIa;#Q=f|#PY=P=kh_JS?R%a?u&L0)r_v&`>maekoxD+=C*tm!@c z*Iw!Iuh)R|e@4L$=1ykT{|N?r_Ima@m}uxoSY!m)8ikeW8rg-(b`{2U`o@`th1zzB za-}lJ(J<1YrZT1W^bACPGv;2YJv)u3m@aPQUhTXzl|G*bEz7zzQyi(Fr5=%U6PAJOKJ?RKziOjf;$hWWT}RJvTWyD}XwkEiEtl$|z9T&8 z_OUUg=SP-AyYQhaF7Y6P`(|g~{cX(6HYlWKCS^%Je7<<4(32-ie{dxhquJdoQC8nv z9Y4dL-+I^^W#Jo~9M?0(0O5@cQOL%wQ)n}K%m`P+Mzp*H;XlqJ>HCV?35b6E;JE4F zV*MkFfNR^V1nRcpzMq)6F+ebm+}MnG{?M7eMjet^dg$2EyRJ-suD^o6zQJ=&a5br{ zNWA_jACee6d?FXjn#R?`!a&;(ZdP?f?v_x&h zXA2voz#+#vy9;hTs=7m>rMuLDPEsmP-Ma<13wkX z=R;q879uRhe2-q(%TLcfV(L81K!dmpCzf#NGMBmLj2a1*>@|%V6eiNmTL*OH05{=} z$($^HX96!y$H`XPk2{-=MtplW{q<{(V~tUb4jf%Mz^JItrH@clu@Bn};PI5l(h@BV z#BtOdi!w<$8+o+7xSXGkG-To&*^e4z1ps-mGe_^(5{*D~Lc z_+)UT-GY}qd&k@skm#ucz=4X2BAQVeucrFrG$lG@0YLSh8`_|aZ>%c%RKWlW#^fI#V`=Nh zxaXjOejx#~`OEO(=gt126Yxf|g#MyG2KGv$IS1na6D1&tAN=9C<5#|2fj~Am1$@d$ zO=7F&P7@UB!=fh(5+ubzKdRJm#H>wvRDQd%guyo%8}+R_^m3!lkFV!v$Q!=+1;GfZ zb(wk%ML$}Yu&eGn$(ZxVlFlK|aRx1$^4*m&nW$Iis7Rt-*2nlkPUc8qheKFn;&aZ# zJ`7GwTf7e(5#AU`(xEBPXLPP#E`(gE zcoc&ONN}r6@et{j{&UevM<#yfHvlQ;9xO=LU#N7#2`MQj(?6ajCJ8)Qh3oALc4(Q4 zk@OrqhxZT#QE9ukU@S%M#Heti3HL2f7-UAu5dCU=V{#yIq;dVQ#DI1ZT!2t2^8D@l zioZX(L%$f1d3#QjJlKsMz=;^)2xS9ZSp5DWqi_pH^F;bt!^s2tud1u?D|Xvw7wy<_ z@yjYNq%|Z8`Yt7|$g~Z6?5Gf+$m1?DwS$_=MBY5`Dl=^6bh^m|HjwOm`y_Os-EZxW19) z)uIU+Twrur!Cu=0cd~H#u`hSjHal1}HTcex%x}Psq@#@jC4f^xOq`ZSqIMC+oltPJ zSJ2qj&|92-|MIG9E-7e$Dj1{O;3?_F%#efH<#9kCpggEbeM?h)vKDPqixN}-F~Cz% zc)*5ZsS=qf_n3}U!yTmiiJI$o)JD{|0?e81Fq|@#xFPE&XsmT0qVGuHRy^F=_VD&C zy#-V6KCT1keLk*zt^y4a3{uZI5(8}Cy7H=ky$!%_N)v2?oF@L!x^sIX^`Wk9(R$y2 zsW~=<8;LNCi3sa|t(0j;iQojW#2aI?NPHhx*#2cR(`8?#!85%O6X#Vg@aRW%G;DYH zg#7_jQ(_Z`xU8c-WZ#z#r6yESvb9+mooAK*h!OMNv*-c@K}l(S0@NKRL_&-5V3O~o zJT8m1VXy?`>2`>fEr^aLEG>HWv}ZsAn}Zl;t3CxV3b#F`T9^fWnh`Oy<(+|q@*w8# ztk720uPv;G6;P)13F->tYI#d9nzIse8H1L2@R-cF=5PR>k={&5TN|9$5)rI0EyuGj z;N$bkef}K{1yewm7~XGPqo3n_boJV#4{TQpu9>qB}u^JA{NbrR3VI#Xdu48mb2&0U=0x>F1;+Y=Ji`S)aA?FHjz z=r~$Sy=A9OJT8)9*D__&DivObpOo>r3nCDEtL5z zyfm?2-r1y}e#zVfuB&LsG?BvYU?+Fr*I%($kC&x>C&W*|obDlZECWa^Ckm!=i1 z>rx^R+rc8@m{kaE)dsXQl~jCYE8lUEl%mLaS*ZA@ae;t8}tTPbIp z^a>UkuG(IzQJw8mDG{0V-!z``&ij7X91VH=fo(E8Z5ib*gB!wIFAH|65+HI{R|_3v zZBQh3?QNck6Vjja$E085eZZjcNfXpcDUD)$`0~f2mISJltRiAWUl)tbpV8npB{h6~C--B0n7ll7I-E^^a+o&L(zCNW>4~Pdt+%Z5aE6>D8V1S~`pLFey9?oWK5Ks_ zqjgR*TiZ{peXnq<`$~FuUv`~7Lvg9FL(0ddnnFi2zq7x0Vo$#VU3@*aHFY0(x-V{P zJY-kEEj4>p|G=~4d~o&xoOu8EIIM-l^|o@TxkD59+G4Lj96MED)JWU~87PFV*9=U+ zlLc9)o`dc3E7>58CZGmnQio!iQP|;ZV*R-t8Aj~NgaXb7Tu?aBYE97J!a9+avwFks8iqV*4^QXndz;HQ);idfPA z={lvLbTcc;D-!n~CdI0UR2GApE$T~*aC{QgV=#ci6T#7(QgN1s=J!HP5Ms-Rf=f)V z3EC;-i1*T`{EHN+50wYftam}FA|4e;RfqpjL?rPhFw*AV03ixkTolqT9}|x+O{%8T z->9ublX@TZ-B+$VF(}Um3dvBlPyq~S^0$-8UTx7jG}-OA9}xJ6A+Feo72sf{M*P`= znVs*uUgndC~zxnkBSY7tYZ$pZR)@o`i8id`;zrnBisI(_u`PDZmd zkaAyWwYqh+zcWIa0_CqV&TlHJs;2&(s){OKF0ZdF?$ap^$GzoM_*opc@45ZmWnHiR zxhctK!BF@a9Jlr#3GP>%FDp(Jsqn2HZ@tU==jYE~?5z)*!;SXmP+pMK88Fozjb2}@ zo~^d;^O4b5)?ROj7-p_c^;fS|mzY9{%-dZZ-@Bca(pFYmZit>Ay~i2!%hz8pXs}$Z zspFi+Y!gfK6(B_yY?XSfNapino6Xj(kX@J8ncI{d8jVQn*P;&_n{o3Gmre7grPmc~ z>B_^wo%~hy(t0!ZY>`EvNHXr;WX=9Am$|lV$I@hOEOMuby=mE?pGd zz~U_+swjM*a;h{iWaTfLn(F{B)TsUdz160&j9hXh{(7;?!d?SJ72;&ANnHnAzFgU3 z5RMk$Oj}wPtQup!5-p(p)MO;VDa0~`CY+!}A=Ic?PLd#L%->c4IgR|Vbw_;OljMGs zE8$@M$#@)E)no@$tr{Fk(a7usPPTkk*@4dWo2)6x*~T2(i|kD%=UZhi44=l|VcxE+ zP+>mA7bgp>egNB^@ZWsfy-^^3DWD4=ttKo%iYQoO)G8THj*vW=!J1C#;BXr$JoHVn zs+v!XU^)Zf0b?k;D-5#5m*F|=0oKZ6^)^7EC5okz4S

Cc88-y$#7(eUKv3(NXil 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 BWkUb} literal 0 HcmV?d00001 diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/.gitattributes b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/.gitattributes new file mode 100644 index 0000000..1ff0c42 --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/.gitignore b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/.gitignore new file mode 100644 index 0000000..9de2987 --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/.gitignore @@ -0,0 +1,253 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# Local build files +*c.cmd +*a.exe + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +[Xx]64/ +[Xx]86/ +[Bb]uild/ +bld/ +[Bb]in/ +[Oo]bj/ + +# Visual Studio 2015 cache/options directory +.vs/ + +# Visual Studio Code +.vscode/ + +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml + +# TODO: Un-comment the next line if you do not want to checkin +# your web deploy settings because they may include unencrypted +# passwords +#*.pubxml +*.publishproj + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignoreable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Microsoft Azure ApplicationInsights config file +ApplicationInsights.config + +# Windows Store app package directory +AppPackages/ +BundleArtifacts/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# LightSwitch generated files +GeneratedArtifacts/ +ModelManifest.xml + +# Paket dependency manager +.paket/paket.exe + +# FAKE - F# Make +.fake/ diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/.travis.yml b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/.travis.yml new file mode 100644 index 0000000..b83ac2a --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/.travis.yml @@ -0,0 +1,72 @@ +language: cpp + +# ubuntu 14.04 version +sudo: required +dist: trusty + +matrix: + include: + - os: linux + compiler: gcc + addons: + apt: + sources: ['ubuntu-toolchain-r-test'] + packages: ['g++-5'] + env: + - MATRIX_EVAL="CC=gcc-5 && CXX=g++-5" + + - os: linux + compiler: gcc + addons: + apt: + sources: ['ubuntu-toolchain-r-test'] + packages: ['g++-6'] + env: + - MATRIX_EVAL="CC=gcc-6 && CXX=g++-6" + + - os: linux + compiler: gcc + addons: + apt: + sources: ['ubuntu-toolchain-r-test'] + packages: ['g++-7'] + env: + - MATRIX_EVAL="CC=gcc-7 && CXX=g++-7" + + - os: osx + osx_image: xcode5 + env: + - MATRIX_EVAL="CC=clang && CXX=clang++" + + - os: osx + osx_image: xcode6 + env: + - MATRIX_EVAL="CC=clang && CXX=clang++" + + - os: osx + osx_image: xcode7 + env: + - MATRIX_EVAL="CC=clang && CXX=clang++" + + - os: osx + osx_image: xcode8 + env: + - MATRIX_EVAL="CC=clang && CXX=clang++" + + +before_script: + - eval "${MATRIX_EVAL}" + - $CXX --version + +script: + - mkdir build && cd ./build + - cmake .. + - make + - cd ../bin && ./stltest + +branches: + only: + - master + +notifications: + email: false diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/CMakeLists.txt b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/CMakeLists.txt new file mode 100644 index 0000000..e4c8662 --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/CMakeLists.txt @@ -0,0 +1,35 @@ +cmake_minimum_required(VERSION 2.8) + +project(MyTinySTL) + +# version +set(MyTinySTL_VERSION_MAJOR 2) +set(MyTinySTL_VERSION_MINOR 0) +set(MyTinySTL_VERSION_PATCH 0) +set(MyTinySTL_VERSION "${MyTinySTL_VERSION_MAJOR}.${MyTinySTL_VERSION_MINOR}.${MyTinySTL_VERSION_PATCH}") +message(STATUS "The version of this project is: ${MyTinySTL_VERSION}") + +# build type +set(CMAKE_BUILD_TYPE release) + +if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -Wall -Wextra -Wno-sign-compare -Wno-unused-but-set-variable -Wno-array-bounds") + # set(EXTRA_CXX_FLAGS -Weffc++ -Wswitch-default -Wfloat-equal -Wconversion -Wsign-conversion) + if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS "5.0.0") + message(FATAL_ERROR "required GCC 5.0 or later") + else() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") + endif() +elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -Wall -Wextra -Wno-sign-compare") + # set(EXTRA_CXX_FLAGS -Weffc++ -Wswitch-default -Wfloat-equal -Wconversion -Wimplicit-fallthrough) + if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS "3.5.0") + message(FATAL_ERROR "required Clang 3.5 or later") + else() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") + endif() +endif() + +message(STATUS "The cmake_cxx_flags is: ${CMAKE_CXX_FLAGS}") + +add_subdirectory(${PROJECT_SOURCE_DIR}/Test) diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/License.txt b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/License.txt new file mode 100644 index 0000000..aef65ba --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/License.txt @@ -0,0 +1,11 @@ +Copyright (c) 2016-2017 Alinshans. All rights reserved. + +First published on github, see https://github.com/Alinshans/MyTinySTL + +The MyTinySTL source code is licensed under the MIT License. + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MSVC/MyTinySTL_VS2015.sln b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MSVC/MyTinySTL_VS2015.sln new file mode 100644 index 0000000..8c22749 --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MSVC/MyTinySTL_VS2015.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MyTinySTL", "MyTinySTL_VS2015.vcxproj", "{E88807F6-B07C-4371-BD38-FB1569F894E4}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E88807F6-B07C-4371-BD38-FB1569F894E4}.Debug|x64.ActiveCfg = Debug|x64 + {E88807F6-B07C-4371-BD38-FB1569F894E4}.Debug|x64.Build.0 = Debug|x64 + {E88807F6-B07C-4371-BD38-FB1569F894E4}.Debug|x86.ActiveCfg = Debug|Win32 + {E88807F6-B07C-4371-BD38-FB1569F894E4}.Debug|x86.Build.0 = Debug|Win32 + {E88807F6-B07C-4371-BD38-FB1569F894E4}.Release|x64.ActiveCfg = Release|x64 + {E88807F6-B07C-4371-BD38-FB1569F894E4}.Release|x64.Build.0 = Release|x64 + {E88807F6-B07C-4371-BD38-FB1569F894E4}.Release|x86.ActiveCfg = Release|Win32 + {E88807F6-B07C-4371-BD38-FB1569F894E4}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MSVC/MyTinySTL_VS2015.vcxproj b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MSVC/MyTinySTL_VS2015.vcxproj new file mode 100644 index 0000000..aa70a5e --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MSVC/MyTinySTL_VS2015.vcxproj @@ -0,0 +1,201 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {E88807F6-B07C-4371-BD38-FB1569F894E4} + Win32Proj + MyTinySTL + 8.1 + MyTinySTL + + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + + + true + + + false + + + false + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + + + Level4 + Disabled + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + Level4 + + + MaxSpeed + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MSVC/MyTinySTL_VS2015.vcxproj.filters b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MSVC/MyTinySTL_VS2015.vcxproj.filters new file mode 100644 index 0000000..aea4c50 --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MSVC/MyTinySTL_VS2015.vcxproj.filters @@ -0,0 +1,162 @@ + + + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {ec314ff3-dcde-4cac-a63a-4f6827750d0a} + + + {c6f24d77-e6f0-439e-954a-c0ca577689d5} + + + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + include + + + test + + + test + + + test + + + test + + + test + + + test + + + test + + + test + + + test + + + test + + + test + + + test + + + test + + + test\Lib + + + test\Lib + + + include + + + include + + + include + + + + + test + + + \ No newline at end of file diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/algo.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/algo.h new file mode 100644 index 0000000..b9d9660 --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/algo.h @@ -0,0 +1,2744 @@ +#ifndef MYTINYSTL_ALGO_H_ +#define MYTINYSTL_ALGO_H_ + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4244) +#endif + +// 这个头文件包含了 mystl 的一系列算法 + +#include +#include + +#include "algobase.h" +#include "memory.h" +#include "heap_algo.h" +#include "functional.h" + +namespace mystl +{ + +/*****************************************************************************************/ +// all_of +// 检查[first, last)内是否全部元素都满足一元操作 unary_pred 为 true 的情况,满足则返回 true +/*****************************************************************************************/ +template +bool all_of(InputIter first, InputIter last, UnaryPredicate unary_pred) +{ + for (; first != last; ++first) + { + if (!unary_pred(*first)) + return false; + } + return true; +} + +/*****************************************************************************************/ +// any_of +// 检查[first, last)内是否存在某个元素满足一元操作 unary_pred 为 true 的情况,满足则返回 true +/*****************************************************************************************/ +template +bool any_of(InputIter first, InputIter last, UnaryPredicate unary_pred) +{ + for (; first != last; ++first) + { + if (unary_pred(*first)) + return true; + } + return false; +} + +/*****************************************************************************************/ +// none_of +// 检查[first, last)内是否全部元素都不满足一元操作 unary_pred 为 true 的情况,满足则返回 true +/*****************************************************************************************/ +template +bool none_of(InputIter first, InputIter last, UnaryPredicate unary_pred) +{ + for (; first != last; ++first) + { + if (unary_pred(*first)) + return false; + } + return true; +} + +/*****************************************************************************************/ +// count +// 对[first, last)区间内的元素与给定值进行比较,缺省使用 operator==,返回元素相等的个数 +/*****************************************************************************************/ +template +size_t count(InputIter first, InputIter last, const T& value) +{ + size_t n = 0; + for (; first != last; ++first) + { + if (*first == value) + ++n; + } + return n; +} + +/*****************************************************************************************/ +// count_if +// 对[first, last)区间内的每个元素都进行一元 unary_pred 操作,返回结果为 true 的个数 +/*****************************************************************************************/ +template +size_t count_if(InputIter first, InputIter last, UnaryPredicate unary_pred) +{ + size_t n = 0; + for (; first != last; ++first) + { + if (unary_pred(*first)) + ++n; + } + return n; +} + +/*****************************************************************************************/ +// find +// 在[first, last)区间内找到等于 value 的元素,返回指向该元素的迭代器 +/*****************************************************************************************/ +template +InputIter +find(InputIter first, InputIter last, const T& value) +{ + while (first != last && *first != value) + ++first; + return first; +} + +/*****************************************************************************************/ +// find_if +// 在[first, last)区间内找到第一个令一元操作 unary_pred 为 true 的元素并返回指向该元素的迭代器 +/*****************************************************************************************/ +template +InputIter +find_if(InputIter first, InputIter last, UnaryPredicate unary_pred) +{ + while (first != last && !unary_pred(*first)) + ++first; + return first; +} + +/*****************************************************************************************/ +// find_if_not +// 在[first, last)区间内找到第一个令一元操作 unary_pred 为 false 的元素并返回指向该元素的迭代器 +/*****************************************************************************************/ +template +InputIter +find_if_not(InputIter first, InputIter last, UnaryPredicate unary_pred) +{ + while (first != last && unary_pred(*first)) + ++first; + return first; +} + +/*****************************************************************************************/ +// search +// 在[first1, last1)中查找[first2, last2)的首次出现点 +/*****************************************************************************************/ +template +ForwardIter1 +search(ForwardIter1 first1, ForwardIter1 last1, + ForwardIter2 first2, ForwardIter2 last2) +{ + auto d1 = mystl::distance(first1, last1); + auto d2 = mystl::distance(first2, last2); + if (d1 < d2) + return last1; + auto current1 = first1; + auto current2 = first2; + while (current2 != last2) + { + if (*current1 == *current2) + { + ++current1; + ++current2; + } + else + { + if (d1 == d2) + { + return last1; + } + else + { + current1 = ++first1; + current2 = first2; + --d1; + } + } + } + return first1; +} + +// 重载版本使用函数对象 comp 代替比较操作 +template +ForwardIter1 +search(ForwardIter1 first1, ForwardIter1 last1, + ForwardIter2 first2, ForwardIter2 last2, Compared comp) +{ + auto d1 = mystl::distance(first1, last1); + auto d2 = mystl::distance(first2, last2); + if (d1 < d2) + return last1; + auto current1 = first1; + auto current2 = first2; + while (current2 != last2) + { + if (comp(*current1, *current2)) + { + ++current1; + ++current2; + } + else + { + if (d1 == d2) + { + return last1; + } + else + { + current1 = ++first1; + current2 = first2; + --d1; + } + } + } + return first1; +} + +/*****************************************************************************************/ +// search_n +// 在[first, last)中查找连续 n 个 value 所形成的子序列,返回一个迭代器指向该子序列的起始处 +/*****************************************************************************************/ +template +ForwardIter +search_n(ForwardIter first, ForwardIter last, Size n, const T& value) +{ + if (n <= 0) + { + return first; + } + else + { + first = mystl::find(first, last, value); + while (first != last) + { + auto m = n - 1; + auto i = first; + ++i; + while (i != last && m != 0 && *i == value) + { + ++i; + --m; + } + if (m == 0) + { + return first; + } + else + { + first = mystl::find(i, last, value); + } + } + return last; + } +} + +// 重载版本使用函数对象 comp 代替比较操作 +template +ForwardIter +search_n(ForwardIter first, ForwardIter last, + Size n, const T& value, Compared comp) +{ + if (n <= 0) + { + return first; + } + else + { + while (first != last) + { + if (comp(*first, value)) + break; + ++first; + } + while (first != last) + { + auto m = n - 1; + auto i = first; + ++i; + while (i != last && m != 0 && comp(*i, value)) + { + ++i; + --m; + } + if (m == 0) + { + return first; + } + else + { + while (i != last) + { + if (comp(*i, value)) + break; + ++i; + } + first = i; + } + } + return last; + } +} + +/*****************************************************************************************/ +// find_end +// 在[first1, last1)区间中查找[first2, last2)最后一次出现的地方,若不存在返回 last1 +/*****************************************************************************************/ +// find_end_dispatch 的 forward_iterator_tag 版本 +template +ForwardIter1 +find_end_dispatch(ForwardIter1 first1, ForwardIter1 last1, + ForwardIter2 first2, ForwardIter2 last2, + forward_iterator_tag, forward_iterator_tag) +{ + if (first2 == last2) + { + return last1; + } + else + { + auto result = last1; + while (true) + { + // 利用 search 查找某个子序列的首次出现点,找不到则返回 last1 + auto new_result = mystl::search(first1, last1, first2, last2); + if (new_result == last1) + { + return result; + } + else + { + result = new_result; + first1 = new_result; + ++first1; + } + } + } +} + +// find_end_dispatch 的 bidirectional_iterator_tag 版本 +template +BidirectionalIter1 +find_end_dispatch(BidirectionalIter1 first1, BidirectionalIter1 last1, + BidirectionalIter2 first2, BidirectionalIter2 last2, + bidirectional_iterator_tag, bidirectional_iterator_tag) +{ + typedef reverse_iterator reviter1; + typedef reverse_iterator reviter2; + reviter1 rlast1(first1); + reviter2 rlast2(first2); + reviter1 rresult = mystl::search(reviter1(last1), rlast1, reviter2(last2), rlast2); + if (rresult == rlast1) + { + return last1; + } + else + { + auto result = rresult.base(); + mystl::advance(result, -mystl::distance(first2, last2)); + return result; + } +} + +template +ForwardIter1 +find_end(ForwardIter1 first1, ForwardIter1 last1, + ForwardIter2 first2, ForwardIter2 last2) +{ + typedef typename iterator_traits::iterator_category Category1; + typedef typename iterator_traits::iterator_category Category2; + return mystl::find_end_dispatch(first1, last1, first2, last2, Category1(), Category2()); +} + +// 重载版本使用函数对象 comp 代替比较操作 +// find_end_dispatch 的 forward_iterator_tag 版本 +template +ForwardIter1 +find_end_dispatch(ForwardIter1 first1, ForwardIter1 last1, + ForwardIter2 first2, ForwardIter2 last2, + forward_iterator_tag, forward_iterator_tag, Compared comp) +{ + if (first2 == last2) + { + return last1; + } + else + { + auto result = last1; + while (true) + { + // 利用 search 查找某个子序列的首次出现点,找不到则返回 last1 + auto new_result = mystl::search(first1, last1, first2, last2, comp); + if (new_result == last1) + { + return result; + } + else + { + result = new_result; + first1 = new_result; + ++first1; + } + } + } +} + +// find_end_dispatch 的 bidirectional_iterator_tag 版本 +template +BidirectionalIter1 +find_end_dispatch(BidirectionalIter1 first1, BidirectionalIter1 last1, + BidirectionalIter2 first2, BidirectionalIter2 last2, + bidirectional_iterator_tag, bidirectional_iterator_tag, Compared comp) +{ + typedef reverse_iterator reviter1; + typedef reverse_iterator reviter2; + reviter1 rlast1(first1); + reviter2 rlast2(first2); + reviter1 rresult = mystl::search(reviter1(last1), rlast1, reviter2(last2), rlast2, comp); + if (rresult == rlast1) + { + return last1; + } + else + { + auto result = rresult.base(); + mystl::advance(result, -mystl::distance(first2, last2)); + return result; + } +} + +template +ForwardIter1 +find_end(ForwardIter1 first1, ForwardIter1 last1, + ForwardIter2 first2, ForwardIter2 last2, Compared comp) +{ + typedef typename iterator_traits::iterator_category Category1; + typedef typename iterator_traits::iterator_category Category2; + return mystl::find_end_dispatch(first1, last1, first2, last2, Category1(), Category2(), comp); +} + +/*****************************************************************************************/ +// find_first_of +// 在[first1, last1)中查找[first2, last2)中的某些元素,返回指向第一次出现的元素的迭代器 +/*****************************************************************************************/ +template +InputIter +find_first_of(InputIter first1, InputIter last1, + ForwardIter first2, ForwardIter last2) +{ + for (; first1 != last1; ++first1) + { + for (auto iter = first2; iter != last2; ++iter) + { + if (*first1 == *iter) + return first1; + } + } + return last1; +} + +// 重载版本使用函数对象 comp 代替比较操作 +template +InputIter +find_first_of(InputIter first1, InputIter last1, + ForwardIter first2, ForwardIter last2, Compared comp) +{ + for (; first1 != last1; ++first1) + { + for (auto iter = first2; iter != last2; ++iter) + { + if (comp(*first1, *iter)) + return first1; + } + } + return last1; +} + +/*****************************************************************************************/ +// for_each +// 使用一个函数对象 f 对[first, last)区间内的每个元素执行一个 operator() 操作,但不能改变元素内容 +// f() 可返回一个值,但该值会被忽略 +/*****************************************************************************************/ +template +Function for_each(InputIter first, InputIter last, Function f) +{ + for (; first != last; ++first) + { + f(*first); + } + return f; +} + +/*****************************************************************************************/ +// adjacent_find +// 找出第一对匹配的相邻元素,缺省使用 operator== 比较,如果找到返回一个迭代器,指向这对元素的第一个元素 +/*****************************************************************************************/ +template +ForwardIter adjacent_find(ForwardIter first, ForwardIter last) +{ + if (first == last) return last; + auto next = first; + while (++next != last) + { + if (*first == *next) return first; + first = next; + } + return last; +} + +// 重载版本使用函数对象 comp 代替比较操作 +template +ForwardIter adjacent_find(ForwardIter first, ForwardIter last, Compared comp) +{ + if (first == last) return last; + auto next = first; + while (++next != last) + { + if (comp(*first, *next)) return first; + first = next; + } + return last; +} + +/*****************************************************************************************/ +// lower_bound +// 在[first, last)中查找第一个不小于 value 的元素,并返回指向它的迭代器,若没有则返回 last +/*****************************************************************************************/ +// lbound_dispatch 的 forward_iterator_tag 版本 +template +ForwardIter +lbound_dispatch(ForwardIter first, ForwardIter last, + const T& value, forward_iterator_tag) +{ + auto len = mystl::distance(first, last); + auto half = len; + ForwardIter middle; + while (len > 0) + { + half = len >> 1; + middle = first; + mystl::advance(middle, half); + if (*middle < value) + { + first = middle; + ++first; + len = len - half - 1; + } + else + { + len = half; + } + } + return first; +} + +// lbound_dispatch 的 random_access_iterator_tag 版本 +template +RandomIter +lbound_dispatch(RandomIter first, RandomIter last, + const T& value, random_access_iterator_tag) +{ + auto len = last - first; + auto half = len; + RandomIter middle; + while (len > 0) + { + half = len >> 1; + middle = first + half; + if (*middle < value) + { + first = middle + 1; + len = len - half - 1; + } + else + { + len = half; + } + } + return first; +} + +template +ForwardIter +lower_bound(ForwardIter first, ForwardIter last, const T& value) +{ + return mystl::lbound_dispatch(first, last, value, iterator_category(first)); +} + +// 重载版本使用函数对象 comp 代替比较操作 +// lbound_dispatch 的 forward_iterator_tag 版本 +template +ForwardIter +lbound_dispatch(ForwardIter first, ForwardIter last, + const T& value, forward_iterator_tag, Compared comp) +{ + auto len = mystl::distance(first, last); + auto half = len; + ForwardIter middle; + while (len > 0) + { + half = len >> 1; + middle = first; + mystl::advance(middle, half); + if (comp(*middle, value)) + { + first = middle; + ++first; + len = len - half - 1; + } + else + { + len = half; + } + } + return first; +} + +// lbound_dispatch 的 random_access_iterator_tag 版本 +template +RandomIter +lbound_dispatch(RandomIter first, RandomIter last, + const T& value, random_access_iterator_tag, Compared comp) +{ + auto len = last - first; + auto half = len; + RandomIter middle; + while (len > 0) + { + half = len >> 1; + middle = first + half; + if (comp(*middle, value)) + { + first = middle + 1; + len = len - half - 1; + } + else + { + len = half; + } + } + return first; +} + +template +ForwardIter +lower_bound(ForwardIter first, ForwardIter last, const T& value, Compared comp) +{ + return mystl::lbound_dispatch(first, last, value, iterator_category(first), comp); +} + +/*****************************************************************************************/ +// upper_bound +// 在[first, last)中查找第一个大于value 的元素,并返回指向它的迭代器,若没有则返回 last +/*****************************************************************************************/ +// ubound_dispatch 的 forward_iterator_tag 版本 +template +ForwardIter +ubound_dispatch(ForwardIter first, ForwardIter last, + const T& value, forward_iterator_tag) +{ + auto len = mystl::distance(first, last); + auto half = len; + ForwardIter middle; + while (len > 0) + { + half = len >> 1; + middle = first; + mystl::advance(middle, half); + if (value < *middle) + { + len = half; + } + else + { + first = middle; + ++first; + len = len - half - 1; + } + } + return first; +} + +// ubound_dispatch 的 random_access_iterator_tag 版本 +template +RandomIter +ubound_dispatch(RandomIter first, RandomIter last, + const T& value, random_access_iterator_tag) +{ + auto len = last - first; + auto half = len; + RandomIter middle; + while (len > 0) + { + half = len >> 1; + middle = first + half; + if (value < *middle) + { + len = half; + } + else + { + first = middle + 1; + len = len - half - 1; + } + } + return first; +} + +template +ForwardIter +upper_bound(ForwardIter first, ForwardIter last, const T& value) +{ + return mystl::ubound_dispatch(first, last, value, iterator_category(first)); +} + +// 重载版本使用函数对象 comp 代替比较操作 +// ubound_dispatch 的 forward_iterator_tag 版本 +template +ForwardIter +ubound_dispatch(ForwardIter first, ForwardIter last, + const T& value, forward_iterator_tag, Compared comp) +{ + auto len = mystl::distance(first, last); + auto half = len; + ForwardIter middle; + while (len > 0) + { + half = len >> 1; + middle = first; + mystl::advance(middle, half); + if (comp(value, *middle)) + { + len = half; + } + else + { + first = middle; + ++first; + len = len - half - 1; + } + } + return first; +} + +// ubound_dispatch 的 random_access_iterator_tag 版本 +template +RandomIter +ubound_dispatch(RandomIter first, RandomIter last, + const T& value, random_access_iterator_tag, Compared comp) +{ + auto len = last - first; + auto half = len; + RandomIter middle; + while (len > 0) + { + half = len >> 1; + middle = first + half; + if (comp(value, *middle)) + { + len = half; + } + else + { + first = middle + 1; + len = len - half - 1; + } + } + return first; +} + +template +ForwardIter +upper_bound(ForwardIter first, ForwardIter last, const T& value, Compared comp) +{ + return mystl::ubound_dispatch(first, last, value, iterator_category(first), comp); +} + +/*****************************************************************************************/ +// binary_search +// 二分查找,如果在[first, last)内有等同于 value 的元素,返回 true,否则返回 false +/*****************************************************************************************/ +template +bool binary_search(ForwardIter first, ForwardIter last, const T& value) +{ + auto i = mystl::lower_bound(first, last, value); + return i != last && !(value < *i); +} + +// 重载版本使用函数对象 comp 代替比较操作 +template +bool binary_search(ForwardIter first, ForwardIter last, const T& value, Compared comp) +{ + auto i = mystl::lower_bound(first, last, value); + return i != last && !comp(value, *i); +} + +/*****************************************************************************************/ +// equal_range +// 查找[first,last)区间中与 value 相等的元素所形成的区间,返回一对迭代器指向区间首尾 +// 第一个迭代器指向第一个不小于 value 的元素,第二个迭代器指向第一个大于 value 的元素 +/*****************************************************************************************/ +// erange_dispatch 的 forward_iterator_tag 版本 +template +mystl::pair +erange_dispatch(ForwardIter first, ForwardIter last, + const T& value, forward_iterator_tag) +{ + auto len = mystl::distance(first, last); + auto half = len; + ForwardIter middle, left, right; + while (len > 0) + { + half = len >> 1; + middle = first; + mystl::advance(middle, half); + if (*middle < value) + { + first = middle; + ++first; + len = len - half - 1; + } + else if (value < *middle) + { + len = half; + } + else + { + left = mystl::lower_bound(first, last, value); + mystl::advance(first, len); + right = mystl::upper_bound(++middle, first, value); + return mystl::pair(left, right); + } + } + return mystl::pair(last, last); +} + +// erange_dispatch 的 random_access_iterator_tag 版本 +template +mystl::pair +erange_dispatch(RandomIter first, RandomIter last, + const T& value, random_access_iterator_tag) +{ + auto len = last - first; + auto half = len; + RandomIter middle, left, right; + while (len > 0) + { + half = len >> 1; + middle = first + half; + if (*middle < value) + { + first = middle + 1; + len = len - half - 1; + } + else if (value < *middle) + { + len = half; + } + else + { + left = mystl::lower_bound(first, middle, value); + right = mystl::upper_bound(++middle, first + len, value); + return mystl::pair(left, right); + } + } + return mystl::pair(last, last); +} + +template +mystl::pair +equal_range(ForwardIter first, ForwardIter last, const T& value) +{ + return mystl::erange_dispatch(first, last, value, iterator_category(first)); +} + +// 重载版本使用函数对象 comp 代替比较操作 +// erange_dispatch 的 forward iterator 版本 +template +mystl::pair +erange_dispatch(ForwardIter first, ForwardIter last, + const T& value, forward_iterator_tag, Compared comp) +{ + auto len = mystl::distance(first, last); + auto half = len; + ForwardIter middle, left, right; + while (len > 0) + { + half = len >> 1; + middle = first; + mystl::advance(middle, half); + if (comp(*middle, value)) + { + first = middle; + ++first; + len = len - half - 1; + } + else if (comp(value, *middle)) + { + len = half; + } + else + { + left = mystl::lower_bound(first, last, value, comp); + mystl::advance(first, len); + right = mystl::upper_bound(++middle, first, value, comp); + return mystl::pair(left, right); + } + } + return mystl::pair(last, last); +} + +// erange_dispatch 的 random access iterator 版本 +template +mystl::pair +erange_dispatch(RandomIter first, RandomIter last, + const T& value, random_access_iterator_tag, Compared comp) +{ + auto len = last - first; + auto half = len; + RandomIter middle, left, right; + while (len > 0) + { + half = len >> 1; + middle = first + half; + if (comp(*middle, value)) + { + first = middle + 1; + len = len - half - 1; + } + else if (comp(value, *middle)) + { + len = half; + } + else + { + left = mystl::lower_bound(first, middle, value, comp); + right = mystl::upper_bound(++middle, first + len, value, comp); + return mystl::pair(left, right); + } + } + return mystl::pair(last, last); +} + +template +mystl::pair +equal_range(ForwardIter first, ForwardIter last, const T& value, Compared comp) +{ + return mystl::erange_dispatch(first, last, value, iterator_category(first), comp); +} + +/*****************************************************************************************/ +// generate +// 将函数对象 gen 的运算结果对[first, last)内的每个元素赋值 +/*****************************************************************************************/ +template +void generate(ForwardIter first, ForwardIter last, Generator gen) +{ + for (; first != last; ++first) + { + *first = gen(); + } +} + +/*****************************************************************************************/ +// generate_n +// 用函数对象 gen 连续对 n 个元素赋值 +/*****************************************************************************************/ +template +void generate_n(ForwardIter first, Size n, Generator gen) +{ + for (; n > 0; --n, ++first) + { + *first = gen(); + } +} + +/*****************************************************************************************/ +// includes +// 判断序列一S1 是否包含序列二S2 +/*****************************************************************************************/ +template +bool includes(InputIter1 first1, InputIter1 last1, + InputIter2 first2, InputIter2 last2) +{ + while (first1 != last1 && first2 != last2) + { + if (*first2 < *first1) + { + return false; + } + else if (*first1 < *first2) + { + ++first1; + } + else + { + ++first1, ++first2; + } + } + return first2 == last2; +} + +// 重载版本使用函数对象 comp 代替比较操作 +template +bool includes(InputIter1 first1, InputIter1 last1, + InputIter2 first2, InputIter2 last2, Compared comp) +{ + while (first1 != last1 && first2 != last2) + { + if (comp(*first2, *first1)) + { + return false; + } + else if (comp(*first1, *first2)) + { + ++first1; + } + else + { + ++first1, ++first2; + } + } + return first2 == last2; +} + +/*****************************************************************************************/ +// is_heap +// 检查[first, last)内的元素是否为一个堆,如果是,则返回 true +/*****************************************************************************************/ +template +bool is_heap(RandomIter first, RandomIter last) +{ + auto n = mystl::distance(first, last); + auto parent = 0; + for (auto child = 1; child < n; ++child) + { + if (first[parent] < first[child]) + return false; + if ((child & 1) == 0) + ++parent; + } + return true; +} + +// 重载版本使用函数对象 comp 代替比较操作 +template +bool is_heap(RandomIter first, RandomIter last, Compared comp) +{ + auto n = mystl::distance(first, last); + auto parent = 0; + for (auto child = 1; child < n; ++child) + { + if (comp(first[parent], first[child])) + return false; + if ((child & 1) == 0) + ++parent; + } + return true; +} + +/*****************************************************************************************/ +// is_sorted +// 检查[first, last)内的元素是否升序,如果是升序,则返回 true +/*****************************************************************************************/ +template +bool is_sorted(ForwardIter first, ForwardIter last) +{ + if (first == last) + return true; + auto next = first; + ++next; + for (; next != last; first = next, ++next) + { + if (*next < *first) + return false; + } + return true; +} + +// 重载版本使用函数对象 comp 代替比较操作 +template +bool is_sorted(ForwardIter first, ForwardIter last, Compared comp) +{ + if (first == last) + return true; + auto next = first; + ++next; + for (; next != last; first = next, ++next) + { + if (comp(*next, *first)) + return false; + } + return true; +} + +/*****************************************************************************************/ +// median +// 找出三个值的中间值 +/*****************************************************************************************/ +template +const T& median(const T& left, const T& mid, const T& right) +{ + if (left < mid) + if (mid < right) // left < mid < right + return mid; + else if (left < right) // left < right <= mid + return right; + else // right <= left < mid + return left; + else if (left < right) // mid <= left < right + return left; + else if (mid < right) // mid < right <= left + return right; + else // right <= mid <= left + return mid; +} + +// 重载版本使用函数对象 comp 代替比较操作 +template +const T& median(const T& left, const T& mid, const T& right, Compared comp) +{ + if (comp(left, mid)) + if (comp(mid, right)) + return mid; + else if (comp(left, right)) + return right; + else + return left; + else if (comp(left, right)) + return left; + else if (comp(mid, right)) + return right; + else + return mid; +} + +/*****************************************************************************************/ +// max_element +// 返回一个迭代器,指向序列中最大的元素 +/*****************************************************************************************/ +template +ForwardIter max_element(ForwardIter first, ForwardIter last) +{ + if (first == last) + return first; + auto result = first; + while (++first != last) + { + if (*result < *first) + result = first; + } + return result; +} + +// 重载版本使用函数对象 comp 代替比较操作 +template +ForwardIter max_element(ForwardIter first, ForwardIter last, Compared comp) +{ + if (first == last) + return first; + auto result = first; + while (++first != last) + { + if (comp(*result, *first)) + result = first; + } + return result; +} + +/*****************************************************************************************/ +// min_element +// 返回一个迭代器,指向序列中最小的元素 +/*****************************************************************************************/ +template +ForwardIter min_elememt(ForwardIter first, ForwardIter last) +{ + if (first == last) + return first; + auto result = first; + while (++first != last) + { + if (*first < *result) + result = first; + } + return result; +} + +// 重载版本使用函数对象 comp 代替比较操作 +template +ForwardIter min_elememt(ForwardIter first, ForwardIter last, Compared comp) +{ + if (first == last) + return first; + auto result = first; + while (++first != last) + { + if (comp(*first, *result)) + result = first; + } + return result; +} + +/*****************************************************************************************/ +// swap_ranges +// 将[first1, last1)从 first2 开始,交换相同个数元素 +// 交换的区间长度必须相同,两个序列不能互相重叠,返回一个迭代器指向序列二最后一个被交换元素的下一位置 +/*****************************************************************************************/ +template +ForwardIter2 +swap_ranges(ForwardIter1 first1, ForwardIter1 last1, + ForwardIter2 first2) +{ + for (; first1 != last1; ++first1, ++first2) + { + mystl::iter_swap(first1, first2); + } + return first2; +} + +/*****************************************************************************************/ +// transform +// 第一个版本以函数对象 unary_op 作用于[first, last)中的每个元素并将结果保存至 result 中 +// 第二个版本以函数对象 binary_op 作用于两个序列[first1, last1)、[first2, last2)的相同位置 +/*****************************************************************************************/ +template +OutputIter +transform(InputIter first, InputIter last, + OutputIter result, UnaryOperation unary_op) +{ + for (; first != last; ++first, ++result) + { + *result = unary_op(*first); + } + return result; +} + +template +OutputIter +transform(InputIter1 first1, InputIter1 last1, + InputIter2 first2, OutputIter result, BinaryOperation binary_op) +{ + for (; first1 != last1; ++first1, ++first2, ++result) + { + *result = binary_op(*first1, *first2); + } + return result; +} + +/*****************************************************************************************/ +// remove_copy +// 移除区间内与指定 value 相等的元素,并将结果复制到以 result 标示起始位置的容器上 +/*****************************************************************************************/ +template +OutputIter +remove_copy(InputIter first, InputIter last, OutputIter result, const T& value) +{ + for (; first != last; ++first) + { + if (*first != value) + { + *result++ = *first; + } + } + return result; +} + +/*****************************************************************************************/ +// remove +// 移除所有与指定 value 相等的元素 +// 并不从容器中删除这些元素,所以 remove 和 remove_if 不适用于 array +/*****************************************************************************************/ +template +ForwardIter remove(ForwardIter first, ForwardIter last, const T& value) +{ + first = mystl::find(first, last, value); // 利用 find 找出第一个匹配的地方 + auto next = first; + return first == last ? first : mystl::remove_copy(++next, last, first, value); +} + +/*****************************************************************************************/ +// remove_copy_if +// 移除区间内所有令一元操作 unary_pred 为 true 的元素,并将结果复制到以 result 为起始位置的容器上 +/*****************************************************************************************/ +template +OutputIter +remove_copy_if(InputIter first, InputIter last, + OutputIter result, UnaryPredicate unary_pred) +{ + for (; first != last; ++first) + { + if (!unary_pred(*first)) + { + *result = *first; + ++result; + } + } + return result; +} + +/*****************************************************************************************/ +// remove_if +// 移除区间内所有令一元操作 unary_pred 为 true 的元素 +/*****************************************************************************************/ +template +ForwardIter +remove_if(ForwardIter first, ForwardIter last, UnaryPredicate unary_pred) +{ + first = mystl::find_if(first, last, unary_pred); // 利用 find_if 找出第一个匹配的地方 + auto next = first; + return first == last ? first : mystl::remove_copy_if(++next, last, first, unary_pred); +} + +/*****************************************************************************************/ +// replace +// 将区间内所有的 old_value 都以 new_value 替代 +/*****************************************************************************************/ +template +void replace(ForwardIter first, ForwardIter last, + const T& old_value, const T& new_value) +{ + for (; first != last; ++first) + { + if (*first == old_value) + *first = new_value; + } +} + +/*****************************************************************************************/ +// replace_copy +// 行为与 replace 类似,不同的是将结果复制到 result 所指的容器中,原序列没有改变 +/*****************************************************************************************/ +template +OutputIter +replace_copy(InputIter first, InputIter last, + OutputIter result, const T& old_value, const T& new_value) +{ + for (; first != last; ++first, ++result) + { + *result = *first == old_value ? new_value : *first; + } + return result; +} + +/*****************************************************************************************/ +// replace_copy_if +// 行为与 replace_if 类似,不同的是将结果复制到 result 所指的容器中,原序列没有改变 +/*****************************************************************************************/ +template +OutputIter +replace_copy_if(InputIter first, InputIter last, + OutputIter result, UnaryPredicate unary_pred, const T& new_value) +{ + for (; first != last; ++first, ++result) + { + *result = unary_pred(*first) ? new_value : *first; + } + return result; +} + +/*****************************************************************************************/ +// replace_if +// 将区间内所有令一元操作 unary_pred 为 true 的元素都用 new_value 替代 +/*****************************************************************************************/ +template +void replace_if(ForwardIter first, ForwardIter last, + UnaryPredicate unary_pred, const T& new_value) +{ + for (; first != last; ++first) + { + if (unary_pred(*first)) + *first = new_value; + } +} + +/*****************************************************************************************/ +// reverse +// 将[first, last)区间内的元素反转 +/*****************************************************************************************/ +// reverse_dispatch 的 bidirectional_iterator_tag 版本 +template +void reverse_dispatch(BidirectionalIter first, BidirectionalIter last, + bidirectional_iterator_tag) +{ + while (true) + { + if (first == last || first == --last) + return; + mystl::iter_swap(first++, last); + } +} + +// reverse_dispatch 的 random_access_iterator_tag 版本 +template +void reverse_dispatch(RandomIter first, RandomIter last, + random_access_iterator_tag) +{ + while (first < last) + mystl::iter_swap(first++, --last); +} + +template +void reverse(BidirectionalIter first, BidirectionalIter last) +{ + mystl::reverse_dispatch(first, last, iterator_category(first)); +} + +/*****************************************************************************************/ +// reverse_copy +// 行为与 reverse 类似,不同的是将结果复制到 result 所指容器中 +/*****************************************************************************************/ +template +OutputIter +reverse_copy(BidirectionalIter first, BidirectionalIter last, + OutputIter result) +{ + while (first != last) + { + --last; + *result = *last; + ++result; + } + return result; +} + +/*****************************************************************************************/ +// random_shuffle +// 将[first, last)内的元素次序随机重排 +// 重载版本使用一个产生随机数的函数对象 rand +/*****************************************************************************************/ +template +void random_shuffle(RandomIter first, RandomIter last) +{ + if (first == last) + return; + srand((unsigned)time(0)); + for (auto i = first + 1; i != last; ++i) + { + mystl::iter_swap(i, first + (rand() % (i - first + 1))); + } +} + +// 重载版本使用一个产生随机数的函数对象 rand +template +void random_shuffle(RandomIter first, RandomIter last, + RandomNumberGenerator& rand) +{ + if (first == last) + return; + auto len = mystl::distance(first, last); + for (auto i = first + 1; i != last; ++i) + { + mystl::iter_swap(i, first + (rand(i - first + 1) % len)); + } +} + +/*****************************************************************************************/ +// rotate +// 将[first, middle)内的元素和 [middle, last)内的元素互换,可以交换两个长度不同的区间 +// 返回交换后 middle 的位置 +/*****************************************************************************************/ +// rotate_dispatch 的 forward_iterator_tag 版本 +template +ForwardIter +rotate_dispatch(ForwardIter first, ForwardIter middle, + ForwardIter last, forward_iterator_tag) +{ + auto first2 = middle; + do + { + mystl::swap(*first++, *first2++); + if (first == middle) + middle = first2; + } while (first2 != last); // 后半段移到前面 + + auto new_middle = first; // 迭代器返回的位置 + first2 = middle; + while (first2 != last) + { // 调整剩余元素 + mystl::swap(*first++, *first2++); + if (first == middle) + { + middle = first2; + } + else if (first2 == last) + { + first2 = middle; + } + } + return new_middle; +} + +// rotate_dispatch 的 bidirectional_iterator_tag 版本 +template +BidirectionalIter +rotate_dispatch(BidirectionalIter first, BidirectionalIter middle, + BidirectionalIter last, bidirectional_iterator_tag) +{ + mystl::reverse_dispatch(first, middle, bidirectional_iterator_tag()); + mystl::reverse_dispatch(middle, last, bidirectional_iterator_tag()); + while (first != middle && middle != last) + mystl::swap(*first++, *--last); + if (first == middle) + { + mystl::reverse_dispatch(middle, last, bidirectional_iterator_tag()); + return last; + } + else + { + mystl::reverse_dispatch(first, middle, bidirectional_iterator_tag()); + return first; + } +} + +// 求最大公因子 +template +EuclideanRingElement rgcd(EuclideanRingElement m, EuclideanRingElement n) +{ + while (n != 0) + { + auto t = m % n; + m = n; + n = t; + } + return m; +} + +// rotate_dispatch 的 random_access_iterator_tag 版本 +template +RandomIter +rotate_dispatch(RandomIter first, RandomIter middle, + RandomIter last, random_access_iterator_tag) +{ + // 因为是 random access iterator,我们可以确定每个元素的位置 + auto n = last - first; + auto l = middle - first; + auto r = n - l; + auto result = first + (last - middle); + if (l == r) + { + mystl::swap_ranges(first, middle, middle); + return result; + } + auto cycle_times = rgcd(n, l); + for (auto i = 0; i < cycle_times; ++i) + { + auto tmp = *first; + auto p = first; + if (l < r) + { + for (auto j = 0; j < r / cycle_times; ++j) + { + if (p > first + r) + { + *p = *(p - r); + p -= r; + } + *p = *(p + l); + p += l; + } + } + else + { + for (auto j = 0; j < l / cycle_times - 1; ++j) + { + if (p < last - l) + { + *p = *(p + l); + p += l; + } + *p = *(p - r); + p -= r; + } + } + *p = tmp; + ++first; + } + return result; +} + +template +ForwardIter +rotate(ForwardIter first, ForwardIter middle, ForwardIter last) +{ + if (first == middle) + return last; + if (middle == last) + return first; + return mystl::rotate_dispatch(first, middle, last, iterator_category(first)); +} + +/*****************************************************************************************/ +// rotate_copy +// 行为与 rotate 类似,不同的是将结果复制到 result 所指的容器中 +/*****************************************************************************************/ +template +ForwardIter +rotate_copy(ForwardIter first, ForwardIter middle, + ForwardIter last, OutputIter result) +{ + return mystl::copy(first, middle, mystl::copy(middle, last, result)); +} + +/*****************************************************************************************/ +// is_permutation +// 判断[first1,last1)是否为[first2, last2)的排列组合 +/*****************************************************************************************/ +template +bool is_permutation_aux(ForwardIter1 first1, ForwardIter1 last1, + ForwardIter2 first2, ForwardIter2 last2, + BinaryPred pred) +{ + constexpr bool is_ra_it = mystl::is_random_access_iterator::value + && mystl::is_random_access_iterator::value; + if (is_ra_it) + { + auto len1 = last1 - first1; + auto len2 = last2 - first2; + if (len1 != len2) + return false; + } + + // 先找出相同的前缀段 + for (; first1 != last1 && first2 != last2; ++first1, (void) ++first2) + { + if (!pred(*first1, *first2)) + break; + } + if (is_ra_it) + { + if (first1 == last1) + return true; + } + else + { + auto len1 = mystl::distance(first1, last1); + auto len2 = mystl::distance(first2, last2); + if (len1 == 0 && len2 == 0) + return true; + if (len1 != len2) + return false; + } + + // 判断剩余部分 + for (auto i = first1; i != last1; ++i) + { + bool is_repeated = false; + for (auto j = first1; j != i; ++j) + { + if (pred(*j, *i)) + { + is_repeated = true; + break; + } + } + + if (!is_repeated) + { + // 计算 *i 在 [first2, last2) 的数目 + auto c2 = 0; + for (auto j = first2; j != last2; ++j) + { + if (pred(*i, *j)) + ++c2; + } + if (c2 == 0) + return false; + + // 计算 *i 在 [first1, last1) 的数目 + auto c1 = 1; + auto j = i; + for (++j; j != last1; ++j) + { + if (pred(*i, *j)) + ++c1; + } + if (c1 != c2) + return false; + } + } + return true; +} + +template +bool is_permutation(ForwardIter1 first1, ForwardIter1 last1, + ForwardIter2 first2, ForwardIter2 last2, + BinaryPred pred) +{ + return is_permutation_aux(first1, last1, first2, last2, pred); +} + +template +bool is_permutation(ForwardIter1 first1, ForwardIter1 last1, + ForwardIter2 first2, ForwardIter2 last2) +{ + typedef typename iterator_traits::value_type v1; + typedef typename iterator_traits::value_type v2; + static_assert(std::is_same::value, + "the type should be same in mystl::is_permutation"); + return is_permutation_aux(first1, last1, first2, last2, + mystl::equal_to()); +} + +/*****************************************************************************************/ +// next_permutation +// 取得[first, last)所标示序列的下一个排列组合,如果没有下一个排序组合,返回 false,否则返回 true +/*****************************************************************************************/ +template +bool next_permutation(BidirectionalIter first, BidirectionalIter last) +{ + auto i = last; + if (first == last || first == --i) + return false; + for (;;) + { + auto ii = i; + if (*--i < *ii) + { // 找到第一对小于关系的元素 + auto j = last; + while (!(*i < *--j)) {} + mystl::iter_swap(i, j); // 交换 i,j 所指元素 + mystl::reverse(ii, last); // 将 ii 之后的所有元素反转 + return true; + } + if (i == first) + { + mystl::reverse(first, last); + return false; + } + } +} + +// 重载版本使用函数对象 comp 代替比较操作 +template +bool next_permutation(BidirectionalIter first, BidirectionalIter last, Compared comp) +{ + auto i = last; + if (first == last || first == --i) + return false; + for (;;) + { + auto ii = i; + if (comp(*--i, *ii)) + { + auto j = last; + while (!comp(*i, *--j)) {} + mystl::iter_swap(i, j); // 交换 i,j 所指元素 + mystl::reverse(ii, last); // 将 ii 之后的所有元素反转 + return true; + } + if (i == first) + { + mystl::reverse(first, last); + return false; + } + } +} + +/*****************************************************************************************/ +// prev_permutation +// 取得[first, last)所标示序列的上一个排列组合,如果没有上一个排序组合,返回 false,否则返回 true +/*****************************************************************************************/ +template +bool prev_permutation(BidirectionalIter first, BidirectionalIter last) +{ + auto i = last; + if (first == last || first == --i) + return false; + for (;;) + { + auto ii = i; + if (*ii < *--i) + { // 找到第一对大于关系的元素 + auto j = last; + while (!(*--j < *i)) {} + mystl::iter_swap(i, j); // 交换i,j + mystl::reverse(ii, last); // 将 ii 之后的所有元素反转 + return true; + } + if (i == first) + { + mystl::reverse(first, last); + return false; + } + } +} + +// 重载版本使用函数对象 comp 代替比较操作 +template +bool prev_permutation(BidirectionalIter first, BidirectionalIter last, Compared comp) +{ + auto i = last; + if (first == last || first == --i) + return false; + for (;;) + { + auto ii = i; + if (comp(*ii, *--i)) + { + auto j = last; + while (!comp(*--j, *i)) {} + mystl::iter_swap(i, j); // 交换i,j + mystl::reverse(ii, last); // 将 ii 之后的所有元素反转 + return true; + } + if (i == first) + { + mystl::reverse(first, last); + return false; + } + } +} + +/*****************************************************************************************/ +// merge +// 将两个经过排序的集合 S1 和 S2 合并起来置于另一段空间,返回一个迭代器指向最后一个元素的下一位置 +/*****************************************************************************************/ +template +OutputIter +merge(InputIter1 first1, InputIter1 last1, + InputIter2 first2, InputIter2 last2, + OutputIter result) +{ + while (first1 != last1 && first2 != last2) + { + if (*first2 < *first1) + { + *result = *first2; + ++first2; + } + else + { + *result = *first1; + ++first1; + } + ++result; + } + return mystl::copy(first2, last2, mystl::copy(first1, last1, result)); +} + +// 重载版本使用函数对象 comp 代替比较操作 +template +OutputIter +merge(InputIter1 first1, InputIter1 last1, + InputIter2 first2, InputIter2 last2, + OutputIter result, Compared comp) +{ + while (first1 != last1 && first2 != last2) + { + if (comp(*first2, *first1)) + { + *result = *first2; + ++first2; + } + else + { + *result = *first1; + ++first1; + } + ++result; + } + return mystl::copy(first2, last2, mystl::copy(first1, last1, result)); +} + +/*****************************************************************************************/ +// inplace_merge +// 把连接在一起的两个有序序列结合成单一序列并保持有序 +/*****************************************************************************************/ +// 没有缓冲区的情况下合并 +template +void merge_without_buffer(BidirectionalIter first, BidirectionalIter middle, + BidirectionalIter last, Distance len1, Distance len2) +{ + if (len1 == 0 || len2 == 0) + return; + if (len1 + len2 == 2) + { + if (*middle < *first) + mystl::iter_swap(first, middle); + return; + } + auto first_cut = first; + auto second_cut = middle; + Distance len11 = 0; + Distance len22 = 0; + if (len1 > len2) + { // 序列一较长,找到序列一的中点 + len11 = len1 >> 1; + mystl::advance(first_cut, len11); + second_cut = mystl::lower_bound(middle, last, *first_cut); + len22 = mystl::distance(middle, second_cut); + } + else + { // 序列二较长,找到序列二的中点 + len22 = len2 >> 1; + mystl::advance(second_cut, len22); + first_cut = mystl::upper_bound(first, middle, *second_cut); + len11 = mystl::distance(first, first_cut); + } + auto new_middle = mystl::rotate(first_cut, middle, second_cut); + mystl::merge_without_buffer(first, first_cut, new_middle, len11, len22); + mystl::merge_without_buffer(new_middle, second_cut, last, len1 - len11, len2 - len22); +} + +template +BidirectionalIter1 +merge_backward(BidirectionalIter1 first1, BidirectionalIter1 last1, + BidirectionalIter2 first2, BidirectionalIter2 last2, + BidirectionalIter1 result) +{ + if (first1 == last1) + return mystl::copy_backward(first2, last2, result); + if (first2 == last2) + return mystl::copy_backward(first1, last1, result); + --last1; + --last2; + while (true) + { + if (*last2 < *last1) + { + *--result = *last1; + if (first1 == last1) + return mystl::copy_backward(first2, ++last2, result); + --last1; + } + else + { + *--result = *last2; + if (first2 == last2) + return mystl::copy_backward(first1, ++last1, result); + --last2; + } + } +} + +template +BidirectionalIter1 +rotate_adaptive(BidirectionalIter1 first, BidirectionalIter1 middle, + BidirectionalIter1 last, Distance len1, Distance len2, + BidirectionalIter2 buffer, Distance buffer_size) +{ + BidirectionalIter2 buffer_end; + if (len1 > len2 && len2 <= buffer_size) + { + buffer_end = mystl::copy(middle, last, buffer); + mystl::copy_backward(first, middle, last); + return mystl::copy(buffer, buffer_end, first); + } + else if (len1 <= buffer_size) + { + buffer_end = mystl::copy(first, middle, buffer); + mystl::copy(middle, last, first); + return mystl::copy_backward(buffer, buffer_end, last); + } + else + { + return mystl::rotate(first, middle, last); + } +} + +// 有缓冲区的情况下合并 +template +void merge_adaptive(BidirectionalIter first, BidirectionalIter middle, + BidirectionalIter last, Distance len1, Distance len2, + Pointer buffer, Distance buffer_size) +{ + // 区间长度足够放进缓冲区 + if (len1 <= len2 && len1 <= buffer_size) + { + Pointer buffer_end = mystl::copy(first, middle, buffer); + mystl::merge(buffer, buffer_end, middle, last, first); + } + else if (len2 <= buffer_size) + { + Pointer buffer_end = mystl::copy(middle, last, buffer); + mystl::merge_backward(first, middle, buffer, buffer_end, last); + } + else + { // 区间长度太长,分割递归处理 + auto first_cut = first; + auto second_cut = middle; + Distance len11 = 0; + Distance len22 = 0; + if (len1 > len2) + { + len11 = len1 >> 1; + mystl::advance(first_cut, len11); + second_cut = mystl::lower_bound(middle, last, *first_cut); + len22 = mystl::distance(middle, second_cut); + } + else + { + len22 = len2 >> 1; + mystl::advance(second_cut, len22); + first_cut = mystl::upper_bound(first, middle, *second_cut); + len11 = mystl::distance(first, first_cut); + } + auto new_middle = mystl::rotate_adaptive(first_cut, middle, second_cut, + len1 - len11, len22, buffer, buffer_size); + mystl::merge_adaptive(first, first_cut, new_middle, len11, len22, buffer, buffer_size); + mystl::merge_adaptive(new_middle, second_cut, last, len1 - len11, + len2 - len22, buffer, buffer_size); + } +} + +template +void +inplace_merge_aux(BidirectionalIter first, BidirectionalIter middle, + BidirectionalIter last, T*) +{ + auto len1 = mystl::distance(first, middle); + auto len2 = mystl::distance(middle, last); + temporary_buffer buf(first, last); + if (!buf.begin()) + { + mystl::merge_without_buffer(first, middle, last, len1, len2); + } + else + { + mystl::merge_adaptive(first, middle, last, len1, len2, buf.begin(), buf.size()); + } +} + +template +void +inplace_merge(BidirectionalIter first, BidirectionalIter middle, + BidirectionalIter last) +{ + if (first == middle || middle == last) + return; + mystl::inplace_merge_aux(first, middle, last, value_type(first)); +} + +// 重载版本使用函数对象 comp 代替比较操作 +// 没有缓冲区的情况下合并 +template +void merge_without_buffer(BidirectionalIter first, BidirectionalIter middle, + BidirectionalIter last, Distance len1, Distance len2, + Compared comp) +{ + if (len1 == 0 || len2 == 0) + return; + if (len1 + len2 == 2) + { + if (comp(*middle, *first)) + mystl::iter_swap(first, middle); + return; + } + auto first_cut = first; + auto second_cut = middle; + Distance len11 = 0; + Distance len22 = 0; + if (len1 > len2) + { + len11 = len1 >> 1; + mystl::advance(first_cut, len11); + second_cut = mystl::lower_bound(middle, last, *first_cut, comp); + len22 = mystl::distance(middle, second_cut); + } + else + { + len22 = len2 >> 1; + mystl::advance(second_cut, len22); + first_cut = mystl::upper_bound(first, middle, *second_cut, comp); + len11 = mystl::distance(first, first_cut); + } + auto new_middle = mystl::rotate(first_cut, middle, second_cut); + mystl::merge_without_buffer(first, first_cut, new_middle, len11, len22, comp); + mystl::merge_without_buffer(new_middle, second_cut, last, len1 - len11, len2 - len22, comp); +} + +template +BidirectionalIter1 +merge_backward(BidirectionalIter1 first1, BidirectionalIter1 last1, + BidirectionalIter2 first2, BidirectionalIter2 last2, + BidirectionalIter1 result, Compared comp) +{ + if (first1 == last1) + return mystl::copy_backward(first2, last2, result); + if (first2 == last2) + return mystl::copy_backward(first1, last1, result); + --last1; + --last2; + while (true) + { + if (comp(*last2, *last1)) + { + *--result = *last1; + if (first1 == last1) + return mystl::copy_backward(first2, ++last2, result); + --last1; + } + else + { + *--result = *last2; + if (first2 == last2) + return mystl::copy_backward(first1, ++last1, result); + --last2; + } + } +} + +// 有缓冲区的情况下合并 +template +void merge_adaptive(BidirectionalIter first, BidirectionalIter middle, + BidirectionalIter last, Distance len1, Distance len2, + Pointer buffer, Distance buffer_size, Compared comp) +{ + // 区间长度足够放进缓冲区 + if (len1 <= len2 && len1 <= buffer_size) + { + Pointer buffer_end = mystl::copy(first, middle, buffer); + mystl::merge(buffer, buffer_end, middle, last, first, comp); + } + else if (len2 <= buffer_size) + { + Pointer buffer_end = mystl::copy(middle, last, buffer); + mystl::merge_backward(first, middle, buffer, buffer_end, last, comp); + } + else + { // 区间长度太长,分割递归处理 + auto first_cut = first; + auto second_cut = middle; + Distance len11 = 0; + Distance len22 = 0; + if (len1 > len2) + { + len11 = len1 >> 1; + mystl::advance(first_cut, len11); + second_cut = mystl::lower_bound(middle, last, *first_cut, comp); + len22 = mystl::distance(middle, second_cut); + } + else + { + len22 = len2 >> 1; + mystl::advance(second_cut, len22); + first_cut = mystl::upper_bound(first, middle, *second_cut, comp); + len11 = mystl::distance(first, first_cut); + } + auto new_middle = mystl::rotate_adaptive(first_cut, middle, second_cut, len1 - len11, + len22, buffer, buffer_size); + mystl::merge_adaptive(first, first_cut, new_middle, len11, + len22, buffer, buffer_size, comp); + mystl::merge_adaptive(new_middle, second_cut, last, len1 - len11, + len2 - len22, buffer, buffer_size, comp); + } +} + +template +void +inplace_merge_aux(BidirectionalIter first, BidirectionalIter middle, + BidirectionalIter last, T*, Compared comp) +{ + auto len1 = mystl::distance(first, middle); + auto len2 = mystl::distance(middle, last); + temporary_buffer buf(first, last); + if (!buf.begin()) + { + mystl::merge_without_buffer(first, middle, last, len1, len2, comp); + } + else + { + mystl::merge_adaptive(first, middle, last, len1, len2, buf.begin(), buf.size(), comp); + } +} + +template +void +inplace_merge(BidirectionalIter first, BidirectionalIter middle, + BidirectionalIter last, Compared comp) +{ + if (first == middle || middle == last) + return; + mystl::inplace_merge_aux(first, middle, last, value_type(first), comp); +} + +/*****************************************************************************************/ +// partial_sort +// 对整个序列做部分排序,保证较小的 N 个元素以递增顺序置于[first, first + N)中 +/*****************************************************************************************/ +template +void partial_sort(RandomIter first, RandomIter middle, + RandomIter last) +{ + mystl::make_heap(first, middle); + for (auto i = middle; i < last; ++i) + { + if (*i < *first) + { + mystl::pop_heap_aux(first, middle, i, *i, distance_type(first)); + } + } + mystl::sort_heap(first, middle); +} + +// 重载版本使用函数对象 comp 代替比较操作 +template +void partial_sort(RandomIter first, RandomIter middle, + RandomIter last, Compared comp) +{ + mystl::make_heap(first, middle, comp); + for (auto i = middle; i < last; ++i) + { + if (comp(*i, *first)) + { + mystl::pop_heap_aux(first, middle, i, *i, distance_type(first), comp); + } + } + mystl::sort_heap(first, middle, comp); +} + +/*****************************************************************************************/ +// partial_sort_copy +// 行为与 partial_sort 类似,不同的是把排序结果复制到 result 容器中 +/*****************************************************************************************/ +template +RandomIter +psort_copy_aux(InputIter first, InputIter last, + RandomIter result_first, RandomIter result_last, + Distance*) +{ + if (result_first == result_last) + return result_last; + auto result_iter = result_first; + while (first != last && result_iter != result_last) + { + *result_iter = *first; + ++result_iter; + ++first; + } + mystl::make_heap(result_first, result_iter); + while (first != last) + { + if (*first < *result_first) + { + mystl::adjust_heap(result_first, static_cast(0), + result_iter - result_first, *first); + } + ++first; + } + mystl::sort_heap(result_first, result_iter); + return result_iter; +} + +template +RandomIter +partial_sort_copy(InputIter first, InputIter last, + RandomIter result_first, RandomIter result_last) +{ + return mystl::psort_copy_aux(first, last, result_first, result_last, + distance_type(result_first)); +} + +// 重载版本使用函数对象 comp 代替比较操作 +template +RandomIter +psort_copy_aux(InputIter first, InputIter last, + RandomIter result_first, RandomIter result_last, + Distance*, Compared comp) +{ + if (result_first == result_last) + return result_last; + auto result_iter = result_first; + while (first != last && result_iter != result_last) + { + *result_iter = *first; + ++result_iter; + ++first; + } + mystl::make_heap(result_first, result_iter, comp); + while (first != last) + { + if (comp(*first, *result_first)) + { + mystl::adjust_heap(result_first, static_cast(0), + result_iter - result_first, *first, comp); + } + ++first; + } + mystl::sort_heap(result_first, result_iter, comp); + return result_iter; +} + +template +RandomIter +partial_sort_copy(InputIter first, InputIter last, + RandomIter result_first, RandomIter result_last, + Compared comp) +{ + return mystl::psort_copy_aux(first, last, result_first, result_last, + distance_type(result_first), comp); +} +/*****************************************************************************************/ +// partition +// 对区间内的元素重排,被一元条件运算判定为 true 的元素会放到区间的前段 +// 该函数不保证元素的原始相对位置 +/*****************************************************************************************/ +template +BidirectionalIter +partition(BidirectionalIter first, BidirectionalIter last, + UnaryPredicate unary_pred) +{ + while (true) + { + while (first != last && unary_pred(*first)) + { + ++first; + } + if (first == last) + break; + --last; + while (first != last && !unary_pred(*last)) + { + --last; + } + if (first == last) + break; + mystl::iter_swap(first, last); + ++first; + } + return first; +} + +/*****************************************************************************************/ +// partition_copy +// 行为与 partition 类似,不同的是,将被一元操作符判定为 true 的放到 result_true 的输出区间 +// 其余放到 result_false 的输出区间,并返回一个 mystl::pair 指向这两个区间的尾部 +/*****************************************************************************************/ +template +mystl::pair +partition_copy(InputIter first, InputIter last, + OutputIter1 result_true, OutputIter2 result_false, + UnaryPredicate unary_pred) +{ + for (; first != last; ++first) + { + if (unary_pred(*first)) + { + *result_true++ = *first; + } + else + { + *result_false++ = *first; + } + } + return mystl::pair(result_true, result_false); +} + +/*****************************************************************************************/ +// sort +// 将[first, last)内的元素以递增的方式排序 +/*****************************************************************************************/ +constexpr static size_t kSmallSectionSize = 128; // 小型区间的大小,在这个大小内采用插入排序 + + // 用于控制分割恶化的情况 +template +Size slg2(Size n) +{ // 找出 lgk <= n 的 k 的最大值 + Size k = 0; + for (; n > 1; n >>= 1) + ++k; + return k; +} + +// 分割函数 unchecked_partition +template +RandomIter +unchecked_partition(RandomIter first, RandomIter last, const T& pivot) +{ + while (true) + { + while (*first < pivot) + ++first; + --last; + while (pivot < *last) + --last; + if (!(first < last)) + return first; + mystl::iter_swap(first, last); + ++first; + } +} + +// 内省式排序,先进行 quick sort,当分割行为有恶化倾向时,改用 heap sort +template +void intro_sort(RandomIter first, RandomIter last, Size depth_limit) +{ + while (static_cast(last - first) > kSmallSectionSize) + { + if (depth_limit == 0) + { // 到达最大分割深度限制 + mystl::partial_sort(first, last, last); // 改用 heap_sort + return; + } + --depth_limit; + auto mid = mystl::median(*(first), *(first + (last - first) / 2), *(last - 1)); + auto cut = mystl::unchecked_partition(first, last, mid); + mystl::intro_sort(cut, last, depth_limit); + last = cut; + } +} + +// 插入排序辅助函数 unchecked_linear_insert +template +void unchecked_linear_insert(RandomIter last, const T& value) +{ + auto next = last; + --next; + while (value < *next) + { + *last = *next; + last = next; + --next; + } + *last = value; +} + +// 插入排序函数 unchecked_insertion_sort +template +void unchecked_insertion_sort(RandomIter first, RandomIter last) +{ + for (auto i = first; i != last; ++i) + { + mystl::unchecked_linear_insert(i, *i); + } +} + +// 插入排序函数 insertion_sort +template +void insertion_sort(RandomIter first, RandomIter last) +{ + if (first == last) + return; + for (auto i = first + 1; i != last; ++i) + { + auto value = *i; + if (value < *first) + { + mystl::copy_backward(first, i, i + 1); + *first = value; + } + else + { + mystl::unchecked_linear_insert(i, value); + } + } +} + +// 最终插入排序函数 final_insertion_sort +template +void final_insertion_sort(RandomIter first, RandomIter last) +{ + if (static_cast(last - first) > kSmallSectionSize) + { + mystl::insertion_sort(first, first + kSmallSectionSize); + mystl::unchecked_insertion_sort(first + kSmallSectionSize, last); + } + else + { + mystl::insertion_sort(first, last); + } +} + +template +void sort(RandomIter first, RandomIter last) +{ + if (first != last) + { + // 内省式排序,将区间分为一个个小区间,然后对整体进行插入排序 + mystl::intro_sort(first, last, slg2(last - first) * 2); + mystl::final_insertion_sort(first, last); + } +} + +// 重载版本使用函数对象 comp 代替比较操作 +// 分割函数 unchecked_partition +template +RandomIter +unchecked_partition(RandomIter first, RandomIter last, + const T& pivot, Compared comp) +{ + while (true) + { + while (comp(*first, pivot)) + ++first; + --last; + while (comp(pivot, *last)) + --last; + if (!(first < last)) + return first; + mystl::iter_swap(first, last); + ++first; + } +} + +// 内省式排序,先进行 quick sort,当分割行为有恶化倾向时,改用 heap sort +template +void intro_sort(RandomIter first, RandomIter last, + Size depth_limit, Compared comp) +{ + while (static_cast(last - first) > kSmallSectionSize) + { + if (depth_limit == 0) + { // 到达最大分割深度限制 + mystl::partial_sort(first, last, last, comp); // 改用 heap_sort + return; + } + --depth_limit; + auto mid = mystl::median(*(first), *(first + (last - first) / 2), *(last - 1)); + auto cut = mystl::unchecked_partition(first, last, mid, comp); + mystl::intro_sort(cut, last, depth_limit, comp); + last = cut; + } +} + +// 插入排序辅助函数 unchecked_linear_insert +template +void unchecked_linear_insert(RandomIter last, const T& value, Compared comp) +{ + auto next = last; + --next; + while (comp(value, *next)) + { // 从尾部开始寻找第一个可插入位置 + *last = *next; + last = next; + --next; + } + *last = value; +} + +// 插入排序函数 unchecked_insertion_sort +template +void unchecked_insertion_sort(RandomIter first, RandomIter last, + Compared comp) +{ + for (auto i = first; i != last; ++i) + { + mystl::unchecked_linear_insert(i, *i, comp); + } +} + +// 插入排序函数 insertion_sort +template +void insertion_sort(RandomIter first, RandomIter last, Compared comp) +{ + if (first == last) + return; + for (auto i = first + 1; i != last; ++i) + { + auto value = *i; + if (comp(value, *first)) + { + mystl::copy_backward(first, i, i + 1); + *first = value; + } + else + { + mystl::unchecked_linear_insert(i, value, comp); + } + } +} + +// 最终插入排序函数 final_insertion_sort +template +void final_insertion_sort(RandomIter first, RandomIter last, Compared comp) +{ + if (static_cast(last - first) > kSmallSectionSize) + { + mystl::insertion_sort(first, first + kSmallSectionSize, comp); + mystl::unchecked_insertion_sort(first + kSmallSectionSize, last, comp); + } + else + { + mystl::insertion_sort(first, last, comp); + } +} + +template +void sort(RandomIter first, RandomIter last, Compared comp) +{ + if (first != last) + { + // 内省式排序,将区间分为一个个小区间,然后对整体进行插入排序 + mystl::intro_sort(first, last, slg2(last - first) * 2, comp); + mystl::final_insertion_sort(first, last, comp); + } +} + +/*****************************************************************************************/ +// nth_element +// 对序列重排,使得所有小于第 n 个元素的元素出现在它的前面,大于它的出现在它的后面 +/*****************************************************************************************/ +template +void nth_element(RandomIter first, RandomIter nth, + RandomIter last) +{ + if (nth == last) + return; + while (last - first > 3) + { + auto cut = mystl::unchecked_partition(first, last, mystl::median(*first, + *(first + (last - first) / 2), + *(last - 1))); + if (cut <= nth) // 如果 nth 位于右段 + first = cut; // 对右段进行分割 + else + last = cut; // 对左段进行分割 + } + mystl::insertion_sort(first, last); +} + +// 重载版本使用函数对象 comp 代替比较操作 +template +void nth_element(RandomIter first, RandomIter nth, + RandomIter last, Compared comp) +{ + if (nth == last) + return; + while (last - first > 3) + { + auto cut = mystl::unchecked_partition(first, last, mystl::median(*first, + *(first + (last - first) / 2), + *(last - 1)), comp); + if (cut <= nth) // 如果 nth 位于右段 + first = cut; // 对右段进行分割 + else + last = cut; // 对左段进行分割 + } + mystl::insertion_sort(first, last, comp); +} + +/*****************************************************************************************/ +// unique_copy +// 从[first, last)中将元素复制到 result 上,序列必须有序,如果有重复的元素,只会复制一次 +/*****************************************************************************************/ +// unique_copy_dispatch 的 forward_iterator_tag 版本 +template +ForwardIter +unique_copy_dispatch(InputIter first, InputIter last, + ForwardIter result, forward_iterator_tag) +{ + *result = *first; + while (++first != last) + { + if (*result != *first) + *++result = *first; + } + return ++result; +} + +// unique_copy_dispatch 的 output_iterator_tag 版本 +// 由于 output iterator 只能进行只读操作,所以不能有 *result != *first 这样的判断 +template +OutputIter +unique_copy_dispatch(InputIter first, InputIter last, + OutputIter result, output_iterator_tag) +{ + auto value = *first; + *result = value; + while (++first != last) + { + if (value != *first) + { + value = *first; + *++result = value; + } + } + return ++result; +} + +template +OutputIter +unique_copy(InputIter first, InputIter last, OutputIter result) +{ + if (first == last) + return result; + return mystl::unique_copy_dispatch(first, last, result, iterator_category(result)); +} + +// 重载版本使用函数对象 comp 代替比较操作 +// unique_copy_dispatch 的 forward_iterator_tag 版本 +template +ForwardIter +unique_copy_dispatch(InputIter first, InputIter last, + ForwardIter result, forward_iterator_tag, Compared comp) +{ + *result = *first; + while (++first != last) + { + if (!comp(*result, *first)) + *++result = *first; + } + return ++result; +} + +// unique_copy_dispatch 的 output_iterator_tag 版本 +// 由于 output iterator 只能进行只读操作,所以不能有 *result != *first 这样的判断 +template +OutputIter +unique_copy_dispatch(InputIter first, InputIter last, + OutputIter result, output_iterator_tag, Compared comp) +{ + auto value = *first; + *result = value; + while (++first != last) + { + if (!comp(value, *first)) + { + value = *first; + *++result = value; + } + } + return ++result; +} + +template +OutputIter +unique_copy(InputIter first, InputIter last, OutputIter result, Compared comp) +{ + if (first == last) + return result; + return mystl::unique_copy_dispatch(first, last, result, iterator_category(result), comp); +} + +/*****************************************************************************************/ +// unique +// 移除[first, last)内重复的元素,序列必须有序,和 remove 类似,它也不能真正的删除重复元素 +/*****************************************************************************************/ +template +ForwardIter unique(ForwardIter first, ForwardIter last) +{ + first = mystl::adjacent_find(first, last); + return mystl::unique_copy(first, last, first); +} + +// 重载版本使用函数对象 comp 代替比较操作 +template +ForwardIter unique(ForwardIter first, ForwardIter last, Compared comp) +{ + first = mystl::adjacent_find(first, last, comp); + return mystl::unique_copy(first, last, first, comp); +} + +} // namespace mystl + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#endif // !MYTINYSTL_ALGO_H_ + diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/algobase.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/algobase.h new file mode 100644 index 0000000..f7342b5 --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/algobase.h @@ -0,0 +1,520 @@ +#ifndef MYTINYSTL_ALGOBASE_H_ +#define MYTINYSTL_ALGOBASE_H_ + +// 这个头文件包含了 mystl 的基本算法 + +#include + +#include "iterator.h" +#include "util.h" + +namespace mystl +{ + +#ifdef max +#pragma message("#undefing marco max") +#undef max +#endif // max + +#ifdef min +#pragma message("#undefing marco min") +#undef min +#endif // min + +/*****************************************************************************************/ +// max +// 取二者中的较大值,语义相等时保证返回第一个参数 +/*****************************************************************************************/ +template +const T& max(const T& lhs, const T& rhs) +{ + return lhs < rhs ? rhs : lhs; +} + +// 重载版本使用函数对象 comp 代替比较操作 +template +const T& max(const T& lhs, const T& rhs, Compare comp) +{ + return comp(lhs, rhs) ? rhs : lhs; +} + +/*****************************************************************************************/ +// min +// 取二者中的较小值,语义相等时保证返回第一个参数 +/*****************************************************************************************/ +template +const T& min(const T& lhs, const T& rhs) +{ + return rhs < lhs ? rhs : lhs; +} + +// 重载版本使用函数对象 comp 代替比较操作 +template +const T& min(const T& lhs, const T& rhs, Compare comp) +{ + return comp(rhs, lhs) ? rhs : lhs; +} + +/*****************************************************************************************/ +// iter_swap +// 将两个迭代器所指对象对调 +/*****************************************************************************************/ +template +void iter_swap(FIter1 lhs, FIter2 rhs) +{ + mystl::swap(*lhs, *rhs); +} + +/*****************************************************************************************/ +// copy +// 把 [first, last)区间内的元素拷贝到 [result, result + (last - first))内 +/*****************************************************************************************/ +// input_iterator_tag 版本 +template +OutputIter +unchecked_copy_cat(InputIter first, InputIter last, OutputIter result, + mystl::input_iterator_tag) +{ + for (; first != last; ++first, ++result) + { + *result = *first; + } + return result; +} + +// ramdom_access_iterator_tag 版本 +template +OutputIter +unchecked_copy_cat(RandomIter first, RandomIter last, OutputIter result, + mystl::random_access_iterator_tag) +{ + for (auto n = last - first; n > 0; --n, ++first, ++result) + { + *result = *first; + } + return result; +} + +template +OutputIter +unchecked_copy(InputIter first, InputIter last, OutputIter result) +{ + return unchecked_copy_cat(first, last, result, iterator_category(first)); +} + +// 为 trivially_copy_assignable 类型提供特化版本 +template +typename std::enable_if< + std::is_same::type, Up>::value && + std::is_trivially_copy_assignable::value, + Up*>::type +unchecked_copy(Tp* first, Tp* last, Up* result) +{ + const auto n = static_cast(last - first); + if (n != 0) + std::memmove(result, first, n * sizeof(Up)); + return result + n; +} + +template +OutputIter copy(InputIter first, InputIter last, OutputIter result) +{ + return unchecked_copy(first, last, result); +} + +/*****************************************************************************************/ +// copy_backward +// 将 [first, last)区间内的元素拷贝到 [result - (last - first), result)内 +/*****************************************************************************************/ +// unchecked_copy_backward_cat 的 bidirectional_iterator_tag 版本 +template +BidirectionalIter2 +unchecked_copy_backward_cat(BidirectionalIter1 first, BidirectionalIter1 last, + BidirectionalIter2 result, mystl::bidirectional_iterator_tag) +{ + while (first != last) + *--result = *--last; + return result; +} + +// unchecked_copy_backward_cat 的 random_access_iterator_tag 版本 +template +BidirectionalIter2 +unchecked_copy_backward_cat(RandomIter1 first, RandomIter1 last, + BidirectionalIter2 result, mystl::random_access_iterator_tag) +{ + for (auto n = last - first; n > 0; --n) + *--result = *--last; + return result; +} + +template +BidirectionalIter2 +unchecked_copy_backward(BidirectionalIter1 first, BidirectionalIter1 last, + BidirectionalIter2 result) +{ + return unchecked_copy_backward_cat(first, last, result, + iterator_category(first)); +} + +// 为 trivially_copy_assignable 类型提供特化版本 +template +typename std::enable_if< + std::is_same::type, Up>::value && + std::is_trivially_copy_assignable::value, + Up*>::type +unchecked_copy_backward(Tp* first, Tp* last, Up* result) +{ + const auto n = static_cast(last - first); + if (n != 0) + { + result -= n; + std::memmove(result, first, n * sizeof(Up)); + } + return result; +} + +template +BidirectionalIter2 +copy_backward(BidirectionalIter1 first, BidirectionalIter1 last, BidirectionalIter2 result) +{ + return unchecked_copy_backward(first, last, result); +} + +/*****************************************************************************************/ +// copy_if +// 把[first, last)内满足一元操作 unary_pred 的元素拷贝到以 result 为起始的位置上 +/*****************************************************************************************/ +template +OutputIter +copy_if(InputIter first, InputIter last, OutputIter result, UnaryPredicate unary_pred) +{ + for (; first != last; ++first) + { + if (unary_pred(*first)) + *result++ = *first; + } + return result; +} + +/*****************************************************************************************/ +// copy_n +// 把 [first, first + n)区间上的元素拷贝到 [result, result + n)上 +// 返回一个 pair 分别指向拷贝结束的尾部 +/*****************************************************************************************/ +template +mystl::pair +unchecked_copy_n(InputIter first, Size n, OutputIter result, mystl::input_iterator_tag) +{ + for (; n > 0; --n, ++first, ++result) + { + *result = *first; + } + return mystl::pair(first, result); +} + +template +mystl::pair +unchecked_copy_n(RandomIter first, Size n, OutputIter result, + mystl::random_access_iterator_tag) +{ + auto last = first + n; + return mystl::pair(last, mystl::copy(first, last, result)); +} + +template +mystl::pair +copy_n(InputIter first, Size n, OutputIter result) +{ + return unchecked_copy_n(first, n, result, iterator_category(first)); +} + +/*****************************************************************************************/ +// move +// 把 [first, last)区间内的元素移动到 [result, result + (last - first))内 +/*****************************************************************************************/ +// input_iterator_tag 版本 +template +OutputIter +unchecked_move_cat(InputIter first, InputIter last, OutputIter result, + mystl::input_iterator_tag) +{ + for (; first != last; ++first, ++result) + { + *result = mystl::move(*first); + } + return result; +} + +// ramdom_access_iterator_tag 版本 +template +OutputIter +unchecked_move_cat(RandomIter first, RandomIter last, OutputIter result, + mystl::random_access_iterator_tag) +{ + for (auto n = last - first; n > 0; --n, ++first, ++result) + { + *result = mystl::move(*first); + } + return result; +} + +template +OutputIter +unchecked_move(InputIter first, InputIter last, OutputIter result) +{ + return unchecked_move_cat(first, last, result, iterator_category(first)); +} + +// 为 trivially_copy_assignable 类型提供特化版本 +template +typename std::enable_if< + std::is_same::type, Up>::value && + std::is_trivially_move_assignable::value, + Up*>::type +unchecked_move(Tp* first, Tp* last, Up* result) +{ + const size_t n = static_cast(last - first); + if (n != 0) + std::memmove(result, first, n * sizeof(Up)); + return result + n; +} + +template +OutputIter move(InputIter first, InputIter last, OutputIter result) +{ + return unchecked_move(first, last, result); +} + +/*****************************************************************************************/ +// move_backward +// 将 [first, last)区间内的元素移动到 [result - (last - first), result)内 +/*****************************************************************************************/ +// bidirectional_iterator_tag 版本 +template +BidirectionalIter2 +unchecked_move_backward_cat(BidirectionalIter1 first, BidirectionalIter1 last, + BidirectionalIter2 result, mystl::bidirectional_iterator_tag) +{ + while (first != last) + *--result = mystl::move(*--last); + return result; +} + +// random_access_iterator_tag 版本 +template +RandomIter2 +unchecked_move_backward_cat(RandomIter1 first, RandomIter1 last, + RandomIter2 result, mystl::random_access_iterator_tag) +{ + for (auto n = last - first; n > 0; --n) + *--result = mystl::move(*--last); + return result; +} + +template +BidirectionalIter2 +unchecked_move_backward(BidirectionalIter1 first, BidirectionalIter1 last, + BidirectionalIter2 result) +{ + return unchecked_move_backward_cat(first, last, result, + iterator_category(first)); +} + +// 为 trivially_copy_assignable 类型提供特化版本 +template +typename std::enable_if< + std::is_same::type, Up>::value && + std::is_trivially_move_assignable::value, + Up*>::type +unchecked_move_backward(Tp* first, Tp* last, Up* result) +{ + const size_t n = static_cast(last - first); + if (n != 0) + { + result -= n; + std::memmove(result, first, n * sizeof(Up)); + } + return result; +} + +template +BidirectionalIter2 +move_backward(BidirectionalIter1 first, BidirectionalIter1 last, BidirectionalIter2 result) +{ + return unchecked_move_backward(first, last, result); +} + +/*****************************************************************************************/ +// equal +// 比较第一序列在 [first, last)区间上的元素值是否和第二序列相等 +/*****************************************************************************************/ +template +bool equal(InputIter1 first1, InputIter1 last1, InputIter2 first2) +{ + for (; first1 != last1; ++first1, ++first2) + { + if (*first1 != *first2) + return false; + } + return true; +} + +// 重载版本使用函数对象 comp 代替比较操作 +template +bool equal(InputIter1 first1, InputIter1 last1, InputIter2 first2, Compared comp) +{ + for (; first1 != last1; ++first1, ++first2) + { + if (!comp(*first1, *first2)) + return false; + } + return true; +} + +/*****************************************************************************************/ +// fill_n +// 从 first 位置开始填充 n 个值 +/*****************************************************************************************/ +template +OutputIter unchecked_fill_n(OutputIter first, Size n, const T& value) +{ + for (; n > 0; --n, ++first) + { + *first = value; + } + return first; +} + +// 为 one-byte 类型提供特化版本 +template +typename std::enable_if< + std::is_integral::value && sizeof(Tp) == 1 && + !std::is_same::value && + std::is_integral::value && sizeof(Up) == 1, + Tp*>::type +unchecked_fill_n(Tp* first, Size n, Up value) +{ + if (n > 0) + { + std::memset(first, (unsigned char)value, (size_t)(n)); + } + return first + n; +} + +template +OutputIter fill_n(OutputIter first, Size n, const T& value) +{ + return unchecked_fill_n(first, n, value); +} + +/*****************************************************************************************/ +// fill +// 为 [first, last)区间内的所有元素填充新值 +/*****************************************************************************************/ +template +void fill_cat(ForwardIter first, ForwardIter last, const T& value, + mystl::forward_iterator_tag) +{ + for (; first != last; ++first) + { + *first = value; + } +} + +template +void fill_cat(RandomIter first, RandomIter last, const T& value, + mystl::random_access_iterator_tag) +{ + fill_n(first, last - first, value); +} + +template +void fill(ForwardIter first, ForwardIter last, const T& value) +{ + fill_cat(first, last, value, iterator_category(first)); +} + +/*****************************************************************************************/ +// lexicographical_compare +// 以字典序排列对两个序列进行比较,当在某个位置发现第一组不相等元素时,有下列几种情况: +// (1)如果第一序列的元素较小,返回 true ,否则返回 false +// (2)如果到达 last1 而尚未到达 last2 返回 true +// (3)如果到达 last2 而尚未到达 last1 返回 false +// (4)如果同时到达 last1 和 last2 返回 false +/*****************************************************************************************/ +template +bool lexicographical_compare(InputIter1 first1, InputIter1 last1, + InputIter2 first2, InputIter2 last2) +{ + for (; first1 != last1 && first2 != last2; ++first1, ++first2) + { + if (*first1 < *first2) + return true; + if (*first2 < *first1) + return false; + } + return first1 == last1 && first2 != last2; +} + +// 重载版本使用函数对象 comp 代替比较操作 +template +bool lexicographical_compare(InputIter1 first1, InputIter1 last1, + InputIter2 first2, InputIter2 last2, Compred comp) +{ + for (; first1 != last1 && first2 != last2; ++first1, ++first2) + { + if (comp(*first1, *first2)) + return true; + if (comp(*first2, *first1)) + return false; + } + return first1 == last1 && first2 != last2; +} + +// 针对 const unsigned char* 的特化版本 +bool lexicographical_compare(const unsigned char* first1, + const unsigned char* last1, + const unsigned char* first2, + const unsigned char* last2) +{ + const auto len1 = last1 - first1; + const auto len2 = last2 - first2; + // 先比较相同长度的部分 + const auto result = std::memcmp(first1, first2, mystl::min(len1, len2)); + // 若相等,长度较长的比较大 + return result != 0 ? result < 0 : len1 < len2; +} + +/*****************************************************************************************/ +// mismatch +// 平行比较两个序列,找到第一处失配的元素,返回一对迭代器,分别指向两个序列中失配的元素 +/*****************************************************************************************/ +template +mystl::pair +mismatch(InputIter1 first1, InputIter1 last1, InputIter2 first2) +{ + while (first1 != last1 && *first1 == *first2) + { + ++first1; + ++first2; + } + return mystl::pair(first1, first2); +} + +// 重载版本使用函数对象 comp 代替比较操作 +template +mystl::pair +mismatch(InputIter1 first1, InputIter1 last1, InputIter2 first2, Compred comp) +{ + while (first1 != last1 && comp(*first1, *first2)) + { + ++first1; + ++first2; + } + return mystl::pair(first1, first2); +} + +} // namespace mystl +#endif // !MYTINYSTL_ALGOBASE_H_ + diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/algorithm.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/algorithm.h new file mode 100644 index 0000000..ee99e4f --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/algorithm.h @@ -0,0 +1,18 @@ +#ifndef MYTINYSTL_ALGORITHM_H_ +#define MYTINYSTL_ALGORITHM_H_ + +// 这个头文件包含了 mystl 的所有算法,包括基本算法,数值算法,heap 算法,set 算法和其他算法 + +#include "algobase.h" +#include "algo.h" +#include "set_algo.h" +#include "heap_algo.h" +#include "numeric.h" + +namespace mystl +{ + +} // namespace mystl + +#endif // !MYTINYSTL_ALGORITHM_H_ + diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/alloc.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/alloc.h new file mode 100644 index 0000000..93d3bcf --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/alloc.h @@ -0,0 +1,264 @@ +#ifndef MYTINYSTL_ALLOC_H_ +#define MYTINYSTL_ALLOC_H_ + +// 这个头文件包含一个类 alloc,用于分配和回收内存,以内存池的方式实现 +// +// 从 v2.0.0 版本开始,将不再使用内存池,这个文件将被弃用,但暂时保留 +// +// 注意!!! +// 我知道这个文件里很多实现是错的,这是很久很久前写的了,后面已经不用这个东西了, +// 所以我也没再维护,有诸多问题,已经有人在issue中都提了,free_list的修改, +// 指针作为参数时没实际修改到原指针,等等。相信会看这么仔细的,大部分都是 +// 初学C++的朋友,大佬都不会看这些玩具了,所以其中的错误,就留给对内存池实现 +// 感兴趣的朋友去修改啦! + +#include + +#include +#include + +namespace mystl +{ + +// 共用体: FreeList +// 采用链表的方式管理内存碎片,分配与回收小内存(<=4K)区块 +union FreeList +{ + union FreeList* next; // 指向下一个区块 + char data[1]; // 储存本块内存的首地址 +}; + +// 不同内存范围的上调大小 +enum +{ + EAlign128 = 8, + EAlign256 = 16, + EAlign512 = 32, + EAlign1024 = 64, + EAlign2048 = 128, + EAlign4096 = 256 +}; + +// 小对象的内存大小 +enum { ESmallObjectBytes = 4096 }; + +// free lists 个数 +enum { EFreeListsNumber = 56 }; + +// 空间配置类 alloc +// 如果内存较大,超过 4096 bytes,直接调用 std::malloc, std::free +// 当内存较小时,以内存池管理,每次配置一大块内存,并维护对应的自由链表 +class alloc +{ +private: + static char* start_free; // 内存池起始位置 + static char* end_free; // 内存池结束位置 + static size_t heap_size; // 申请 heap 空间附加值大小 + + static FreeList* free_list[EFreeListsNumber]; // 自由链表 + +public: + static void* allocate(size_t n); + static void deallocate(void* p, size_t n); + static void* reallocate(void* p, size_t old_size, size_t new_size); + +private: + static size_t M_align(size_t bytes); + static size_t M_round_up(size_t bytes); + static size_t M_freelist_index(size_t bytes); + static void* M_refill(size_t n); + static char* M_chunk_alloc(size_t size, size_t &nobj); +}; + +// 静态成员变量初始化 + +char* alloc::start_free = nullptr; +char* alloc::end_free = nullptr; +size_t alloc::heap_size = 0; + +FreeList* alloc::free_list[EFreeListsNumber] = { + nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr, + nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr, + nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr, + nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr, + nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr, + nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr, + nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr + }; + +// 分配大小为 n 的空间, n > 0 +inline void* alloc::allocate(size_t n) +{ + FreeList* my_free_list; + FreeList* result; + if (n > static_cast(ESmallObjectBytes)) + return std::malloc(n); + my_free_list = free_list[M_freelist_index(n)]; + result = my_free_list; + if (result == nullptr) + { + void* r = M_refill(M_round_up(n)); + return r; + } + my_free_list = result->next; + return result; +} + +// 释放 p 指向的大小为 n 的空间, p 不能为 0 +inline void alloc::deallocate(void* p, size_t n) +{ + if (n > static_cast(ESmallObjectBytes)) + { + std::free(p); + return; + } + FreeList* q = reinterpret_cast(p); + FreeList* my_free_list; + my_free_list = free_list[M_freelist_index(n)]; + q->next = my_free_list; + my_free_list = q; +} + +// 重新分配空间,接受三个参数,参数一为指向新空间的指针,参数二为原来空间的大小,参数三为申请空间的大小 +inline void* alloc::reallocate(void* p, size_t old_size, size_t new_size) +{ + deallocate(p, old_size); + p = allocate(new_size); + return p; +} + +// bytes 对应上调大小 +inline size_t alloc::M_align(size_t bytes) +{ + if (bytes <= 512) + { + return bytes <= 256 + ? bytes <= 128 ? EAlign128 : EAlign256 + : EAlign512; + } + return bytes <= 2048 + ? bytes <= 1024 ? EAlign1024 : EAlign2048 + : EAlign4096; +} + +// 将 bytes 上调至对应区间大小 +inline size_t alloc::M_round_up(size_t bytes) +{ + return ((bytes + M_align(bytes) - 1) & ~(M_align(bytes) - 1)); +} + +// 根据区块大小,选择第 n 个 free lists +inline size_t alloc::M_freelist_index(size_t bytes) +{ + if (bytes <= 512) + { + return bytes <= 256 + ? bytes <= 128 + ? ((bytes + EAlign128 - 1) / EAlign128 - 1) + : (15 + (bytes + EAlign256 - 129) / EAlign256) + : (23 + (bytes + EAlign512 - 257) / EAlign512); + } + return bytes <= 2048 + ? bytes <= 1024 + ? (31 + (bytes + EAlign1024 - 513) / EAlign1024) + : (39 + (bytes + EAlign2048 - 1025) / EAlign2048) + : (47 + (bytes + EAlign4096 - 2049) / EAlign4096); +} + +// 重新填充 free list +void* alloc::M_refill(size_t n) +{ + size_t nblock = 10; + char* c = M_chunk_alloc(n, nblock); + FreeList* my_free_list; + FreeList* result, *cur, *next; + // 如果只有一个区块,就把这个区块返回给调用者,free list 没有增加新节点 + if (nblock == 1) + return c; + // 否则把一个区块给调用者,剩下的纳入 free list 作为新节点 + my_free_list = free_list[M_freelist_index(n)]; + result = (FreeList*)c; + my_free_list = next = (FreeList*)(c + n); + for (size_t i = 1; ; ++i) + { + cur = next; + next = (FreeList*)((char*)next + n); + if (nblock - 1 == i) + { + cur->next = nullptr; + break; + } + else + { + cur->next = next; + } + } + return result; +} + +// 从内存池中取空间给 free list 使用,条件不允许时,会调整 nblock +char* alloc::M_chunk_alloc(size_t size, size_t& nblock) +{ + char* result; + size_t need_bytes = size * nblock; + size_t pool_bytes = end_free - start_free; + + // 如果内存池剩余大小完全满足需求量,返回它 + if (pool_bytes >= need_bytes) + { + result = start_free; + start_free += need_bytes; + return result; + } + + // 如果内存池剩余大小不能完全满足需求量,但至少可以分配一个或一个以上的区块,就返回它 + else if (pool_bytes >= size) + { + nblock = pool_bytes / size; + need_bytes = size * nblock; + result = start_free; + start_free += need_bytes; + return result; + } + + // 如果内存池剩余大小连一个区块都无法满足 + else + { + if (pool_bytes > 0) + { // 如果内存池还有剩余,把剩余的空间加入到 free list 中 + FreeList* my_free_list = free_list[M_freelist_index(pool_bytes)]; + ((FreeList*)start_free)->next = my_free_list; + my_free_list = (FreeList*)start_free; + } + // 申请 heap 空间 + size_t bytes_to_get = (need_bytes << 1) + M_round_up(heap_size >> 4); + start_free = (char*)std::malloc(bytes_to_get); + if (!start_free) + { // heap 空间也不够 + FreeList* my_free_list, *p; + // 试着查找有无未用区块,且区块足够大的 free list + for (size_t i = size; i <= ESmallObjectBytes; i += M_align(i)) + { + my_free_list = free_list[M_freelist_index(i)]; + p = my_free_list; + if (p) + { + my_free_list = p->next; + start_free = (char*)p; + end_free = start_free + i; + return M_chunk_alloc(size, nblock); + } + } + std::printf("out of memory"); + end_free = nullptr; + throw std::bad_alloc(); + } + end_free = start_free + bytes_to_get; + heap_size += bytes_to_get; + return M_chunk_alloc(size, nblock); + } +} + +} // namespace mystl +#endif // !MYTINYSTL_ALLOC_H_ + diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/allocator.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/allocator.h new file mode 100644 index 0000000..a3a5d4e --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/allocator.h @@ -0,0 +1,113 @@ +#ifndef MYTINYSTL_ALLOCATOR_H_ +#define MYTINYSTL_ALLOCATOR_H_ + +// 这个头文件包含一个模板类 allocator,用于管理内存的分配、释放,对象的构造、析构 + +#include "construct.h" +#include "util.h" + +namespace mystl +{ + +// 模板类:allocator +// 模板函数代表数据类型 +template +class allocator +{ +public: + typedef T value_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + +public: + static T* allocate(); + static T* allocate(size_type n); + + static void deallocate(T* ptr); + static void deallocate(T* ptr, size_type n); + + static void construct(T* ptr); + static void construct(T* ptr, const T& value); + static void construct(T* ptr, T&& value); + + template + static void construct(T* ptr, Args&& ...args); + + static void destroy(T* ptr); + static void destroy(T* first, T* last); +}; + +template +T* allocator::allocate() +{ + return static_cast(::operator new(sizeof(T))); +} + +template +T* allocator::allocate(size_type n) +{ + if (n == 0) + return nullptr; + return static_cast(::operator new(n * sizeof(T))); +} + +template +void allocator::deallocate(T* ptr) +{ + if (ptr == nullptr) + return; + ::operator delete(ptr); +} + +template +void allocator::deallocate(T* ptr, size_type /*size*/) +{ + if (ptr == nullptr) + return; + ::operator delete(ptr); +} + +template +void allocator::construct(T* ptr) +{ + mystl::construct(ptr); +} + +template +void allocator::construct(T* ptr, const T& value) +{ + mystl::construct(ptr, value); +} + +template + void allocator::construct(T* ptr, T&& value) +{ + mystl::construct(ptr, mystl::move(value)); +} + +template +template + void allocator::construct(T* ptr, Args&& ...args) +{ + mystl::construct(ptr, mystl::forward(args)...); +} + +template +void allocator::destroy(T* ptr) +{ + mystl::destroy(ptr); +} + +template +void allocator::destroy(T* first, T* last) +{ + mystl::destroy(first, last); +} + +} // namespace mystl +#endif // !MYTINYSTL_ALLOCATOR_H_ + diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/astring.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/astring.h new file mode 100644 index 0000000..0bf7adc --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/astring.h @@ -0,0 +1,18 @@ +#ifndef MYTINYSTL_ASTRING_H_ +#define MYTINYSTL_ASTRING_H_ + +// 定义了 string, wstring, u16string, u32string 类型 + +#include "basic_string.h" + +namespace mystl +{ + +using string = mystl::basic_string; +using wstring = mystl::basic_string; +using u16string = mystl::basic_string; +using u32string = mystl::basic_string; + +} +#endif // !MYTINYSTL_ASTRING_H_ + diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/basic_string.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/basic_string.h new file mode 100644 index 0000000..668ca5c --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/basic_string.h @@ -0,0 +1,2075 @@ +#ifndef MYTINYSTL_BASIC_STRING_H_ +#define MYTINYSTL_BASIC_STRING_H_ + +// 这个头文件包含一个模板类 basic_string +// 用于表示字符串类型 + +#include + +#include "iterator.h" +#include "memory.h" +#include "functional.h" +#include "exceptdef.h" + +namespace mystl +{ + +// char_traits + +template +struct char_traits +{ + typedef CharType char_type; + + static size_t length(const char_type* str) + { + size_t len = 0; + for (; *str != char_type(0); ++str) + ++len; + return len; + } + + static int compare(const char_type* s1, const char_type* s2, size_t n) + { + for (; n != 0; --n, ++s1, ++s2) + { + if (*s1 < *s2) + return -1; + if (*s2 < *s1) + return 1; + } + return 0; + } + + static char_type* copy(char_type* dst, const char_type* src, size_t n) + { + MYSTL_DEBUG(src + n <= dst || dst + n <= src); + char_type* r = dst; + for (; n != 0; --n, ++dst, ++src) + *dst = *src; + return r; + } + + static char_type* move(char_type* dst, const char_type* src, size_t n) + { + char_type* r = dst; + if (dst < src) + { + for (; n != 0; --n, ++dst, ++src) + *dst = *src; + } + else if (src < dst) + { + dst += n; + src += n; + for (; n != 0; --n) + *--dst = *--src; + } + return r; + } + + static char_type* fill(char_type* dst, char_type ch, size_t count) + { + char_type* r = dst; + for (; count > 0; --count, ++dst) + *dst = ch; + return r; + } +}; + +// Partialized. char_traits +template <> +struct char_traits +{ + typedef char char_type; + + static size_t length(const char_type* str) noexcept + { return std::strlen(str); } + + static int compare(const char_type* s1, const char_type* s2, size_t n) noexcept + { return std::memcmp(s1, s2, n); } + + static char_type* copy(char_type* dst, const char_type* src, size_t n) noexcept + { + MYSTL_DEBUG(src + n <= dst || dst + n <= src); + return static_cast(std::memcpy(dst, src, n)); + } + + static char_type* move(char_type* dst, const char_type* src, size_t n) noexcept + { + return static_cast(std::memmove(dst, src, n)); + } + + static char_type* fill(char_type* dst, char_type ch, size_t count) noexcept + { + return static_cast(std::memset(dst, ch, count)); + } +}; + +// Partialized. char_traits +template <> +struct char_traits +{ + typedef wchar_t char_type; + + static size_t length(const char_type* str) noexcept + { + return std::wcslen(str); + } + + static int compare(const char_type* s1, const char_type* s2, size_t n) noexcept + { + return std::wmemcmp(s1, s2, n); + } + + static char_type* copy(char_type* dst, const char_type* src, size_t n) noexcept + { + MYSTL_DEBUG(src + n <= dst || dst + n <= src); + return static_cast(std::wmemcpy(dst, src, n)); + } + + static char_type* move(char_type* dst, const char_type* src, size_t n) noexcept + { + return static_cast(std::wmemmove(dst, src, n)); + } + + static char_type* fill(char_type* dst, char_type ch, size_t count) noexcept + { + return static_cast(std::wmemset(dst, ch, count)); + } +}; + +// Partialized. char_traits +template <> +struct char_traits +{ + typedef char16_t char_type; + + static size_t length(const char_type* str) noexcept + { + size_t len = 0; + for (; *str != char_type(0); ++str) + ++len; + return len; + } + + static int compare(const char_type* s1, const char_type* s2, size_t n) noexcept + { + for (; n != 0; --n, ++s1, ++s2) + { + if (*s1 < *s2) + return -1; + if (*s2 < *s1) + return 1; + } + return 0; + } + + static char_type* copy(char_type* dst, const char_type* src, size_t n) noexcept + { + MYSTL_DEBUG(src + n <= dst || dst + n <= src); + char_type* r = dst; + for (; n != 0; --n, ++dst, ++src) + *dst = *src; + return r; + } + + static char_type* move(char_type* dst, const char_type* src, size_t n) noexcept + { + char_type* r = dst; + if (dst < src) + { + for (; n != 0; --n, ++dst, ++src) + *dst = *src; + } + else if (src < dst) + { + dst += n; + src += n; + for (; n != 0; --n) + *--dst = *--src; + } + return r; + } + + static char_type* fill(char_type* dst, char_type ch, size_t count) noexcept + { + char_type* r = dst; + for (; count > 0; --count, ++dst) + *dst = ch; + return r; + } +}; + +// Partialized. char_traits +template <> +struct char_traits +{ + typedef char32_t char_type; + + static size_t length(const char_type* str) noexcept + { + size_t len = 0; + for (; *str != char_type(0); ++str) + ++len; + return len; + } + + static int compare(const char_type* s1, const char_type* s2, size_t n) noexcept + { + for (; n != 0; --n, ++s1, ++s2) + { + if (*s1 < *s2) + return -1; + if (*s2 < *s1) + return 1; + } + return 0; + } + + static char_type* copy(char_type* dst, const char_type* src, size_t n) noexcept + { + MYSTL_DEBUG(src + n <= dst || dst + n <= src); + char_type* r = dst; + for (; n != 0; --n, ++dst, ++src) + *dst = *src; + return r; + } + + static char_type* move(char_type* dst, const char_type* src, size_t n) noexcept + { + char_type* r = dst; + if (dst < src) + { + for (; n != 0; --n, ++dst, ++src) + *dst = *src; + } + else if (src < dst) + { + dst += n; + src += n; + for (; n != 0; --n) + *--dst = *--src; + } + return r; + } + + static char_type* fill(char_type* dst, char_type ch, size_t count) noexcept + { + char_type* r = dst; + for (; count > 0; --count, ++dst) + *dst = ch; + return r; + } +}; + +// 初始化 basic_string 尝试分配的最小 buffer 大小,可能被忽略 +#define STRING_INIT_SIZE 32 + +// 模板类 basic_string +// 参数一代表字符类型,参数二代表萃取字符类型的方式,缺省使用 mystl::char_traits +template > +class basic_string +{ +public: + typedef CharTraits traits_type; + typedef CharTraits char_traits; + + typedef mystl::allocator allocator_type; + typedef mystl::allocator data_allocator; + + typedef typename allocator_type::value_type value_type; + typedef typename allocator_type::pointer pointer; + typedef typename allocator_type::const_pointer const_pointer; + typedef typename allocator_type::reference reference; + typedef typename allocator_type::const_reference const_reference; + typedef typename allocator_type::size_type size_type; + typedef typename allocator_type::difference_type difference_type; + + typedef value_type* iterator; + typedef const value_type* const_iterator; + typedef mystl::reverse_iterator reverse_iterator; + typedef mystl::reverse_iterator const_reverse_iterator; + + allocator_type get_allocator() { return allocator_type(); } + + static_assert(std::is_pod::value, "Character type of basic_string must be a POD"); + static_assert(std::is_same::value, + "CharType must be same as traits_type::char_type"); + +public: + // 末尾位置的值,例: + // if (str.find('a') != string::npos) { /* do something */ } + static constexpr size_type npos = static_cast(-1); + +private: + iterator buffer_; // 储存字符串的起始位置 + size_type size_; // 大小 + size_type cap_; // 容量 + +public: + // 构造、复制、移动、析构函数 + + basic_string() noexcept + { try_init(); } + + basic_string(size_type n, value_type ch) + :buffer_(nullptr), size_(0), cap_(0) + { + fill_init(n, ch); + } + + basic_string(const basic_string& other, size_type pos) + :buffer_(nullptr), size_(0), cap_(0) + { + init_from(other.buffer_, pos, other.size_ - pos); + } + basic_string(const basic_string& other, size_type pos, size_type count) + :buffer_(nullptr), size_(0), cap_(0) + { + init_from(other.buffer_, pos, count); + } + + basic_string(const_pointer str) + :buffer_(nullptr), size_(0), cap_(0) + { + init_from(str, 0, char_traits::length(str)); + } + basic_string(const_pointer str, size_type count) + :buffer_(nullptr), size_(0), cap_(0) + { + init_from(str, 0, count); + } + + template ::value, int>::type = 0> + basic_string(Iter first, Iter last) + { copy_init(first, last, iterator_category(first)); } + + basic_string(const basic_string& rhs) + :buffer_(nullptr), size_(0), cap_(0) + { + init_from(rhs.buffer_, 0, rhs.size_); + } + basic_string(basic_string&& rhs) noexcept + :buffer_(rhs.buffer_), size_(rhs.size_), cap_(rhs.cap_) + { + rhs.buffer_ = nullptr; + rhs.size_ = 0; + rhs.cap_ = 0; + } + + basic_string& operator=(const basic_string& rhs); + basic_string& operator=(basic_string&& rhs) noexcept; + + basic_string& operator=(const_pointer str); + basic_string& operator=(value_type ch); + + ~basic_string() { destroy_buffer(); } + +public: + // 迭代器相关操作 + iterator begin() noexcept + { return buffer_; } + const_iterator begin() const noexcept + { return buffer_; } + iterator end() noexcept + { return buffer_ + size_; } + const_iterator end() const noexcept + { return buffer_ + size_; } + + reverse_iterator rbegin() noexcept + { return reverse_iterator(end()); } + const_reverse_iterator rbegin() const noexcept + { return const_reverse_iterator(end()); } + reverse_iterator rend() noexcept + { return reverse_iterator(begin()); } + const_reverse_iterator rend() const noexcept + { return const_reverse_iterator(begin()); } + + const_iterator cbegin() const noexcept + { return begin(); } + const_iterator cend() const noexcept + { return end(); } + const_reverse_iterator crbegin() const noexcept + { return rbegin(); } + const_reverse_iterator crend() const noexcept + { return rend(); } + + // 容量相关操作 + bool empty() const noexcept + { return size_ == 0; } + + size_type size() const noexcept + { return size_; } + size_type length() const noexcept + { return size_; } + size_type capacity() const noexcept + { return cap_; } + size_type max_size() const noexcept + { return static_cast(-1); } + + void reserve(size_type n); + void shrink_to_fit(); + + // 访问元素相关操作 + reference operator[](size_type n) + { + MYSTL_DEBUG(n <= size_); + if (n == size_) + *(buffer_ + n) = value_type(); + return *(buffer_ + n); + } + const_reference operator[](size_type n) const + { + MYSTL_DEBUG(n <= size_); + if (n == size_) + *(buffer_ + n) = value_type(); + return *(buffer_ + n); + } + + reference at(size_type n) + { + THROW_OUT_OF_RANGE_IF(n >= size_, "basic_string::at()" + "subscript out of range"); + return (*this)[n]; + } + const_reference at(size_type n) const + { + THROW_OUT_OF_RANGE_IF(n >= size_, "basic_string::at()" + "subscript out of range"); + return (*this)[n]; + } + + reference front() + { + MYSTL_DEBUG(!empty()); + return *begin(); + } + const_reference front() const + { + MYSTL_DEBUG(!empty()); + return *begin(); + } + + reference back() + { + MYSTL_DEBUG(!empty()); + return *(end() - 1); + } + const_reference back() const + { + MYSTL_DEBUG(!empty()); + return *(end() - 1); + } + + const_pointer data() const noexcept + { return to_raw_pointer(); } + const_pointer c_str() const noexcept + { return to_raw_pointer(); } + + // 添加删除相关操作 + + // insert + iterator insert(const_iterator pos, value_type ch); + iterator insert(const_iterator pos, size_type count, value_type ch); + + template + iterator insert(const_iterator pos, Iter first, Iter last); + + + // push_back / pop_back + void push_back(value_type ch) + { append(1, ch); } + void pop_back() + { + MYSTL_DEBUG(!empty()); + --size_; + } + + // append + basic_string& append(size_type count, value_type ch); + + basic_string& append(const basic_string& str) + { return append(str, 0, str.size_); } + basic_string& append(const basic_string& str, size_type pos) + { return append(str, pos, str.size_ - pos); } + basic_string& append(const basic_string& str, size_type pos, size_type count); + + basic_string& append(const_pointer s) + { return append(s, char_traits::length(s)); } + basic_string& append(const_pointer s, size_type count); + + template ::value, int>::type = 0> + basic_string& append(Iter first, Iter last) + { return append_range(first, last); } + + // erase /clear + iterator erase(const_iterator pos); + iterator erase(const_iterator first, const_iterator last); + + // resize + void resize(size_type count) + { resize(count, value_type()); } + void resize(size_type count, value_type ch); + + void clear() noexcept + { size_ = 0; } + + // basic_string 相关操作 + + // compare + int compare(const basic_string& other) const; + int compare(size_type pos1, size_type count1, const basic_string& other) const; + int compare(size_type pos1, size_type count1, const basic_string& other, + size_type pos2, size_type count2 = npos) const; + int compare(const_pointer s) const; + int compare(size_type pos1, size_type count1, const_pointer s) const; + int compare(size_type pos1, size_type count1, const_pointer s, size_type count2) const; + + // substr + basic_string substr(size_type index, size_type count = npos) + { + count = mystl::min(count, size_ - index); + return basic_string(buffer_ + index, buffer_ + index + count); + } + + // replace + basic_string& replace(size_type pos, size_type count, const basic_string& str) + { + THROW_OUT_OF_RANGE_IF(pos > size_, "basic_string::replace's pos out of range"); + return replace_cstr(buffer_ + pos, count, str.buffer_, str.size_); + } + basic_string& replace(const_iterator first, const_iterator last, const basic_string& str) + { + MYSTL_DEBUG(begin() <= first && last <= end() && first <= last); + return replace_cstr(first, static_cast(last - first), str.buffer_, str.size_); + } + + basic_string& replace(size_type pos, size_type count, const_pointer str) + { + THROW_OUT_OF_RANGE_IF(pos > size_, "basic_string::replace's pos out of range"); + return replace_cstr(buffer_ + pos, count, str, char_traits::length(str)); + } + basic_string& replace(const_iterator first, const_iterator last, const_pointer str) + { + MYSTL_DEBUG(begin() <= first && last <= end() && first <= last); + return replace_cstr(first, static_cast(last - first), str, char_traits::length(str)); + } + + basic_string& replace(size_type pos, size_type count, const_pointer str, size_type count2) + { + THROW_OUT_OF_RANGE_IF(pos > size_, "basic_string::replace's pos out of range"); + return replace_cstr(buffer_ + pos, count, str, count2); + } + basic_string& replace(const_iterator first, const_iterator last, const_pointer str, size_type count) + { + MYSTL_DEBUG(begin() <= first && last <= end() && first <= last); + return replace_cstr(first, static_cast(last - first), str, count); + + } + + basic_string& replace(size_type pos, size_type count, size_type count2, value_type ch) + { + THROW_OUT_OF_RANGE_IF(pos > size_, "basic_string::replace's pos out of range"); + return replace_fill(buffer_ + pos, count, count2, ch); + } + basic_string& replace(const_iterator first, const_iterator last, size_type count, value_type ch) + { + MYSTL_DEBUG(begin() <= first && last <= end() && first <= last); + return replace_fill(first, static_cast(last - first), count, ch); + } + + basic_string& replace(size_type pos1, size_type count1, const basic_string& str, + size_type pos2, size_type count2 = npos) + { + THROW_OUT_OF_RANGE_IF(pos1 > size_ || pos2 > str.size_, + "basic_string::replace's pos out of range"); + return replace_cstr(buffer_ + pos1, count1, str.buffer_ + pos2, count2); + } + + template ::value, int>::type = 0> + basic_string& replace(const_iterator first, const_iterator last, Iter first2, Iter last2) + { + MYSTL_DEBUG(begin() <= first && last <= end() && first <= last); + return replace_copy(first, last, first2, last2); + } + + // reverse + void reverse() noexcept; + + // swap + void swap(basic_string& rhs) noexcept; + + // 查找相关操作 + + // find + size_type find(value_type ch, size_type pos = 0) const noexcept; + size_type find(const_pointer str, size_type pos = 0) const noexcept; + size_type find(const_pointer str, size_type pos, size_type count) const noexcept; + size_type find(const basic_string& str, size_type pos = 0) const noexcept; + + // rfind + size_type rfind(value_type ch, size_type pos = npos) const noexcept; + size_type rfind(const_pointer str, size_type pos = npos) const noexcept; + size_type rfind(const_pointer str, size_type pos, size_type count) const noexcept; + size_type rfind(const basic_string& str, size_type pos = npos) const noexcept; + + // find_first_of + size_type find_first_of(value_type ch, size_type pos = 0) const noexcept; + size_type find_first_of(const_pointer s, size_type pos = 0) const noexcept; + size_type find_first_of(const_pointer s, size_type pos, size_type count) const noexcept; + size_type find_first_of(const basic_string& str, size_type pos = 0) const noexcept; + + // find_first_not_of + size_type find_first_not_of(value_type ch, size_type pos = 0) const noexcept; + size_type find_first_not_of(const_pointer s, size_type pos = 0) const noexcept; + size_type find_first_not_of(const_pointer s, size_type pos, size_type count) const noexcept; + size_type find_first_not_of(const basic_string& str, size_type pos = 0) const noexcept; + + // find_last_of + size_type find_last_of(value_type ch, size_type pos = 0) const noexcept; + size_type find_last_of(const_pointer s, size_type pos = 0) const noexcept; + size_type find_last_of(const_pointer s, size_type pos, size_type count) const noexcept; + size_type find_last_of(const basic_string& str, size_type pos = 0) const noexcept; + + // find_last_not_of + size_type find_last_not_of(value_type ch, size_type pos = 0) const noexcept; + size_type find_last_not_of(const_pointer s, size_type pos = 0) const noexcept; + size_type find_last_not_of(const_pointer s, size_type pos, size_type count) const noexcept; + size_type find_last_not_of(const basic_string& str, size_type pos = 0) const noexcept; + + // count + size_type count(value_type ch, size_type pos = 0) const noexcept; + +public: + // 重载 operator+= + basic_string& operator+=(const basic_string& str) + { return append(str); } + basic_string& operator+=(value_type ch) + { return append(1, ch); } + basic_string& operator+=(const_pointer str) + { return append(str, str + char_traits::length(str)); } + + // 重载 operator >> / operatror << + + friend std::istream& operator >> (std::istream& is, basic_string& str) + { + value_type* buf = new value_type[4096]; + is >> buf; + basic_string tmp(buf); + str = std::move(tmp); + delete[]buf; + return is; + } + + friend std::ostream& operator << (std::ostream& os, const basic_string& str) + { + for (size_type i = 0; i < str.size_; ++i) + os << *(str.buffer_ + i); + return os; + } + +private: + // helper functions + + // init / destroy + void try_init() noexcept; + + void fill_init(size_type n, value_type ch); + + template + void copy_init(Iter first, Iter last, mystl::input_iterator_tag); + template + void copy_init(Iter first, Iter last, mystl::forward_iterator_tag); + + void init_from(const_pointer src, size_type pos, size_type n); + + void destroy_buffer(); + + // get raw pointer + const_pointer to_raw_pointer() const; + + // shrink_to_fit + void reinsert(size_type size); + + // append + template + basic_string& append_range(Iter first, Iter last); + + // compare + int compare_cstr(const_pointer s1, size_type n1, const_pointer s2, size_type n2) const; + + // replace + basic_string& replace_cstr(const_iterator first, size_type count1, const_pointer str, size_type count2); + basic_string& replace_fill(const_iterator first, size_type count1, size_type count2, value_type ch); + template + basic_string& replace_copy(const_iterator first, const_iterator last, Iter first2, Iter last2); + + // reallocate + void reallocate(size_type need); + iterator reallocate_and_fill(iterator pos, size_type n, value_type ch); + iterator reallocate_and_copy(iterator pos, const_iterator first, const_iterator last); +}; + +/*****************************************************************************************/ + +// 复制赋值操作符 +template +basic_string& +basic_string:: +operator=(const basic_string& rhs) +{ + if (this != &rhs) + { + basic_string tmp(rhs); + swap(tmp); + } + return *this; +} + +// 移动赋值操作符 +template +basic_string& +basic_string:: +operator=(basic_string&& rhs) noexcept +{ + destroy_buffer(); + buffer_ = rhs.buffer_; + size_ = rhs.size_; + cap_ = rhs.cap_; + rhs.buffer_ = nullptr; + rhs.size_ = 0; + rhs.cap_ = 0; + return *this; +} + +// 用一个字符串赋值 +template +basic_string& +basic_string:: +operator=(const_pointer str) +{ + const size_type len = char_traits::length(str); + if (cap_ < len) + { + auto new_buffer = data_allocator::allocate(len + 1); + data_allocator::deallocate(buffer_); + buffer_ = new_buffer; + cap_ = len + 1; + } + char_traits::copy(buffer_, str, len); + size_ = len; + return *this; +} + +// 用一个字符赋值 +template +basic_string& +basic_string:: +operator=(value_type ch) +{ + if (cap_ < 1) + { + auto new_buffer = data_allocator::allocate(2); + data_allocator::deallocate(buffer_); + buffer_ = new_buffer; + cap_ = 2; + } + *buffer_ = ch; + size_ = 1; + return *this; +} + +// 预留储存空间 +template +void basic_string:: +reserve(size_type n) +{ + if (cap_ < n) + { + THROW_LENGTH_ERROR_IF(n > max_size(), "n can not larger than max_size()" + "in basic_string::reserve(n)"); + auto new_buffer = data_allocator::allocate(n); + char_traits::move(new_buffer, buffer_, size_); + buffer_ = new_buffer; + cap_ = n; + } +} + +// 减少不用的空间 +template +void basic_string:: +shrink_to_fit() +{ + if (size_ != cap_) + { + reinsert(size_); + } +} + +// 在 pos 处插入一个元素 +template +typename basic_string::iterator +basic_string:: +insert(const_iterator pos, value_type ch) +{ + iterator r = const_cast(pos); + if (size_ == cap_) + { + return reallocate_and_fill(r, 1, ch); + } + char_traits::move(r + 1, r, end() - r); + ++size_; + *r = ch; + return r; +} + +// 在 pos 处插入 n 个元素 +template +typename basic_string::iterator +basic_string:: +insert(const_iterator pos, size_type count, value_type ch) +{ + iterator r = const_cast(pos); + if (count == 0) + return r; + if (cap_ - size_ < count) + { + return reallocate_and_fill(r, count, ch); + } + if (pos == end()) + { + char_traits::fill(end(), ch, count); + size_ += count; + return r; + } + char_traits::move(r + count, r, count); + char_traits::fill(r, ch, count); + size_ += count; + return r; +} + +// 在 pos 处插入 [first, last) 内的元素 +template +template +typename basic_string::iterator +basic_string:: +insert(const_iterator pos, Iter first, Iter last) +{ + iterator r = const_cast(pos); + const size_type len = mystl::distance(first, last); + if (len == 0) + return r; + if (cap_ - size_ < len) + { + return reallocate_and_copy(r, first, last); + } + if (pos == end()) + { + mystl::uninitialized_copy(first, last, end()); + size_ += len; + return r; + } + char_traits::move(r + len, r, len); + mystl::uninitialized_copy(first, last, r); + size_ += len; + return r; +} + +// 在末尾添加 count 个 ch +template +basic_string& +basic_string:: +append(size_type count, value_type ch) +{ + THROW_LENGTH_ERROR_IF(size_ > max_size() - count, + "basic_string's size too big"); + if (cap_ - size_ < count) + { + reallocate(count); + } + char_traits::fill(buffer_ + size_, ch, count); + size_ += count; + return *this; +} + +// 在末尾添加 [str[pos] str[pos+count]) 一段 +template +basic_string& +basic_string:: +append(const basic_string& str, size_type pos, size_type count) +{ + THROW_LENGTH_ERROR_IF(size_ > max_size() - count, + "basic_string's size too big"); + if (count == 0) + return *this; + if (cap_ - size_ < count) + { + reallocate(count); + } + char_traits::copy(buffer_ + size_, str.buffer_ + pos, count); + size_ += count; + return *this; +} + +// 在末尾添加 [s, s+count) 一段 +template +basic_string& +basic_string:: +append(const_pointer s, size_type count) +{ + THROW_LENGTH_ERROR_IF(size_ > max_size() - count, + "basic_string's size too big"); + if (cap_ - size_ < count) + { + reallocate(count); + } + char_traits::copy(buffer_ + size_, s, count); + size_ += count; + return *this; +} + +// 删除 pos 处的元素 +template +typename basic_string::iterator +basic_string:: +erase(const_iterator pos) +{ + MYSTL_DEBUG(pos != end()); + iterator r = const_cast(pos); + char_traits::move(r, pos + 1, end() - pos - 1); + --size_; + return r; +} + +// 删除 [first, last) 的元素 +template +typename basic_string::iterator +basic_string:: +erase(const_iterator first, const_iterator last) +{ + if (first == begin() && last == end()) + { + clear(); + return end(); + } + const size_type n = end() - last; + iterator r = const_cast(first); + char_traits::move(r, last, n); + size_ -= (last - first); + return r; +} + +// 重置容器大小 +template +void basic_string:: +resize(size_type count, value_type ch) +{ + if (count < size_) + { + erase(buffer_ + count, buffer_ + size_); + } + else + { + append(count - size_, ch); + } +} + +// 比较两个 basic_string,小于返回 -1,大于返回 1,等于返回 0 +template +int basic_string:: +compare(const basic_string& other) const +{ + return compare_cstr(buffer_, size_, other.buffer_, other.size_); +} + +// 从 pos1 下标开始的 count1 个字符跟另一个 basic_string 比较 +template +int basic_string:: +compare(size_type pos1, size_type count1, const basic_string& other) const +{ + auto n1 = mystl::min(count1, size_ - pos1); + return compare_cstr(buffer_ + pos1, n1, other.buffer_, other.size_); +} + +// 从 pos1 下标开始的 count1 个字符跟另一个 basic_string 下标 pos2 开始的 count2 个字符比较 +template +int basic_string:: +compare(size_type pos1, size_type count1, const basic_string& other, + size_type pos2, size_type count2) const +{ + auto n1 = mystl::min(count1, size_ - pos1); + auto n2 = mystl::min(count2, other.size_ - pos2); + return compare_cstr(buffer_, n1, other.buffer_, n2); +} + +// 跟一个字符串比较 +template +int basic_string:: +compare(const_pointer s) const +{ + auto n2 = char_traits::length(s); + return compare_cstr(buffer_, size_, s, n2); +} + +// 从下标 pos1 开始的 count1 个字符跟另一个字符串比较 +template +int basic_string:: +compare(size_type pos1, size_type count1, const_pointer s) const +{ + auto n1 = mystl::min(count1, size_ - pos1); + auto n2 = char_traits::length(s); + return compare_cstr(buffer_, n1, s, n2); +} + +// 从下标 pos1 开始的 count1 个字符跟另一个字符串的前 count2 个字符比较 +template +int basic_string:: +compare(size_type pos1, size_type count1, const_pointer s, size_type count2) const +{ + auto n1 = mystl::min(count1, size_ - pos1); + return compare_cstr(buffer_, n1, s, count2); +} + +// 反转 basic_string +template +void basic_string:: +reverse() noexcept +{ + for (auto i = begin(), j = end(); i < j;) + { + mystl::iter_swap(i++, --j); + } +} + +// 交换两个 basic_string +template +void basic_string:: +swap(basic_string& rhs) noexcept +{ + if (this != &rhs) + { + mystl::swap(buffer_, rhs.buffer_); + mystl::swap(size_, rhs.size_); + mystl::swap(cap_, rhs.cap_); + } +} + +// 从下标 pos 开始查找字符为 ch 的元素,若找到返回其下标,否则返回 npos +template +typename basic_string::size_type +basic_string:: +find(value_type ch, size_type pos) const noexcept +{ + for (auto i = pos; i < size_; ++i) + { + if (*(buffer_ + i) == ch) + return i; + } + return npos; +} + +// 从下标 pos 开始查找字符串 str,若找到返回起始位置的下标,否则返回 npos +template +typename basic_string::size_type +basic_string:: +find(const_pointer str, size_type pos) const noexcept +{ + const auto len = char_traits::length(str); + if (len == 0) + return pos; + if (size_ - pos < len) + return npos; + const auto left = size_ - len; + for (auto i = pos; i <= left; ++i) + { + if (*(buffer_ + i) == *str) + { + size_type j = 1; + for (; j < len; ++j) + { + if (*(buffer_ + i + j) != *(str + j)) + break; + } + if (j == len) + return i; + } + } + return npos; +} + +// 从下标 pos 开始查找字符串 str 的前 count 个字符,若找到返回起始位置的下标,否则返回 npos +template +typename basic_string::size_type +basic_string:: +find(const_pointer str, size_type pos, size_type count) const noexcept +{ + if (count == 0) + return pos; + if (size_ - pos < count) + return npos; + const auto left = size_ - count; + for (auto i = pos; i <= left; ++i) + { + if (*(buffer_ + i) == *str) + { + size_type j = 1; + for (; j < count; ++j) + { + if (*(buffer_ + i + j) != *(str + j)) + break; + } + if (j == count) + return i; + } + } + return npos; +} + +// 从下标 pos 开始查找字符串 str,若找到返回起始位置的下标,否则返回 npos +template +typename basic_string::size_type +basic_string:: +find(const basic_string& str, size_type pos) const noexcept +{ + const size_type count = str.size_; + if (count == 0) + return pos; + if (size_ - pos < count) + return npos; + const auto left = size_ - count; + for (auto i = pos; i <= left; ++i) + { + if (*(buffer_ + i) == str.front()) + { + size_type j = 1; + for (; j < count; ++j) + { + if (*(buffer_ + i + j) != str[j]) + break; + } + if (j == count) + return i; + } + } + return npos; +} + +// 从下标 pos 开始反向查找值为 ch 的元素,与 find 类似 +template +typename basic_string::size_type +basic_string:: +rfind(value_type ch, size_type pos) const noexcept +{ + if (pos >= size_) + pos = size_ - 1; + for (auto i = pos; i != 0; --i) + { + if (*(buffer_ + i) == ch) + return i; + } + return front() == ch ? 0 : npos; +} + +// 从下标 pos 开始反向查找字符串 str,与 find 类似 +template +typename basic_string::size_type +basic_string:: +rfind(const_pointer str, size_type pos) const noexcept +{ + if (pos >= size_) + pos = size_ - 1; + const size_type len = char_traits::length(str); + switch (len) + { + case 0: + return pos; + case 1: + { + for (auto i = pos; i != 0; --i) + { + if (*(buffer_ + i) == *str) + return i; + } + return front() == *str ? 0 : npos; + } + default: + { // len >= 2 + for (auto i = pos; i >= len - 1; --i) + { + if (*(buffer_ + i) == *(str + len - 1)) + { + size_type j = 1; + for (; j < len; ++j) + { + if (*(buffer_ + i - j) != *(str + len - j - 1)) + break; + } + if (j == len) + return i - len + 1; + } + } + break; + } + } + return npos; +} + +// 从下标 pos 开始反向查找字符串 str 前 count 个字符,与 find 类似 +template +typename basic_string::size_type +basic_string:: +rfind(const_pointer str, size_type pos, size_type count) const noexcept +{ + if (count == 0) + return pos; + if (pos >= size_) + pos = size_ - 1; + if (pos < count - 1) + return npos; + for (auto i = pos; i >= count - 1; --i) + { + if (*(buffer_ + i) == *(str + count - 1)) + { + size_type j = 1; + for (; j < count; ++j) + { + if (*(buffer_ + i - j) != *(str + count - j - 1)) + break; + } + if (j == count) + return i - count + 1; + } + } + return npos; +} + +// 从下标 pos 开始反向查找字符串 str,与 find 类似 +template +typename basic_string::size_type +basic_string:: +rfind(const basic_string& str, size_type pos) const noexcept +{ + const size_type count = str.size_; + if (pos >= size_) + pos = size_ - 1; + if (count == 0) + return pos; + if (pos < count - 1) + return npos; + for (auto i = pos; i >= count - 1; --i) + { + if (*(buffer_ + i) == str[count - 1]) + { + size_type j = 1; + for (; j < count; ++j) + { + if (*(buffer_ + i - j) != str[count - j - 1]) + break; + } + if (j == count) + return i - count + 1; + } + } + return npos; +} + +// 从下标 pos 开始查找 ch 出现的第一个位置 +template +typename basic_string::size_type +basic_string:: +find_first_of(value_type ch, size_type pos) const noexcept +{ + for (auto i = pos; i < size_; ++i) + { + if (*(buffer_ + i) == ch) + return i; + } + return npos; +} + +// 从下标 pos 开始查找字符串 s 其中的一个字符出现的第一个位置 +template +typename basic_string::size_type +basic_string:: +find_first_of(const_pointer s, size_type pos) const noexcept +{ + const size_type len = char_traits::length(s); + for (auto i = pos; i < size_; ++i) + { + value_type ch = *(buffer_ + i); + for (size_type j = 0; j < len; ++j) + { + if (ch == *(s + j)) + return i; + } + } + return npos; +} + +// 从下标 pos 开始查找字符串 s +template +typename basic_string::size_type +basic_string:: +find_first_of(const_pointer s, size_type pos, size_type count) const noexcept +{ + for (auto i = pos; i < size_; ++i) + { + value_type ch = *(buffer_ + i); + for (size_type j = 0; j < count; ++j) + { + if (ch == *(s + j)) + return i; + } + } + return npos; +} + +// 从下标 pos 开始查找字符串 str 其中一个字符出现的第一个位置 +template +typename basic_string::size_type +basic_string:: +find_first_of(const basic_string& str, size_type pos) const noexcept +{ + for (auto i = pos; i < size_; ++i) + { + value_type ch = *(buffer_ + i); + for (size_type j = 0; j < str.size_; ++j) + { + if (ch == str[j]) + return i; + } + } + return npos; +} + +// 从下标 pos 开始查找与 ch 不相等的第一个位置 +template +typename basic_string::size_type +basic_string:: +find_first_not_of(value_type ch, size_type pos) const noexcept +{ + for (auto i = pos; i < size_; ++i) + { + if (*(buffer_ + i) != ch) + return i; + } + return npos; +} + +// 从下标 pos 开始查找与字符串 s 其中一个字符不相等的第一个位置 +template +typename basic_string::size_type +basic_string:: +find_first_not_of(const_pointer s, size_type pos) const noexcept +{ + const size_type len = char_traits::length(s); + for (auto i = pos; i < size_; ++i) + { + value_type ch = *(buffer_ + i); + for (size_type j = 0; j < len; ++j) + { + if (ch != *(s + j)) + return i; + } + } + return npos; +} + +// 从下标 pos 开始查找与字符串 s 前 count 个字符中不相等的第一个位置 +template +typename basic_string::size_type +basic_string:: +find_first_not_of(const_pointer s, size_type pos, size_type count) const noexcept +{ + for (auto i = pos; i < size_; ++i) + { + value_type ch = *(buffer_ + i); + for (size_type j = 0; j < count; ++j) + { + if (ch != *(s + j)) + return i; + } + } + return npos; +} + +// 从下标 pos 开始查找与字符串 str 的字符中不相等的第一个位置 +template +typename basic_string::size_type +basic_string:: +find_first_not_of(const basic_string& str, size_type pos) const noexcept +{ + for (auto i = pos; i < size_; ++i) + { + value_type ch = *(buffer_ + i); + for (size_type j = 0; j < str.size_; ++j) + { + if (ch != str[j]) + return i; + } + } + return npos; +} + +// 从下标 pos 开始查找与 ch 相等的最后一个位置 +template +typename basic_string::size_type +basic_string:: +find_last_of(value_type ch, size_type pos) const noexcept +{ + for (auto i = size_ - 1; i >= pos; --i) + { + if (*(buffer_ + i) == ch) + return i; + } + return npos; +} + +// 从下标 pos 开始查找与字符串 s 其中一个字符相等的最后一个位置 +template +typename basic_string::size_type +basic_string:: +find_last_of(const_pointer s, size_type pos) const noexcept +{ + const size_type len = char_traits::length(s); + for (auto i = size_ - 1; i >= pos; --i) + { + value_type ch = *(buffer_ + i); + for (size_type j = 0; j < len; ++j) + { + if (ch == *(s + j)) + return i; + } + } + return npos; +} + +// 从下标 pos 开始查找与字符串 s 前 count 个字符中相等的最后一个位置 +template +typename basic_string::size_type +basic_string:: +find_last_of(const_pointer s, size_type pos, size_type count) const noexcept +{ + for (auto i = size_ - 1; i >= pos; --i) + { + value_type ch = *(buffer_ + i); + for (size_type j = 0; j < count; ++j) + { + if (ch == *(s + j)) + return i; + } + } + return npos; +} + +// 从下标 pos 开始查找与字符串 str 字符中相等的最后一个位置 +template +typename basic_string::size_type +basic_string:: +find_last_of(const basic_string& str, size_type pos) const noexcept +{ + for (auto i = size_ - 1; i >= pos; --i) + { + value_type ch = *(buffer_ + i); + for (size_type j = 0; j < str.size_; ++j) + { + if (ch == str[j]) + return i; + } + } + return npos; +} + +// 从下标 pos 开始查找与 ch 字符不相等的最后一个位置 +template +typename basic_string::size_type +basic_string:: +find_last_not_of(value_type ch, size_type pos) const noexcept +{ + for (auto i = size_ - 1; i >= pos; --i) + { + if (*(buffer_ + i) != ch) + return i; + } + return npos; +} + +// 从下标 pos 开始查找与字符串 s 的字符中不相等的最后一个位置 +template +typename basic_string::size_type +basic_string:: +find_last_not_of(const_pointer s, size_type pos) const noexcept +{ + const size_type len = char_traits::length(s); + for (auto i = size_ - 1; i >= pos; --i) + { + value_type ch = *(buffer_ + i); + for (size_type j = 0; j < len; ++j) + { + if (ch != *(s + j)) + return i; + } + } + return npos; +} + +// 从下标 pos 开始查找与字符串 s 前 count 个字符中不相等的最后一个位置 +template +typename basic_string::size_type +basic_string:: +find_last_not_of(const_pointer s, size_type pos, size_type count) const noexcept +{ + for (auto i = size_ - 1; i >= pos; --i) + { + value_type ch = *(buffer_ + i); + for (size_type j = 0; j < count; ++j) + { + if (ch != *(s + j)) + return i; + } + } + return npos; +} + +// 从下标 pos 开始查找与字符串 str 字符中不相等的最后一个位置 +template +typename basic_string::size_type +basic_string:: +find_last_not_of(const basic_string& str, size_type pos) const noexcept +{ + for (auto i = size_ - 1; i >= pos; --i) + { + value_type ch = *(buffer_ + i); + for (size_type j = 0; j < str.size_; ++j) + { + if (ch != str[j]) + return i; + } + } + return npos; +} + +// 返回从下标 pos 开始字符为 ch 的元素出现的次数 +template +typename basic_string::size_type +basic_string:: +count(value_type ch, size_type pos) const noexcept +{ + size_type n = 0; + for (auto i = pos; i < size_; ++i) + { + if (*(buffer_ + i) == ch) + ++n; + } + return n; +} + +/*****************************************************************************************/ +// helper function + +// 尝试初始化一段 buffer,若分配失败则忽略,不会抛出异常 +template +void basic_string:: +try_init() noexcept +{ + try + { + buffer_ = data_allocator::allocate(static_cast(STRING_INIT_SIZE)); + size_ = 0; + cap_ = 0; + } + catch (...) + { + buffer_ = nullptr; + size_ = 0; + cap_ = 0; + // no throw + } +} + +// fill_init 函数 +template +void basic_string:: +fill_init(size_type n, value_type ch) +{ + const auto init_size = mystl::max(static_cast(STRING_INIT_SIZE), n + 1); + buffer_ = data_allocator::allocate(init_size); + char_traits::fill(buffer_, ch, n); + size_ = n; + cap_ = init_size; +} + +// copy_init 函数 +template +template +void basic_string:: +copy_init(Iter first, Iter last, mystl::input_iterator_tag) +{ + size_type n = mystl::distance(first, last); + const auto init_size = mystl::max(static_cast(STRING_INIT_SIZE), n + 1); + try + { + buffer_ = data_allocator::allocate(init_size); + size_ = n; + cap_ = init_size; + } + catch (...) + { + buffer_ = nullptr; + size_ = 0; + cap_ = 0; + throw; + } + for (; n > 0; --n, ++first) + append(*first); +} + +template +template +void basic_string:: +copy_init(Iter first, Iter last, mystl::forward_iterator_tag) +{ + const size_type n = mystl::distance(first, last); + const auto init_size = mystl::max(static_cast(STRING_INIT_SIZE), n + 1); + try + { + buffer_ = data_allocator::allocate(init_size); + size_ = n; + cap_ = init_size; + mystl::uninitialized_copy(first, last, buffer_); + } + catch (...) + { + buffer_ = nullptr; + size_ = 0; + cap_ = 0; + throw; + } +} + +// init_from 函数 +template +void basic_string:: +init_from(const_pointer src, size_type pos, size_type count) +{ + const auto init_size = mystl::max(static_cast(STRING_INIT_SIZE), count + 1); + buffer_ = data_allocator::allocate(init_size); + char_traits::copy(buffer_, src + pos, count); + size_ = count; + cap_ = init_size; +} + +// destroy_buffer 函数 +template +void basic_string:: +destroy_buffer() +{ + if (buffer_ != nullptr) + { + data_allocator::deallocate(buffer_, cap_); + buffer_ = nullptr; + size_ = 0; + cap_ = 0; + } +} + +// to_raw_pointer 函数 +template +typename basic_string::const_pointer +basic_string:: +to_raw_pointer() const +{ + *(buffer_ + size_) = value_type(); + return buffer_; +} + +// reinsert 函数 +template +void basic_string:: +reinsert(size_type size) +{ + auto new_buffer = data_allocator::allocate(size); + try + { + char_traits::move(new_buffer, buffer_, size); + } + catch (...) + { + data_allocator::deallocate(new_buffer); + } + buffer_ = new_buffer; + size_ = size; + cap_ = size; +} + +// append_range,末尾追加一段 [first, last) 内的字符 +template +template +basic_string& +basic_string:: +append_range(Iter first, Iter last) +{ + const size_type n = mystl::distance(first, last); + THROW_LENGTH_ERROR_IF(size_ > max_size() - n, + "basic_string's size too big"); + if (cap_ - size_ < n) + { + reallocate(n); + } + mystl::uninitialized_copy_n(first, n, buffer_ + size_); + size_ += n; + return *this; +} + +template +int basic_string:: +compare_cstr(const_pointer s1, size_type n1, const_pointer s2, size_type n2) const +{ + auto rlen = mystl::min(n1, n2); + auto res = char_traits::compare(s1, s2, rlen); + if (res != 0) return res; + if (n1 < n2) return -1; + if (n1 > n2) return 1; + return 0; +} + +// 把 first 开始的 count1 个字符替换成 str 开始的 count2 个字符 +template +basic_string& +basic_string:: +replace_cstr(const_iterator first, size_type count1, const_pointer str, size_type count2) +{ + if (static_cast(cend() - first) < count1) + { + count1 = cend() - first; + } + if (count1 < count2) + { + const size_type add = count2 - count1; + THROW_LENGTH_ERROR_IF(size_ > max_size() - add, + "basic_string's size too big"); + if (size_ > cap_ - add) + { + reallocate(add); + } + pointer r = const_cast(first); + char_traits::move(r + count2, first + count1, end() - (first + count1)); + char_traits::copy(r, str, count2); + size_ += add; + } + else + { + pointer r = const_cast(first); + char_traits::move(r + count2, first + count1, end() - (first + count1)); + char_traits::copy(r, str, count2); + size_ -= (count1 - count2); + } + return *this; +} + +// 把 first 开始的 count1 个字符替换成 count2 个 ch 字符 +template +basic_string& +basic_string:: +replace_fill(const_iterator first, size_type count1, size_type count2, value_type ch) +{ + if (static_cast(cend() - first) < count1) + { + count1 = cend() - first; + } + if (count1 < count2) + { + const size_type add = count2 - count1; + THROW_LENGTH_ERROR_IF(size_ > max_size() - add, + "basic_string's size too big"); + if (size_ > cap_ - add) + { + reallocate(add); + } + pointer r = const_cast(first); + char_traits::move(r + count2, first + count1, end() - (first + count1)); + char_traits::fill(r, ch, count2); + size_ += add; + } + else + { + pointer r = const_cast(first); + char_traits::move(r + count2, first + count1, end() - (first + count1)); + char_traits::fill(r, ch, count2); + size_ -= (count1 - count2); + } + return *this; +} + +// 把 [first, last) 的字符替换成 [first2, last2) +template +template +basic_string& +basic_string:: +replace_copy(const_iterator first, const_iterator last, Iter first2, Iter last2) +{ + size_type len1 = last - first; + size_type len2 = last2 - first2; + if (len1 < len2) + { + const size_type add = len2 - len1; + THROW_LENGTH_ERROR_IF(size_ > max_size() - add, + "basic_string's size too big"); + if (size_ > cap_ - add) + { + reallocate(add); + } + pointer r = const_cast(first); + char_traits::move(r + len2, first + len1, end() - (first + len1)); + char_traits::copy(r, first2, len2); + size_ += add; + } + else + { + pointer r = const_cast(first); + char_traits::move(r + len2, first + len1, end() - (first + len1)); + char_traits::copy(r, first2, len2); + size_ -= (len1 - len2); + } + return *this; +} + +// reallocate 函数 +template +void basic_string:: +reallocate(size_type need) +{ + const auto new_cap = mystl::max(cap_ + need, cap_ + (cap_ >> 1)); + auto new_buffer = data_allocator::allocate(new_cap); + char_traits::move(new_buffer, buffer_, size_); + data_allocator::deallocate(buffer_); + buffer_ = new_buffer; + cap_ = new_cap; +} + +// reallocate_and_fill 函数 +template +typename basic_string::iterator +basic_string:: +reallocate_and_fill(iterator pos, size_type n, value_type ch) +{ + const auto r = pos - buffer_; + const auto old_cap = cap_; + const auto new_cap = mystl::max(old_cap + n, old_cap + (old_cap >> 1)); + auto new_buffer = data_allocator::allocate(new_cap); + auto e1 = char_traits::move(new_buffer, buffer_, r) + r; + auto e2 = char_traits::fill(e1, ch, n) + n; + char_traits::move(e2, buffer_ + r, size_ - r); + data_allocator::deallocate(buffer_, old_cap); + buffer_ = new_buffer; + size_ += n; + cap_ = new_cap; + return buffer_ + r; +} + +// reallocate_and_copy 函数 +template +typename basic_string::iterator +basic_string:: +reallocate_and_copy(iterator pos, const_iterator first, const_iterator last) +{ + const auto r = pos - buffer_; + const auto old_cap = cap_; + const size_type n = mystl::distance(first, last); + const auto new_cap = mystl::max(old_cap + n, old_cap + (old_cap >> 1)); + auto new_buffer = data_allocator::allocate(new_cap); + auto e1 = char_traits::move(new_buffer, buffer_, r) + r; + auto e2 = mystl::uninitialized_copy_n(first, n, e1) + n; + char_traits::move(e2, buffer_ + r, size_ - r); + data_allocator::deallocate(buffer_, old_cap); + buffer_ = new_buffer; + size_ += n; + cap_ = new_cap; + return buffer_ + r; +} + +/*****************************************************************************************/ +// 重载全局操作符 + +// 重载 operator+ +template +basic_string +operator+(const basic_string& lhs, + const basic_string& rhs) +{ + basic_string tmp(lhs); + tmp.append(rhs); + return tmp; +} + +template +basic_string +operator+(const CharType* lhs, const basic_string& rhs) +{ + basic_string tmp(lhs); + tmp.append(rhs); + return tmp; +} + +template +basic_string +operator+(CharType ch, const basic_string& rhs) +{ + basic_string tmp(1, ch); + tmp.append(rhs); + return tmp; +} + +template +basic_string +operator+(const basic_string& lhs, const CharType* rhs) +{ + basic_string tmp(lhs); + tmp.append(rhs); + return tmp; +} + +template +basic_string +operator+(const basic_string& lhs, CharType ch) +{ + basic_string tmp(lhs); + tmp.append(1, ch); + return tmp; +} + +template +basic_string +operator+(basic_string&& lhs, + const basic_string& rhs) +{ + basic_string tmp(mystl::move(lhs)); + tmp.append(rhs); + return tmp; +} + +template +basic_string +operator+(const basic_string& lhs, + basic_string&& rhs) +{ + basic_string tmp(mystl::move(rhs)); + tmp.insert(tmp.begin(), lhs.begin(), lhs.end()); + return tmp; +} + +template +basic_string +operator+(basic_string&& lhs, + basic_string&& rhs) +{ + basic_string tmp(mystl::move(lhs)); + tmp.append(rhs); + return tmp; +} + +template +basic_string +operator+(const CharType* lhs, basic_string&& rhs) +{ + basic_string tmp(mystl::move(rhs)); + tmp.insert(tmp.begin(), lhs, lhs + char_traits::length(lhs)); + return tmp; +} + +template +basic_string +operator+(CharType ch, basic_string&& rhs) +{ + basic_string tmp(mystl::move(rhs)); + tmp.insert(tmp.begin(), ch); + return tmp; +} + +template +basic_string +operator+(basic_string&& lhs, const CharType* rhs) +{ + basic_string tmp(mystl::move(lhs)); + tmp.append(rhs); + return tmp; +} + +template +basic_string +operator+(basic_string&& lhs, CharType ch) +{ + basic_string tmp(mystl::move(lhs)); + tmp.append(1, ch); + return tmp; +} + +// 重载比较操作符 +template +bool operator==(const basic_string& lhs, + const basic_string& rhs) +{ + return lhs.size() == rhs.size() && lhs.compare(rhs) == 0; +} + +template +bool operator!=(const basic_string& lhs, + const basic_string& rhs) +{ + return lhs.size() != rhs.size() || lhs.compare(rhs) != 0; +} + +template +bool operator<(const basic_string& lhs, + const basic_string& rhs) +{ + return lhs.compare(rhs) < 0; +} + +template +bool operator<=(const basic_string& lhs, + const basic_string& rhs) +{ + return lhs.compare(rhs) <= 0; +} + +template +bool operator>(const basic_string& lhs, + const basic_string& rhs) +{ + return lhs.compare(rhs) > 0; +} + +template +bool operator>=(const basic_string& lhs, + const basic_string& rhs) +{ + return lhs.compare(rhs) >= 0; +} + +// 重载 mystl 的 swap +template +void swap(basic_string& lhs, + basic_string& rhs) noexcept +{ + lhs.swap(rhs); +} + +// 特化 mystl::hash +template +struct hash> +{ + size_t operator()(const basic_string& str) + { + return bitwise_hash((const unsigned char*)str.c_str(), + str.size() * sizeof(CharType)); + } +}; + +} // namespace mystl +#endif // !MYTINYSTL_BASIC_STRING_H_ + diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/construct.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/construct.h new file mode 100644 index 0000000..aeda991 --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/construct.h @@ -0,0 +1,85 @@ +#ifndef MYTINYSTL_CONSTRUCT_H_ +#define MYTINYSTL_CONSTRUCT_H_ + +// 这个头文件包含两个函数 construct,destroy +// construct : 负责对象的构造 +// destroy : 负责对象的析构 + +#include + +#include "type_traits.h" +#include "iterator.h" + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4100) // unused parameter +#endif // _MSC_VER + +namespace mystl +{ + +// construct 构造对象 + +template +void construct(Ty* ptr) +{ + ::new ((void*)ptr) Ty(); +} + +template +void construct(Ty1* ptr, const Ty2& value) +{ + ::new ((void*)ptr) Ty1(value); +} + +template +void construct(Ty* ptr, Args&&... args) +{ + ::new ((void*)ptr) Ty(mystl::forward(args)...); +} + +// destroy 将对象析构 + +template +void destroy_one(Ty*, std::true_type) {} + +template +void destroy_one(Ty* pointer, std::false_type) +{ + if (pointer != nullptr) + { + pointer->~Ty(); + } +} + +template +void destroy_cat(ForwardIter , ForwardIter , std::true_type) {} + +template +void destroy_cat(ForwardIter first, ForwardIter last, std::false_type) +{ + for (; first != last; ++first) + destroy(&*first); +} + +template +void destroy(Ty* pointer) +{ + destroy_one(pointer, std::is_trivially_destructible{}); +} + +template +void destroy(ForwardIter first, ForwardIter last) +{ + destroy_cat(first, last, std::is_trivially_destructible< + typename iterator_traits::value_type>{}); +} + +} // namespace mystl + +#ifdef _MSC_VER +#pragma warning(pop) +#endif // _MSC_VER + +#endif // !MYTINYSTL_CONSTRUCT_H_ + diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/deque.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/deque.h new file mode 100644 index 0000000..7975d83 --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/deque.h @@ -0,0 +1,1426 @@ +#ifndef MYTINYSTL_DEQUE_H_ +#define MYTINYSTL_DEQUE_H_ + +// 这个头文件包含了一个模板类 deque +// deque: 双端队列 + +// notes: +// +// 异常保证: +// mystl::deque 满足基本异常保证,部分函数无异常保证,并对以下等函数做强异常安全保证: +// * emplace_front +// * emplace_back +// * emplace +// * push_front +// * push_back +// * insert + +#include + +#include "iterator.h" +#include "memory.h" +#include "util.h" +#include "exceptdef.h" + +namespace mystl +{ + +#ifdef max +#pragma message("#undefing marco max") +#undef max +#endif // max + +#ifdef min +#pragma message("#undefing marco min") +#undef min +#endif // min + +// deque map 初始化的大小 +#ifndef DEQUE_MAP_INIT_SIZE +#define DEQUE_MAP_INIT_SIZE 8 +#endif + +template +struct deque_buf_size +{ + static constexpr size_t value = sizeof(T) < 256 ? 4096 / sizeof(T) : 16; +}; + +// deque 的迭代器设计 +template +struct deque_iterator : public iterator +{ + typedef deque_iterator iterator; + typedef deque_iterator const_iterator; + typedef deque_iterator self; + + typedef T value_type; + typedef Ptr pointer; + typedef Ref reference; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef T* value_pointer; + typedef T** map_pointer; + + static const size_type buffer_size = deque_buf_size::value; + + // 迭代器所含成员数据 + value_pointer cur; // 指向所在缓冲区的当前元素 + value_pointer first; // 指向所在缓冲区的头部 + value_pointer last; // 指向所在缓冲区的尾部 + map_pointer node; // 缓冲区所在节点 + + // 构造、复制、移动函数 + deque_iterator() noexcept + :cur(nullptr), first(nullptr), last(nullptr), node(nullptr) {} + + deque_iterator(value_pointer v, map_pointer n) + :cur(v), first(*n), last(*n + buffer_size), node(n) {} + + deque_iterator(const iterator& rhs) + :cur(rhs.cur), first(rhs.first), last(rhs.last), node(rhs.node) + { + } + deque_iterator(iterator&& rhs) noexcept + :cur(rhs.cur), first(rhs.first), last(rhs.last), node(rhs.node) + { + rhs.cur = nullptr; + rhs.first = nullptr; + rhs.last = nullptr; + rhs.node = nullptr; + } + + deque_iterator(const const_iterator& rhs) + :cur(rhs.cur), first(rhs.first), last(rhs.last), node(rhs.node) + { + } + + self& operator=(const iterator& rhs) + { + if (this != &rhs) + { + cur = rhs.cur; + first = rhs.first; + last = rhs.last; + node = rhs.node; + } + return *this; + } + + // 转到另一个缓冲区 + void set_node(map_pointer new_node) + { + node = new_node; + first = *new_node; + last = first + buffer_size; + } + + // 重载运算符 + reference operator*() const { return *cur; } + pointer operator->() const { return cur; } + + difference_type operator-(const self& x) const + { + return static_cast(buffer_size) * (node - x.node) + + (cur - first) - (x.cur - x.first); + } + + self& operator++() + { + ++cur; + if (cur == last) + { // 如果到达缓冲区的尾 + set_node(node + 1); + cur = first; + } + return *this; + } + self operator++(int) + { + self tmp = *this; + ++*this; + return tmp; + } + + self& operator--() + { + if (cur == first) + { // 如果到达缓冲区的头 + set_node(node - 1); + cur = last; + } + --cur; + return *this; + } + self operator--(int) + { + self tmp = *this; + --*this; + return tmp; + } + + self& operator+=(difference_type n) + { + const auto offset = n + (cur - first); + if (offset >= 0 && offset < static_cast(buffer_size)) + { // 仍在当前缓冲区 + cur += n; + } + else + { // 要跳到其他的缓冲区 + const auto node_offset = offset > 0 + ? offset / static_cast(buffer_size) + : -static_cast((-offset - 1) / buffer_size) - 1; + set_node(node + node_offset); + cur = first + (offset - node_offset * static_cast(buffer_size)); + } + return *this; + } + self operator+(difference_type n) const + { + self tmp = *this; + return tmp += n; + } + self& operator-=(difference_type n) + { + return *this += -n; + } + self operator-(difference_type n) const + { + self tmp = *this; + return tmp -= n; + } + + reference operator[](difference_type n) const { return *(*this + n); } + + // 重载比较操作符 + bool operator==(const self& rhs) const { return cur == rhs.cur; } + bool operator< (const self& rhs) const + { return node == rhs.node ? (cur < rhs.cur) : (node < rhs.node); } + bool operator!=(const self& rhs) const { return !(*this == rhs); } + bool operator> (const self& rhs) const { return rhs < *this; } + bool operator<=(const self& rhs) const { return !(rhs < *this); } + bool operator>=(const self& rhs) const { return !(*this < rhs); } +}; + +// 模板类 deque +// 模板参数代表数据类型 +template +class deque +{ +public: + // deque 的型别定义 + typedef mystl::allocator allocator_type; + typedef mystl::allocator data_allocator; + typedef mystl::allocator map_allocator; + + typedef typename allocator_type::value_type value_type; + typedef typename allocator_type::pointer pointer; + typedef typename allocator_type::const_pointer const_pointer; + typedef typename allocator_type::reference reference; + typedef typename allocator_type::const_reference const_reference; + typedef typename allocator_type::size_type size_type; + typedef typename allocator_type::difference_type difference_type; + typedef pointer* map_pointer; + typedef const_pointer* const_map_pointer; + + typedef deque_iterator iterator; + typedef deque_iterator const_iterator; + typedef mystl::reverse_iterator reverse_iterator; + typedef mystl::reverse_iterator const_reverse_iterator; + + allocator_type get_allocator() { return allocator_type(); } + + static const size_type buffer_size = deque_buf_size::value; + +private: + // 用以下四个数据来表现一个 deque + iterator begin_; // 指向第一个节点 + iterator end_; // 指向最后一个结点 + map_pointer map_; // 指向一块 map,map 中的每个元素都是一个指针,指向一个缓冲区 + size_type map_size_; // map 内指针的数目 + +public: + // 构造、复制、移动、析构函数 + + deque() + { fill_init(0, value_type()); } + + explicit deque(size_type n) + { fill_init(n, value_type()); } + + deque(size_type n, const value_type& value) + { fill_init(n, value); } + + template ::value, int>::type = 0> + deque(IIter first, IIter last) + { copy_init(first, last, iterator_category(first)); } + + deque(std::initializer_list ilist) + { + copy_init(ilist.begin(), ilist.end(), mystl::forward_iterator_tag()); + } + + deque(const deque& rhs) + { + copy_init(rhs.begin(), rhs.end(), mystl::forward_iterator_tag()); + } + deque(deque&& rhs) noexcept + :begin_(mystl::move(rhs.begin_)), + end_(mystl::move(rhs.end_)), + map_(rhs.map_), + map_size_(rhs.map_size_) + { + rhs.map_ = nullptr; + rhs.map_size_ = 0; + } + + deque& operator=(const deque& rhs); + deque& operator=(deque&& rhs); + + deque& operator=(std::initializer_list ilist) + { + deque tmp(ilist); + swap(tmp); + return *this; + } + + ~deque() + { + if (map_ != nullptr) + { + clear(); + data_allocator::deallocate(*begin_.node, buffer_size); + *begin_.node = nullptr; + map_allocator::deallocate(map_, map_size_); + map_ = nullptr; + } + } + +public: + // 迭代器相关操作 + + iterator begin() noexcept + { return begin_; } + const_iterator begin() const noexcept + { return begin_; } + iterator end() noexcept + { return end_; } + const_iterator end() const noexcept + { return end_; } + + reverse_iterator rbegin() noexcept + { return reverse_iterator(end()); } + const_reverse_iterator rbegin() const noexcept + { return reverse_iterator(end()); } + reverse_iterator rend() noexcept + { return reverse_iterator(begin()); } + const_reverse_iterator rend() const noexcept + { return reverse_iterator(begin()); } + + const_iterator cbegin() const noexcept + { return begin(); } + const_iterator cend() const noexcept + { return end(); } + const_reverse_iterator crbegin() const noexcept + { return rbegin(); } + const_reverse_iterator crend() const noexcept + { return rend(); } + + // 容量相关操作 + + bool empty() const noexcept { return begin() == end(); } + size_type size() const noexcept { return end_ - begin_; } + size_type max_size() const noexcept { return static_cast(-1); } + void resize(size_type new_size) { resize(new_size, value_type()); } + void resize(size_type new_size, const value_type& value); + void shrink_to_fit() noexcept; + + // 访问元素相关操作 + reference operator[](size_type n) + { + MYSTL_DEBUG(n < size()); + return begin_[n]; + } + const_reference operator[](size_type n) const + { + MYSTL_DEBUG(n < size()); + return begin_[n]; + } + + reference at(size_type n) + { + THROW_OUT_OF_RANGE_IF(!(n < size()), "deque::at() subscript out of range"); + return (*this)[n]; + } + const_reference at(size_type n) const + { + THROW_OUT_OF_RANGE_IF(!(n < size()), "deque::at() subscript out of range"); + return (*this)[n]; + } + + reference front() + { + MYSTL_DEBUG(!empty()); + return *begin(); + } + const_reference front() const + { + MYSTL_DEBUG(!empty()); + return *begin(); + } + reference back() + { + MYSTL_DEBUG(!empty()); + return *(end() - 1); + } + const_reference back() const + { + MYSTL_DEBUG(!empty()); + return *(end() - 1); + } + + // 修改容器相关操作 + + // assign + + void assign(size_type n, const value_type& value) + { fill_assign(n, value); } + + template ::value, int>::type = 0> + void assign(IIter first, IIter last) + { copy_assign(first, last, iterator_category(first)); } + + void assign(std::initializer_list ilist) + { copy_assign(ilist.begin(), ilist.end(), mystl::forward_iterator_tag{}); } + + // emplace_front / emplace_back / emplace + + template + void emplace_front(Args&& ...args); + template + void emplace_back(Args&& ...args); + template + iterator emplace(iterator pos, Args&& ...args); + + // push_front / push_back + + void push_front(const value_type& value); + void push_back(const value_type& value); + + void push_front(value_type&& value) { emplace_front(mystl::move(value)); } + void push_back(value_type&& value) { emplace_back(mystl::move(value)); } + + // pop_back / pop_front + + void pop_front(); + void pop_back(); + + // insert + + iterator insert(iterator position, const value_type& value); + iterator insert(iterator position, value_type&& value); + void insert(iterator position, size_type n, const value_type& value); + template ::value, int>::type = 0> + void insert(iterator position, IIter first, IIter last) + { insert_dispatch(position, first, last, iterator_category(first)); } + + // erase /clear + + iterator erase(iterator position); + iterator erase(iterator first, iterator last); + void clear(); + + // swap + + void swap(deque& rhs) noexcept; + +private: + // helper functions + + // create node / destroy node + map_pointer create_map(size_type size); + void create_buffer(map_pointer nstart, map_pointer nfinish); + void destroy_buffer(map_pointer nstart, map_pointer nfinish); + + // initialize + void map_init(size_type nelem); + void fill_init(size_type n, const value_type& value); + template + void copy_init(IIter, IIter, input_iterator_tag); + template + void copy_init(FIter, FIter, forward_iterator_tag); + + // assign + void fill_assign(size_type n, const value_type& value); + template + void copy_assign(IIter first, IIter last, input_iterator_tag); + template + void copy_assign(FIter first, FIter last, forward_iterator_tag); + + // insert + template + iterator insert_aux(iterator position, Args&& ...args); + void fill_insert(iterator position, size_type n, const value_type& x); + template + void copy_insert(iterator, FIter, FIter, size_type); + template + void insert_dispatch(iterator, IIter, IIter, input_iterator_tag); + template + void insert_dispatch(iterator, FIter, FIter, forward_iterator_tag); + + // reallocate + void require_capacity(size_type n, bool front); + void reallocate_map_at_front(size_type need); + void reallocate_map_at_back(size_type need); + +}; + +/*****************************************************************************************/ + +// 复制赋值运算符 +template +deque& deque::operator=(const deque& rhs) +{ + if (this != &rhs) + { + const auto len = size(); + if (len >= rhs.size()) + { + erase(mystl::copy(rhs.begin_, rhs.end_, begin_), end_); + } + else + { + iterator mid = rhs.begin() + static_cast(len); + mystl::copy(rhs.begin_, mid, begin_); + insert(end_, mid, rhs.end_); + } + } + return *this; +} + +// 移动赋值运算符 +template +deque& deque::operator=(deque&& rhs) +{ + clear(); + begin_ = mystl::move(rhs.begin_); + end_ = mystl::move(rhs.end_); + map_ = rhs.map_; + map_size_ = rhs.map_size_; + rhs.map_ = nullptr; + rhs.map_size_ = 0; + return *this; +} + +// 重置容器大小 +template +void deque::resize(size_type new_size, const value_type& value) +{ + const auto len = size(); + if (new_size < len) + { + erase(begin_ + new_size, end_); + } + else + { + insert(end_, new_size - len, value); + } +} + +// 减小容器容量 +template +void deque::shrink_to_fit() noexcept +{ + // 至少会留下头部缓冲区 + for (auto cur = map_; cur < begin_.node; ++cur) + { + data_allocator::deallocate(*cur, buffer_size); + *cur = nullptr; + } + for (auto cur = end_.node + 1; cur < map_ + map_size_; ++cur) + { + data_allocator::deallocate(*cur, buffer_size); + *cur = nullptr; + } +} + +// 在头部就地构建元素 +template +template +void deque::emplace_front(Args&& ...args) +{ + if (begin_.cur != begin_.first) + { + data_allocator::construct(begin_.cur - 1, mystl::forward(args)...); + --begin_.cur; + } + else + { + require_capacity(1, true); + try + { + --begin_; + data_allocator::construct(begin_.cur, mystl::forward(args)...); + } + catch (...) + { + ++begin_; + throw; + } + } +} + +// 在尾部就地构建元素 +template +template +void deque::emplace_back(Args&& ...args) +{ + if (end_.cur != end_.last - 1) + { + data_allocator::construct(end_.cur, mystl::forward(args)...); + ++end_.cur; + } + else + { + require_capacity(1, false); + data_allocator::construct(end_.cur, mystl::forward(args)...); + ++end_; + } +} + +// 在 pos 位置就地构建元素 +template +template +typename deque::iterator deque::emplace(iterator pos, Args&& ...args) +{ + if (pos.cur == begin_.cur) + { + emplace_front(mystl::forward(args)...); + return begin_; + } + else if (pos.cur == end_.cur) + { + emplace_back(mystl::forward(args)...); + return end_ - 1; + } + return insert_aux(pos, mystl::forward(args)...); +} + +// 在头部插入元素 +template +void deque::push_front(const value_type& value) +{ + if (begin_.cur != begin_.first) + { + data_allocator::construct(begin_.cur - 1, value); + --begin_.cur; + } + else + { + require_capacity(1, true); + try + { + --begin_; + data_allocator::construct(begin_.cur, value); + } + catch (...) + { + ++begin_; + throw; + } + } +} + +// 在尾部插入元素 +template +void deque::push_back(const value_type& value) +{ + if (end_.cur != end_.last - 1) + { + data_allocator::construct(end_.cur, value); + ++end_.cur; + } + else + { + require_capacity(1, false); + data_allocator::construct(end_.cur, value); + ++end_; + } +} + +// 弹出头部元素 +template +void deque::pop_front() +{ + MYSTL_DEBUG(!empty()); + if (begin_.cur != begin_.last - 1) + { + data_allocator::destroy(begin_.cur); + ++begin_.cur; + } + else + { + data_allocator::destroy(begin_.cur); + ++begin_; + destroy_buffer(begin_.node - 1, begin_.node - 1); + } +} + +// 弹出尾部元素 +template +void deque::pop_back() +{ + MYSTL_DEBUG(!empty()); + if (end_.cur != end_.first) + { + --end_.cur; + data_allocator::destroy(end_.cur); + } + else + { + --end_; + data_allocator::destroy(end_.cur); + destroy_buffer(end_.node + 1, end_.node + 1); + } +} + +// 在 position 处插入元素 +template +typename deque::iterator +deque::insert(iterator position, const value_type& value) +{ + if (position.cur == begin_.cur) + { + push_front(value); + return begin_; + } + else if (position.cur == end_.cur) + { + push_back(value); + auto tmp = end_; + --tmp; + return tmp; + } + else + { + return insert_aux(position, value); + } +} + +template +typename deque::iterator +deque::insert(iterator position, value_type&& value) +{ + if (position.cur == begin_.cur) + { + emplace_front(mystl::move(value)); + return begin_; + } + else if (position.cur == end_.cur) + { + emplace_back(mystl::move(value)); + auto tmp = end_; + --tmp; + return tmp; + } + else + { + return insert_aux(position, mystl::move(value)); + } +} + +// 在 position 位置插入 n 个元素 +template +void deque::insert(iterator position, size_type n, const value_type& value) +{ + if (position.cur == begin_.cur) + { + require_capacity(n, true); + auto new_begin = begin_ - n; + mystl::uninitialized_fill_n(new_begin, n, value); + begin_ = new_begin; + } + else if (position.cur == end_.cur) + { + require_capacity(n, false); + auto new_end = end_ + n; + mystl::uninitialized_fill_n(end_, n, value); + end_ = new_end; + } + else + { + fill_insert(position, n, value); + } +} + +// 删除 position 处的元素 +template +typename deque::iterator +deque::erase(iterator position) +{ + auto next = position; + ++next; + const size_type elems_before = position - begin_; + if (elems_before < (size() / 2)) + { + mystl::copy_backward(begin_, position, next); + pop_front(); + } + else + { + mystl::copy(next, end_, position); + pop_back(); + } + return begin_ + elems_before; +} + +// 删除[first, last)上的元素 +template +typename deque::iterator +deque::erase(iterator first, iterator last) +{ + if (first == begin_ && last == end_) + { + clear(); + return end_; + } + else + { + const size_type len = last - first; + const size_type elems_before = first - begin_; + if (elems_before < ((size() - len) / 2)) + { + mystl::copy_backward(begin_, first, last); + auto new_begin = begin_ + len; + data_allocator::destroy(begin_.cur, new_begin.cur); + begin_ = new_begin; + } + else + { + mystl::copy(last, end_, first); + auto new_end = end_ - len; + data_allocator::destroy(new_end.cur, end_.cur); + end_ = new_end; + } + return begin_ + elems_before; + } +} + +// 清空 deque +template +void deque::clear() +{ + // clear 会保留头部的缓冲区 + for (map_pointer cur = begin_.node + 1; cur < end_.node; ++cur) + { + data_allocator::destroy(*cur, *cur + buffer_size); + } + if (begin_.node != end_.node) + { // 有两个以上的缓冲区 + mystl::destroy(begin_.cur, begin_.last); + mystl::destroy(end_.first, end_.cur); + } + else + { + mystl::destroy(begin_.cur, end_.cur); + } + shrink_to_fit(); + end_ = begin_; +} + +// 交换两个 deque +template +void deque::swap(deque& rhs) noexcept +{ + if (this != &rhs) + { + mystl::swap(begin_, rhs.begin_); + mystl::swap(end_, rhs.end_); + mystl::swap(map_, rhs.map_); + mystl::swap(map_size_, rhs.map_size_); + } +} + +/*****************************************************************************************/ +// helper function + +template +typename deque::map_pointer +deque::create_map(size_type size) +{ + map_pointer mp = nullptr; + mp = map_allocator::allocate(size); + for (size_type i = 0; i < size; ++i) + *(mp + i) = nullptr; + return mp; +} + +// create_buffer 函数 +template +void deque:: +create_buffer(map_pointer nstart, map_pointer nfinish) +{ + map_pointer cur; + try + { + for (cur = nstart; cur <= nfinish; ++cur) + { + *cur = data_allocator::allocate(buffer_size); + } + } + catch (...) + { + while (cur != nstart) + { + --cur; + data_allocator::deallocate(*cur, buffer_size); + *cur = nullptr; + } + throw; + } +} + +// destroy_buffer 函数 +template +void deque:: +destroy_buffer(map_pointer nstart, map_pointer nfinish) +{ + for (map_pointer n = nstart; n <= nfinish; ++n) + { + data_allocator::deallocate(*n, buffer_size); + *n = nullptr; + } +} + +// map_init 函数 +template +void deque:: +map_init(size_type nElem) +{ + const size_type nNode = nElem / buffer_size + 1; // 需要分配的缓冲区个数 + map_size_ = mystl::max(static_cast(DEQUE_MAP_INIT_SIZE), nNode + 2); + try + { + map_ = create_map(map_size_); + } + catch (...) + { + map_ = nullptr; + map_size_ = 0; + throw; + } + + // 让 nstart 和 nfinish 都指向 map_ 最中央的区域,方便向头尾扩充 + map_pointer nstart = map_ + (map_size_ - nNode) / 2; + map_pointer nfinish = nstart + nNode - 1; + try + { + create_buffer(nstart, nfinish); + } + catch (...) + { + map_allocator::deallocate(map_, map_size_); + map_ = nullptr; + map_size_ = 0; + throw; + } + begin_.set_node(nstart); + end_.set_node(nfinish); + begin_.cur = begin_.first; + end_.cur = end_.first + (nElem % buffer_size); +} + +// fill_init 函数 +template +void deque:: +fill_init(size_type n, const value_type& value) +{ + map_init(n); + if (n != 0) + { + for (auto cur = begin_.node; cur < end_.node; ++cur) + { + mystl::uninitialized_fill(*cur, *cur + buffer_size, value); + } + mystl::uninitialized_fill(end_.first, end_.cur, value); + } +} + +// copy_init 函数 +template +template +void deque:: +copy_init(IIter first, IIter last, input_iterator_tag) +{ + const size_type n = mystl::distance(first, last); + map_init(n); + for (; first != last; ++first) + emplace_back(*first); +} + +template +template +void deque:: +copy_init(FIter first, FIter last, forward_iterator_tag) +{ + const size_type n = mystl::distance(first, last); + map_init(n); + for (auto cur = begin_.node; cur < end_.node; ++cur) + { + auto next = first; + mystl::advance(next, buffer_size); + mystl::uninitialized_copy(first, next, *cur); + first = next; + } + mystl::uninitialized_copy(first, last, end_.first); +} + +// fill_assign 函数 +template +void deque:: +fill_assign(size_type n, const value_type& value) +{ + if (n > size()) + { + mystl::fill(begin(), end(), value); + insert(end(), n - size(), value); + } + else + { + erase(begin() + n, end()); + mystl::fill(begin(), end(), value); + } +} + +// copy_assign 函数 +template +template +void deque:: +copy_assign(IIter first, IIter last, input_iterator_tag) +{ + auto first1 = begin(); + auto last1 = end(); + for (; first != last && first1 != last1; ++first, ++first1) + { + *first1 = *first; + } + if (first1 != last1) + { + erase(first1, last1); + } + else + { + insert_dispatch(end_, first, last, input_iterator_tag{}); + } +} + +template +template +void deque:: +copy_assign(FIter first, FIter last, forward_iterator_tag) +{ + const size_type len1 = size(); + const size_type len2 = mystl::distance(first, last); + if (len1 < len2) + { + auto next = first; + mystl::advance(next, len1); + mystl::copy(first, next, begin_); + insert_dispatch(end_, next, last, forward_iterator_tag{}); + } + else + { + erase(mystl::copy(first, last, begin_), end_); + } +} + +// insert_aux 函数 +template +template +typename deque::iterator +deque:: +insert_aux(iterator position, Args&& ...args) +{ + const size_type elems_before = position - begin_; + value_type value_copy = value_type(mystl::forward(args)...); + if (elems_before < (size() / 2)) + { // 在前半段插入 + emplace_front(front()); + auto front1 = begin_; + ++front1; + auto front2 = front1; + ++front2; + position = begin_ + elems_before; + auto pos = position; + ++pos; + mystl::copy(front2, pos, front1); + } + else + { // 在后半段插入 + emplace_back(back()); + auto back1 = end_; + --back1; + auto back2 = back1; + --back2; + position = begin_ + elems_before; + mystl::copy_backward(position, back2, back1); + } + *position = mystl::move(value_copy); + return position; +} + +// fill_insert 函数 +template +void deque:: +fill_insert(iterator position, size_type n, const value_type& value) +{ + const size_type elems_before = position - begin_; + const size_type len = size(); + auto value_copy = value; + if (elems_before < (len / 2)) + { + require_capacity(n, true); + // 原来的迭代器可能会失效 + auto old_begin = begin_; + auto new_begin = begin_ - n; + position = begin_ + elems_before; + try + { + if (elems_before >= n) + { + auto begin_n = begin_ + n; + mystl::uninitialized_copy(begin_, begin_n, new_begin); + begin_ = new_begin; + mystl::copy(begin_n, position, old_begin); + mystl::fill(position - n, position, value_copy); + } + else + { + mystl::uninitialized_fill( + mystl::uninitialized_copy(begin_, position, new_begin), begin_, value_copy); + begin_ = new_begin; + mystl::fill(old_begin, position, value_copy); + } + } + catch (...) + { + if (new_begin.node != begin_.node) + destroy_buffer(new_begin.node, begin_.node - 1); + throw; + } + } + else + { + require_capacity(n, false); + // 原来的迭代器可能会失效 + auto old_end = end_; + auto new_end = end_ + n; + const size_type elems_after = len - elems_before; + position = end_ - elems_after; + try + { + if (elems_after > n) + { + auto end_n = end_ - n; + mystl::uninitialized_copy(end_n, end_, end_); + end_ = new_end; + mystl::copy_backward(position, end_n, old_end); + mystl::fill(position, position + n, value_copy); + } + else + { + mystl::uninitialized_fill(end_, position + n, value_copy); + mystl::uninitialized_copy(position, end_, position + n); + end_ = new_end; + mystl::fill(position, old_end, value_copy); + } + } + catch (...) + { + if(new_end.node != end_.node) + destroy_buffer(end_.node + 1, new_end.node); + throw; + } + } +} + +// copy_insert +template +template +void deque:: +copy_insert(iterator position, FIter first, FIter last, size_type n) +{ + const size_type elems_before = position - begin_; + auto len = size(); + if (elems_before < (len / 2)) + { + require_capacity(n, true); + // 原来的迭代器可能会失效 + auto old_begin = begin_; + auto new_begin = begin_ - n; + position = begin_ + elems_before; + try + { + if (elems_before >= n) + { + auto begin_n = begin_ + n; + mystl::uninitialized_copy(begin_, begin_n, new_begin); + begin_ = new_begin; + mystl::copy(begin_n, position, old_begin); + mystl::copy(first, last, position - n); + } + else + { + auto mid = first; + mystl::advance(mid, n - elems_before); + mystl::uninitialized_copy(first, mid, + mystl::uninitialized_copy(begin_, position, new_begin)); + begin_ = new_begin; + mystl::copy(mid, last, old_begin); + } + } + catch (...) + { + if(new_begin.node != begin_.node) + destroy_buffer(new_begin.node, begin_.node - 1); + throw; + } + } + else + { + require_capacity(n, false); + // 原来的迭代器可能会失效 + auto old_end = end_; + auto new_end = end_ + n; + const auto elems_after = len - elems_before; + position = end_ - elems_after; + try + { + if (elems_after > n) + { + auto end_n = end_ - n; + mystl::uninitialized_copy(end_n, end_, end_); + end_ = new_end; + mystl::copy_backward(position, end_n, old_end); + mystl::copy(first, last, position); + } + else + { + auto mid = first; + mystl::advance(mid, elems_after); + mystl::uninitialized_copy(position, end_, + mystl::uninitialized_copy(mid, last, end_)); + end_ = new_end; + mystl::copy(first, mid, position); + } + } + catch (...) + { + if(new_end.node != end_.node) + destroy_buffer(end_.node + 1, new_end.node); + throw; + } + } +} + +// insert_dispatch 函数 +template +template +void deque:: +insert_dispatch(iterator position, IIter first, IIter last, input_iterator_tag) +{ + if (last <= first) return; + const size_type n = mystl::distance(first, last); + const size_type elems_before = position - begin_; + if (elems_before < (size() / 2)) + { + require_capacity(n, true); + } + else + { + require_capacity(n, false); + } + position = begin_ + elems_before; + auto cur = --last; + for (size_type i = 0; i < n; ++i, --cur) + { + insert(position, *cur); + } +} + +template +template +void deque:: +insert_dispatch(iterator position, FIter first, FIter last, forward_iterator_tag) +{ + if (last <= first) return; + const size_type n = mystl::distance(first, last); + if (position.cur == begin_.cur) + { + require_capacity(n, true); + auto new_begin = begin_ - n; + try + { + mystl::uninitialized_copy(first, last, new_begin); + begin_ = new_begin; + } + catch (...) + { + if(new_begin.node != begin_.node) + destroy_buffer(new_begin.node, begin_.node - 1); + throw; + } + } + else if (position.cur == end_.cur) + { + require_capacity(n, false); + auto new_end = end_ + n; + try + { + mystl::uninitialized_copy(first, last, end_); + end_ = new_end; + } + catch (...) + { + if(new_end.node != end_.node) + destroy_buffer(end_.node + 1, new_end.node); + throw; + } + } + else + { + copy_insert(position, first, last, n); + } +} + +// require_capacity 函数 +template +void deque::require_capacity(size_type n, bool front) +{ + if (front && (static_cast(begin_.cur - begin_.first) < n)) + { + const size_type need_buffer = (n - (begin_.cur - begin_.first)) / buffer_size + 1; + if (need_buffer > static_cast(begin_.node - map_)) + { + reallocate_map_at_front(need_buffer); + return; + } + create_buffer(begin_.node - need_buffer, begin_.node - 1); + } + else if (!front && (static_cast(end_.last - end_.cur - 1) < n)) + { + const size_type need_buffer = (n - (end_.last - end_.cur - 1)) / buffer_size + 1; + if (need_buffer > static_cast((map_ + map_size_) - end_.node - 1)) + { + reallocate_map_at_back(need_buffer); + return; + } + create_buffer(end_.node + 1, end_.node + need_buffer); + } +} + +// reallocate_map_at_front 函数 +template +void deque::reallocate_map_at_front(size_type need_buffer) +{ + const size_type new_map_size = mystl::max(map_size_ << 1, + map_size_ + need_buffer + DEQUE_MAP_INIT_SIZE); + map_pointer new_map = create_map(new_map_size); + const size_type old_buffer = end_.node - begin_.node + 1; + const size_type new_buffer = old_buffer + need_buffer; + + // 另新的 map 中的指针指向原来的 buffer,并开辟新的 buffer + auto begin = new_map + (new_map_size - new_buffer) / 2; + auto mid = begin + need_buffer; + auto end = mid + old_buffer; + create_buffer(begin, mid - 1); + for (auto begin1 = mid, begin2 = begin_.node; begin1 != end; ++begin1, ++begin2) + *begin1 = *begin2; + + // 更新数据 + map_allocator::deallocate(map_, map_size_); + map_ = new_map; + map_size_ = new_map_size; + begin_ = iterator(*mid + (begin_.cur - begin_.first), mid); + end_ = iterator(*(end - 1) + (end_.cur - end_.first), end - 1); +} + +// reallocate_map_at_back 函数 +template +void deque::reallocate_map_at_back(size_type need_buffer) +{ + const size_type new_map_size = mystl::max(map_size_ << 1, + map_size_ + need_buffer + DEQUE_MAP_INIT_SIZE); + map_pointer new_map = create_map(new_map_size); + const size_type old_buffer = end_.node - begin_.node + 1; + const size_type new_buffer = old_buffer + need_buffer; + + // 另新的 map 中的指针指向原来的 buffer,并开辟新的 buffer + auto begin = new_map + ((new_map_size - new_buffer) / 2); + auto mid = begin + old_buffer; + auto end = mid + need_buffer; + for (auto begin1 = begin, begin2 = begin_.node; begin1 != mid; ++begin1, ++begin2) + *begin1 = *begin2; + create_buffer(mid, end - 1); + + // 更新数据 + map_allocator::deallocate(map_, map_size_); + map_ = new_map; + map_size_ = new_map_size; + begin_ = iterator(*begin + (begin_.cur - begin_.first), begin); + end_ = iterator(*(mid - 1) + (end_.cur - end_.first), mid - 1); +} + +// 重载比较操作符 +template +bool operator==(const deque& lhs, const deque& rhs) +{ + return lhs.size() == rhs.size() && + mystl::equal(lhs.begin(), lhs.end(), rhs.begin()); +} + +template +bool operator<(const deque& lhs, const deque& rhs) +{ + return mystl::lexicographical_compare( + lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); +} + +template +bool operator!=(const deque& lhs, const deque& rhs) +{ + return !(lhs == rhs); +} + +template +bool operator>(const deque& lhs, const deque& rhs) +{ + return rhs < lhs; +} + +template +bool operator<=(const deque& lhs, const deque& rhs) +{ + return !(rhs < lhs); +} + +template +bool operator>=(const deque& lhs, const deque& rhs) +{ + return !(lhs < rhs); +} + +// 重载 mystl 的 swap +template +void swap(deque& lhs, deque& rhs) +{ + lhs.swap(rhs); +} + +} // namespace mystl +#endif // !MYTINYSTL_DEQUE_H_ + diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/exceptdef.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/exceptdef.h new file mode 100644 index 0000000..ef8b983 --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/exceptdef.h @@ -0,0 +1,26 @@ +#ifndef MYTINYSTL_EXCEPTDEF_H_ +#define MYTINYSTL_EXCEPTDEF_H_ + +#include + +#include + +namespace mystl +{ + +#define MYSTL_DEBUG(expr) \ + assert(expr) + +#define THROW_LENGTH_ERROR_IF(expr, what) \ + if ((expr)) throw std::length_error(what) + +#define THROW_OUT_OF_RANGE_IF(expr, what) \ + if ((expr)) throw std::out_of_range(what) + +#define THROW_RUNTIME_ERROR_IF(expr, what) \ + if ((expr)) throw std::runtime_error(what) + +} // namepsace mystl + +#endif // !MYTINYSTL_EXCEPTDEF_H_ + diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/functional.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/functional.h new file mode 100644 index 0000000..b445017 --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/functional.h @@ -0,0 +1,285 @@ +#ifndef MYTINYSTL_FUNCTIONAL_H_ +#define MYTINYSTL_FUNCTIONAL_H_ + +// 这个头文件包含了 mystl 的函数对象与哈希函数 + +#include + +namespace mystl +{ + +// 定义一元函数的参数型别和返回值型别 +template +struct unarg_function +{ + typedef Arg argument_type; + typedef Result result_type; +}; + +// 定义二元函数的参数型别的返回值型别 +template +struct binary_function +{ + typedef Arg1 first_argument_type; + typedef Arg2 second_argument_type; + typedef Result result_type; +}; + +// 函数对象:加法 +template +struct plus :public binary_function +{ + T operator()(const T& x, const T& y) const { return x + y; } +}; + +// 函数对象:减法 +template +struct minus :public binary_function +{ + T operator()(const T& x, const T& y) const { return x - y; } +}; + +// 函数对象:乘法 +template +struct multiplies :public binary_function +{ + T operator()(const T& x, const T& y) const { return x * y; } +}; + +// 函数对象:除法 +template +struct divides :public binary_function +{ + T operator()(const T& x, const T& y) const { return x / y; } +}; + +// 函数对象:模取 +template +struct modulus :public binary_function +{ + T operator()(const T& x, const T& y) const { return x % y; } +}; + +// 函数对象:否定 +template +struct negate :public unarg_function +{ + T operator()(const T& x) const { return -x; } +}; + +// 加法的证同元素 +template +T identity_element(plus) { return T(0); } + +// 乘法的证同元素 +template +T identity_element(multiplies) { return T(1); } + +// 函数对象:等于 +template +struct equal_to :public binary_function +{ + bool operator()(const T& x, const T& y) const { return x == y; } +}; + +// 函数对象:不等于 +template +struct not_equal_to :public binary_function +{ + bool operator()(const T& x, const T& y) const { return x != y; } +}; + +// 函数对象:大于 +template +struct greater :public binary_function +{ + bool operator()(const T& x, const T& y) const { return x > y; } +}; + +// 函数对象:小于 +template +struct less :public binary_function +{ + bool operator()(const T& x, const T& y) const { return x < y; } +}; + +// 函数对象:大于等于 +template +struct greater_equal :public binary_function +{ + bool operator()(const T& x, const T& y) const { return x >= y; } +}; + +// 函数对象:小于等于 +template +struct less_equal :public binary_function +{ + bool operator()(const T& x, const T& y) const { return x <= y; } +}; + +// 函数对象:逻辑与 +template +struct logical_and :public binary_function +{ + bool operator()(const T& x, const T& y) const { return x && y; } +}; + +// 函数对象:逻辑或 +template +struct logical_or :public binary_function +{ + bool operator()(const T& x, const T& y) const { return x || y; } +}; + +// 函数对象:逻辑非 +template +struct logical_not :public unarg_function +{ + bool operator()(const T& x) const { return !x; } +}; + +// 证同函数:不会改变元素,返回本身 +template +struct identity :public unarg_function +{ + const T& operator()(const T& x) const { return x; } +}; + +// 选择函数:接受一个 pair,返回第一个元素 +template +struct selectfirst :public unarg_function +{ + const typename Pair::first_type& operator()(const Pair& x) const + { + return x.first; + } +}; + +// 选择函数:接受一个 pair,返回第二个元素 +template +struct selectsecond :public unarg_function +{ + const typename Pair::second_type& operator()(const Pair& x) const + { + return x.second; + } +}; + +// 投射函数:返回第一参数 +template +struct projectfirst :public binary_function +{ + Arg1 operator()(const Arg1& x, const Arg2&) const { return x; } +}; + +// 投射函数:返回第二参数 +template +struct projectsecond :public binary_function +{ + Arg2 operator()(const Arg1&, const Arg2& y) const { return y; } +}; + +/*****************************************************************************************/ +// 哈希函数对象 + +// 对于大部分类型,hash function 什么都不做 +template +struct hash {}; + +// 针对指针的偏特化版本 +template +struct hash +{ + size_t operator()(T* p) const noexcept + { return reinterpret_cast(p); } +}; + +// 对于整型类型,只是返回原值 +#define MYSTL_TRIVIAL_HASH_FCN(Type) \ +template <> struct hash \ +{ \ + size_t operator()(Type val) const noexcept \ + { return static_cast(val); } \ +}; + +MYSTL_TRIVIAL_HASH_FCN(bool) + +MYSTL_TRIVIAL_HASH_FCN(char) + +MYSTL_TRIVIAL_HASH_FCN(signed char) + +MYSTL_TRIVIAL_HASH_FCN(unsigned char) + +MYSTL_TRIVIAL_HASH_FCN(wchar_t) + +MYSTL_TRIVIAL_HASH_FCN(char16_t) + +MYSTL_TRIVIAL_HASH_FCN(char32_t) + +MYSTL_TRIVIAL_HASH_FCN(short) + +MYSTL_TRIVIAL_HASH_FCN(unsigned short) + +MYSTL_TRIVIAL_HASH_FCN(int) + +MYSTL_TRIVIAL_HASH_FCN(unsigned int) + +MYSTL_TRIVIAL_HASH_FCN(long) + +MYSTL_TRIVIAL_HASH_FCN(unsigned long) + +MYSTL_TRIVIAL_HASH_FCN(long long) + +MYSTL_TRIVIAL_HASH_FCN(unsigned long long) + +#undef MYSTL_TRIVIAL_HASH_FCN + +// 对于浮点数,逐位哈希 +inline size_t bitwise_hash(const unsigned char* first, size_t count) +{ +#if (_MSC_VER && _WIN64) || ((__GNUC__ || __clang__) &&__SIZEOF_POINTER__ == 8) + const size_t fnv_offset = 14695981039346656037ull; + const size_t fnv_prime = 1099511628211ull; +#else + const size_t fnv_offset = 2166136261u; + const size_t fnv_prime = 16777619u; +#endif + size_t result = fnv_offset; + for (size_t i = 0; i < count; ++i) + { + result ^= (size_t)first[i]; + result *= fnv_prime; + } + return result; +} + +template <> +struct hash +{ + size_t operator()(const float& val) + { + return val == 0.0f ? 0 : bitwise_hash((const unsigned char*)&val, sizeof(float)); + } +}; + +template <> +struct hash +{ + size_t operator()(const double& val) + { + return val == 0.0f ? 0 : bitwise_hash((const unsigned char*)&val, sizeof(double)); + } +}; + +template <> +struct hash +{ + size_t operator()(const long double& val) + { + return val == 0.0f ? 0 : bitwise_hash((const unsigned char*)&val, sizeof(long double)); + } +}; + +} // namespace mystl +#endif // !MYTINYSTL_FUNCTIONAL_H_ + diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/hashtable.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/hashtable.h new file mode 100644 index 0000000..9296fc2 --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/hashtable.h @@ -0,0 +1,1609 @@ +#ifndef MYTINYSTL_HASHTABLE_H_ +#define MYTINYSTL_HASHTABLE_H_ + +// 这个头文件包含了一个模板类 hashtable +// hashtable : 哈希表,使用开链法处理冲突 + +#include + +#include "algo.h" +#include "functional.h" +#include "memory.h" +#include "vector.h" +#include "util.h" +#include "exceptdef.h" + +namespace mystl +{ + +// hashtable 的节点定义 +template +struct hashtable_node +{ + hashtable_node* next; // 指向下一个节点 + T value; // 储存实值 + + hashtable_node() = default; + hashtable_node(const T& n) :next(nullptr), value(n) {} + + hashtable_node(const hashtable_node& node) :next(node.next), value(node.value) {} + hashtable_node(hashtable_node&& node) :next(node.next), value(mystl::move(node.value)) + { + node.next = nullptr; + } +}; + +// value traits +template +struct ht_value_traits_imp +{ + typedef T key_type; + typedef T mapped_type; + typedef T value_type; + + template + static const key_type& get_key(const Ty& value) + { + return value; + } + + template + static const value_type& get_value(const Ty& value) + { + return value; + } +}; + +template +struct ht_value_traits_imp +{ + typedef typename std::remove_cv::type key_type; + typedef typename T::second_type mapped_type; + typedef T value_type; + + template + static const key_type& get_key(const Ty& value) + { + return value.first; + } + + template + static const value_type& get_value(const Ty& value) + { + return value; + } +}; + +template +struct ht_value_traits +{ + static constexpr bool is_map = mystl::is_pair::value; + + typedef ht_value_traits_imp value_traits_type; + + typedef typename value_traits_type::key_type key_type; + typedef typename value_traits_type::mapped_type mapped_type; + typedef typename value_traits_type::value_type value_type; + + template + static const key_type& get_key(const Ty& value) + { + return value_traits_type::get_key(value); + } + + template + static const value_type& get_value(const Ty& value) + { + return value_traits_type::get_value(value); + } +}; + + +// forward declaration + +template +class hashtable; + +template +struct ht_iterator; + +template +struct ht_const_iterator; + +template +struct ht_local_iterator; + +template +struct ht_const_local_iterator; + +// ht_iterator + +template +struct ht_iterator_base :public mystl::iterator +{ + typedef mystl::hashtable hashtable; + typedef ht_iterator_base base; + typedef mystl::ht_iterator iterator; + typedef mystl::ht_const_iterator const_iterator; + typedef hashtable_node* node_ptr; + typedef hashtable* contain_ptr; + typedef const node_ptr const_node_ptr; + typedef const contain_ptr const_contain_ptr; + + typedef size_t size_type; + typedef ptrdiff_t difference_type; + + node_ptr node; // 迭代器当前所指节点 + contain_ptr ht; // 保持与容器的连结 + + ht_iterator_base() = default; + + bool operator==(const base& rhs) const { return node == rhs.node; } + bool operator!=(const base& rhs) const { return node != rhs.node; } +}; + +template +struct ht_iterator :public ht_iterator_base +{ + typedef ht_iterator_base base; + typedef typename base::hashtable hashtable; + typedef typename base::iterator iterator; + typedef typename base::const_iterator const_iterator; + typedef typename base::node_ptr node_ptr; + typedef typename base::contain_ptr contain_ptr; + + typedef ht_value_traits value_traits; + typedef T value_type; + typedef value_type* pointer; + typedef value_type& reference; + + using base::node; + using base::ht; + + ht_iterator() = default; + ht_iterator(node_ptr n, contain_ptr t) + { + node = n; + ht = t; + } + ht_iterator(const iterator& rhs) + { + node = rhs.node; + ht = rhs.ht; + } + ht_iterator(const const_iterator& rhs) + { + node = rhs.node; + ht = rhs.ht; + } + iterator& operator=(const iterator& rhs) + { + if (this != &rhs) + { + node = rhs.node; + ht = rhs.ht; + } + return *this; + } + iterator& operator=(const const_iterator& rhs) + { + if (this != &rhs) + { + node = rhs.node; + ht = rhs.ht; + } + return *this; + } + + // 重载操作符 + reference operator*() const { return node->value; } + pointer operator->() const { return &(operator*()); } + + iterator& operator++() + { + MYSTL_DEBUG(node != nullptr); + const node_ptr old = node; + node = node->next; + if (node == nullptr) + { // 如果下一个位置为空,跳到下一个 bucket 的起始处 + auto index = ht->hash(value_traits::get_key(old->value)); + while (!node && ++index < ht->bucket_size_) + node = ht->buckets_[index]; + } + return *this; + } + iterator operator++(int) + { + iterator tmp = *this; + ++*this; + return tmp; + } +}; + +template +struct ht_const_iterator :public ht_iterator_base +{ + typedef ht_iterator_base base; + typedef typename base::hashtable hashtable; + typedef typename base::iterator iterator; + typedef typename base::const_iterator const_iterator; + typedef typename base::const_node_ptr node_ptr; + typedef typename base::const_contain_ptr contain_ptr; + + typedef ht_value_traits value_traits; + typedef T value_type; + typedef const value_type* pointer; + typedef const value_type& reference; + + using base::node; + using base::ht; + + ht_const_iterator() = default; + ht_const_iterator(node_ptr n, contain_ptr t) + { + node = n; + ht = t; + } + ht_const_iterator(const iterator& rhs) + { + node = rhs.node; + ht = rhs.ht; + } + ht_const_iterator(const const_iterator& rhs) + { + node = rhs.node; + ht = rhs.ht; + } + const_iterator& operator=(const iterator& rhs) + { + if (this != &rhs) + { + node = rhs.node; + ht = rhs.ht; + } + return *this; + } + const_iterator& operator=(const const_iterator& rhs) + { + if (this != &rhs) + { + node = rhs.node; + ht = rhs.ht; + } + return *this; + } + + // 重载操作符 + reference operator*() const { return node->value; } + pointer operator->() const { return &(operator*()); } + + const_iterator& operator++() + { + MYSTL_DEBUG(node != nullptr); + const node_ptr old = node; + node = node->next; + if (node == nullptr) + { // 如果下一个位置为空,跳到下一个 bucket 的起始处 + auto index = ht->hash(value_traits::get_key(old->value)); + while (!node && ++index < ht->bucket_size_) + { + node = ht->buckets_[index]; + } + } + return *this; + } + const_iterator operator++(int) + { + const_iterator tmp = *this; + ++*this; + return tmp; + } +}; + +// local iterator +template +struct ht_local_iterator :public mystl::iterator +{ + typedef T value_type; + typedef value_type* pointer; + typedef value_type& reference; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef hashtable_node* node_ptr; + + typedef ht_local_iterator self; + typedef ht_local_iterator local_iterator; + typedef ht_const_local_iterator const_local_iterator; + node_ptr node; + + ht_local_iterator(node_ptr n) + :node(n) + { + } + ht_local_iterator(const local_iterator& rhs) + :node(rhs.node) + { + } + ht_local_iterator(const const_local_iterator& rhs) + :node(rhs.node) + { + } + + reference operator*() const { return node->value; } + pointer operator->() const { return &(operator*()); } + + self& operator++() + { + MYSTL_DEBUG(node != nullptr); + node = node->next; + return *this; + } + + self operator++(int) + { + self tmp(*this); + ++*this; + return tmp; + } + + bool operator==(const self& other) const { return node == other.node; } + bool operator!=(const self& other) const { return node != other.node; } +}; + +template +struct ht_const_local_iterator :public mystl::iterator +{ + typedef T value_type; + typedef const value_type* pointer; + typedef const value_type& reference; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef const hashtable_node* node_ptr; + + typedef ht_const_local_iterator self; + typedef ht_local_iterator local_iterator; + typedef ht_const_local_iterator const_local_iterator; + + node_ptr node; + + ht_const_local_iterator(node_ptr n) + :node(n) + { + } + ht_const_local_iterator(const local_iterator& rhs) + :node(rhs.node) + { + } + ht_const_local_iterator(const const_local_iterator& rhs) + :node(rhs.node) + { + } + + reference operator*() const { return node->value; } + pointer operator->() const { return &(operator*()); } + + self& operator++() + { + MYSTL_DEBUG(node != nullptr); + node = node->next; + return *this; + } + + self operator++(int) + { + self tmp(*this); + ++*this; + return tmp; + } + + bool operator==(const self& other) const { return node == other.node; } + bool operator!=(const self& other) const { return node != other.node; } +}; + +// bucket 使用的大小 + +#if (_MSC_VER && _WIN64) || ((__GNUC__ || __clang__) &&__SIZEOF_POINTER__ == 8) +#define SYSTEM_64 1 +#else +#define SYSTEM_32 1 +#endif + +#ifdef SYSTEM_64 + +#define PRIME_NUM 99 + +// 1. start with p = 101 +// 2. p = next_prime(p * 1.7) +// 3. if p < (2 << 63), go to step 2, otherwise, go to step 4 +// 4. end with p = prev_prime(2 << 63 - 1) +static constexpr size_t ht_prime_list[] = { + 101ull, 173ull, 263ull, 397ull, 599ull, 907ull, 1361ull, 2053ull, 3083ull, + 4637ull, 6959ull, 10453ull, 15683ull, 23531ull, 35311ull, 52967ull, 79451ull, + 119179ull, 178781ull, 268189ull, 402299ull, 603457ull, 905189ull, 1357787ull, + 2036687ull, 3055043ull, 4582577ull, 6873871ull, 10310819ull, 15466229ull, + 23199347ull, 34799021ull, 52198537ull, 78297827ull, 117446801ull, 176170229ull, + 264255353ull, 396383041ull, 594574583ull, 891861923ull, 1337792887ull, + 2006689337ull, 3010034021ull, 4515051137ull, 6772576709ull, 10158865069ull, + 15238297621ull, 22857446471ull, 34286169707ull, 51429254599ull, 77143881917ull, + 115715822899ull, 173573734363ull, 260360601547ull, 390540902329ull, + 585811353559ull, 878717030339ull, 1318075545511ull, 1977113318311ull, + 2965669977497ull, 4448504966249ull, 6672757449409ull, 10009136174239ull, + 15013704261371ull, 22520556392057ull, 33780834588157ull, 50671251882247ull, + 76006877823377ull, 114010316735089ull, 171015475102649ull, 256523212653977ull, + 384784818980971ull, 577177228471507ull, 865765842707309ull, 1298648764060979ull, + 1947973146091477ull, 2921959719137273ull, 4382939578705967ull, 6574409368058969ull, + 9861614052088471ull, 14792421078132871ull, 22188631617199337ull, 33282947425799017ull, + 49924421138698549ull, 74886631708047827ull, 112329947562071807ull, 168494921343107851ull, + 252742382014661767ull, 379113573021992729ull, 568670359532989111ull, 853005539299483657ull, + 1279508308949225477ull, 1919262463423838231ull, 2878893695135757317ull, 4318340542703636011ull, + 6477510814055453699ull, 9716266221083181299ull, 14574399331624771603ull, 18446744073709551557ull +}; + +#else + +#define PRIME_NUM 44 + +// 1. start with p = 101 +// 2. p = next_prime(p * 1.7) +// 3. if p < (2 << 31), go to step 2, otherwise, go to step 4 +// 4. end with p = prev_prime(2 << 31 - 1) +static constexpr size_t ht_prime_list[] = { + 101u, 173u, 263u, 397u, 599u, 907u, 1361u, 2053u, 3083u, 4637u, 6959u, + 10453u, 15683u, 23531u, 35311u, 52967u, 79451u, 119179u, 178781u, 268189u, + 402299u, 603457u, 905189u, 1357787u, 2036687u, 3055043u, 4582577u, 6873871u, + 10310819u, 15466229u, 23199347u, 34799021u, 52198537u, 78297827u, 117446801u, + 176170229u, 264255353u, 396383041u, 594574583u, 891861923u, 1337792887u, + 2006689337u, 3010034021u, 4294967291u, +}; + +#endif + +// 找出最接近并大于等于 n 的那个质数 +inline size_t ht_next_prime(size_t n) +{ + const size_t* first = ht_prime_list; + const size_t* last = ht_prime_list + PRIME_NUM; + const size_t* pos = mystl::lower_bound(first, last, n); + return pos == last ? *(last - 1) : *pos; +} + +// 模板类 hashtable +// 参数一代表数据类型,参数二代表哈希函数,参数三代表键值相等的比较函数 +template +class hashtable +{ + + friend struct mystl::ht_iterator; + friend struct mystl::ht_const_iterator; + +public: + // hashtable 的型别定义 + typedef ht_value_traits value_traits; + typedef typename value_traits::key_type key_type; + typedef typename value_traits::mapped_type mapped_type; + typedef typename value_traits::value_type value_type; + typedef Hash hasher; + typedef KeyEqual key_equal; + + typedef hashtable_node node_type; + typedef node_type* node_ptr; + typedef mystl::vector bucket_type; + + typedef mystl::allocator allocator_type; + typedef mystl::allocator data_allocator; + typedef mystl::allocator node_allocator; + + typedef typename allocator_type::pointer pointer; + typedef typename allocator_type::const_pointer const_pointer; + typedef typename allocator_type::reference reference; + typedef typename allocator_type::const_reference const_reference; + typedef typename allocator_type::size_type size_type; + typedef typename allocator_type::difference_type difference_type; + + typedef mystl::ht_iterator iterator; + typedef mystl::ht_const_iterator const_iterator; + typedef mystl::ht_local_iterator local_iterator; + typedef mystl::ht_const_local_iterator const_local_iterator; + + allocator_type get_allocator() const { return allocator_type(); } + +private: + // 用以下六个参数来表现 hashtable + bucket_type buckets_; + size_type bucket_size_; + size_type size_; + float mlf_; + hasher hash_; + key_equal equal_; + +private: + bool is_equal(const key_type& key1, const key_type& key2) + { + return equal_(key1, key2); + } + + bool is_equal(const key_type& key1, const key_type& key2) const + { + return equal_(key1, key2); + } + + const_iterator M_cit(node_ptr node) const noexcept + { + return const_iterator(node, const_cast(this)); + } + + iterator M_begin() noexcept + { + for (size_type n = 0; n < bucket_size_; ++n) + { + if (buckets_[n]) // 找到第一个有节点的位置就返回 + return iterator(buckets_[n], this); + } + return iterator(nullptr, this); + } + + const_iterator M_begin() const noexcept + { + for (size_type n = 0; n < bucket_size_; ++n) + { + if (buckets_[n]) // 找到第一个有节点的位置就返回 + return M_cit(buckets_[n]); + } + return M_cit(nullptr); + } + +public: + // 构造、复制、移动、析构函数 + explicit hashtable(size_type bucket_count, + const Hash& hash = Hash(), + const KeyEqual& equal = KeyEqual()) + :size_(0), mlf_(1.0f), hash_(hash), equal_(equal) + { + init(bucket_count); + } + + template ::value, int>::type = 0> + hashtable(Iter first, Iter last, + size_type bucket_count, + const Hash& hash = Hash(), + const KeyEqual& equal = KeyEqual()) + :size_(mystl::distance(first, last)), mlf_(1.0f), hash_(hash), equal_(equal) + { + init(mystl::max(bucket_count, static_cast(mystl::distance(first, last)))); + } + + hashtable(const hashtable& rhs) + :hash_(rhs.hash_), equal_(rhs.equal_) + { + copy_init(rhs); + } + hashtable(hashtable&& rhs) noexcept + : bucket_size_(rhs.bucket_size_), + size_(rhs.size_), + mlf_(rhs.mlf_), + hash_(rhs.hash_), + equal_(rhs.equal_) + { + buckets_ = mystl::move(rhs.buckets_); + rhs.bucket_size_ = 0; + rhs.size_ = 0; + rhs.mlf_ = 0.0f; + } + + hashtable& operator=(const hashtable& rhs); + hashtable& operator=(hashtable&& rhs) noexcept; + + ~hashtable() { clear(); } + + // 迭代器相关操作 + iterator begin() noexcept + { return M_begin(); } + const_iterator begin() const noexcept + { return M_begin(); } + iterator end() noexcept + { return iterator(nullptr, this); } + const_iterator end() const noexcept + { return M_cit(nullptr); } + + const_iterator cbegin() const noexcept + { return begin(); } + const_iterator cend() const noexcept + { return end(); } + + // 容量相关操作 + bool empty() const noexcept { return size_ == 0; } + size_type size() const noexcept { return size_; } + size_type max_size() const noexcept { return static_cast(-1); } + + // 修改容器相关操作 + + // emplace / empalce_hint + + template + iterator emplace_multi(Args&& ...args); + + template + pair emplace_unique(Args&& ...args); + + // [note]: hint 对于 hash_table 其实没有意义,因为即使提供了 hint,也要做一次 hash, + // 来确保 hash_table 的性质,所以选择忽略它 + template + iterator emplace_multi_use_hint(const_iterator /*hint*/, Args&& ...args) + { return emplace_multi(mystl::forward(args)...); } + + template + iterator emplace_unique_use_hint(const_iterator /*hint*/, Args&& ...args) + { return emplace_unique(mystl::forward(args)...).first; } + + // insert + + iterator insert_multi_noresize(const value_type& value); + pair insert_unique_noresize(const value_type& value); + + iterator insert_multi(const value_type& value) + { + rehash_if_need(1); + return insert_multi_noresize(value); + } + iterator insert_multi(value_type&& value) + { return emplace_multi(mystl::move(value)); } + + + pair insert_unique(const value_type& value) + { + rehash_if_need(1); + return insert_unique_noresize(value); + } + pair insert_unique(value_type&& value) + { return emplace_unique(mystl::move(value)); } + + // [note]: 同 emplace_hint + iterator insert_multi_use_hint(const_iterator /*hint*/, const value_type& value) + { return insert_multi(value); } + iterator insert_multi_use_hint(const_iterator /*hint*/, value_type&& value) + { return emplace_multi(mystl::move(value)); } + + iterator insert_unique_use_hint(const_iterator /*hint*/, const value_type& value) + { return insert_unique(value).first; } + iterator insert_unique_use_hint(const_iterator /*hint*/, value_type&& value) + { return emplace_unique(mystl::move(value)); } + + template + void insert_multi(InputIter first, InputIter last) + { copy_insert_multi(first, last, iterator_category(first)); } + + template + void insert_unique(InputIter first, InputIter last) + { copy_insert_unique(first, last, iterator_category(first)); } + + // erase / clear + + void erase(const_iterator position); + void erase(const_iterator first, const_iterator last); + + size_type erase_multi(const key_type& key); + size_type erase_unique(const key_type& key); + + void clear(); + + void swap(hashtable& rhs) noexcept; + + // 查找相关操作 + + size_type count(const key_type& key) const; + + iterator find(const key_type& key); + const_iterator find(const key_type& key) const; + + pair equal_range_multi(const key_type& key); + pair equal_range_multi(const key_type& key) const; + + pair equal_range_unique(const key_type& key); + pair equal_range_unique(const key_type& key) const; + + // bucket interface + + local_iterator begin(size_type n) noexcept + { + MYSTL_DEBUG(n < size_); + return buckets_[n]; + } + const_local_iterator begin(size_type n) const noexcept + { + MYSTL_DEBUG(n < size_); + return buckets_[n]; + } + const_local_iterator cbegin(size_type n) const noexcept + { + MYSTL_DEBUG(n < size_); + return buckets_[n]; + } + + local_iterator end(size_type n) noexcept + { + MYSTL_DEBUG(n < size_); + return nullptr; + } + const_local_iterator end(size_type n) const noexcept + { + MYSTL_DEBUG(n < size_); + return nullptr; + } + const_local_iterator cend(size_type n) const noexcept + { + MYSTL_DEBUG(n < size_); + return nullptr; + } + + size_type bucket_count() const noexcept + { return bucket_size_; } + size_type max_bucket_count() const noexcept + { return ht_prime_list[PRIME_NUM - 1]; } + + size_type bucket_size(size_type n) const noexcept; + size_type bucket(const key_type& key) const + { return hash(key); } + + // hash policy + + float load_factor() const noexcept + { return bucket_size_ != 0 ? (float)size_ / bucket_size_ : 0.0f; } + + float max_load_factor() const noexcept + { return mlf_; } + void max_load_factor(float ml) + { + THROW_OUT_OF_RANGE_IF(ml != ml || ml < 0, "invalid hash load factor"); + mlf_ = ml; + } + + void rehash(size_type count); + + void reserve(size_type count) + { rehash(static_cast((float)count / max_load_factor() + 0.5f)); } + + hasher hash_fcn() const { return hash_; } + key_equal key_eq() const { return equal_; } + +private: + // hashtable 成员函数 + + // init + void init(size_type n); + void copy_init(const hashtable& ht); + + // node + template + node_ptr create_node(Args&& ...args); + void destroy_node(node_ptr n); + + // hash + size_type next_size(size_type n) const; + size_type hash(const key_type& key, size_type n) const; + size_type hash(const key_type& key) const; + void rehash_if_need(size_type n); + + // insert + template + void copy_insert_multi(InputIter first, InputIter last, mystl::input_iterator_tag); + template + void copy_insert_multi(ForwardIter first, ForwardIter last, mystl::forward_iterator_tag); + template + void copy_insert_unique(InputIter first, InputIter last, mystl::input_iterator_tag); + template + void copy_insert_unique(ForwardIter first, ForwardIter last, mystl::forward_iterator_tag); + + // insert node + pair insert_node_unique(node_ptr np); + iterator insert_node_multi(node_ptr np); + + // bucket operator + void replace_bucket(size_type bucket_count); + void erase_bucket(size_type n, node_ptr first, node_ptr last); + void erase_bucket(size_type n, node_ptr last); + + // comparision + bool equal_to_multi(const hashtable& other); + bool equal_to_unique(const hashtable& other); +}; + +/*****************************************************************************************/ + +// 复制赋值运算符 +template +hashtable& +hashtable:: +operator=(const hashtable& rhs) +{ + if (this != &rhs) + { + hashtable tmp(rhs); + swap(tmp); + } + return *this; +} + +// 移动赋值运算符 +template +hashtable& +hashtable:: +operator=(hashtable&& rhs) noexcept +{ + hashtable tmp(mystl::move(rhs)); + swap(tmp); + return *this; +} + +// 就地构造元素,键值允许重复 +// 强异常安全保证 +template +template +typename hashtable::iterator +hashtable:: +emplace_multi(Args&& ...args) +{ + auto np = create_node(mystl::forward(args)...); + try + { + if ((float)(size_ + 1) > (float)bucket_size_ * max_load_factor()) + rehash(size_ + 1); + } + catch (...) + { + destroy_node(np); + throw; + } + return insert_node_multi(np); +} + +// 就地构造元素,键值允许重复 +// 强异常安全保证 +template +template +pair::iterator, bool> +hashtable:: +emplace_unique(Args&& ...args) +{ + auto np = create_node(mystl::forward(args)...); + try + { + if ((float)(size_ + 1) > (float)bucket_size_ * max_load_factor()) + rehash(size_ + 1); + } + catch (...) + { + destroy_node(np); + throw; + } + return insert_node_unique(np); +} + +// 在不需要重建表格的情况下插入新节点,键值不允许重复 +template +pair::iterator, bool> +hashtable:: +insert_unique_noresize(const value_type& value) +{ + const auto n = hash(value_traits::get_key(value)); + auto first = buckets_[n]; + for (auto cur = first; cur; cur = cur->next) + { + if (is_equal(value_traits::get_key(cur->value), value_traits::get_key(value))) + return mystl::make_pair(iterator(cur, this), false); + } + // 让新节点成为链表的第一个节点 + auto tmp = create_node(value); + tmp->next = first; + buckets_[n] = tmp; + ++size_; + return mystl::make_pair(iterator(tmp, this), true); +} + +// 在不需要重建表格的情况下插入新节点,键值允许重复 +template +typename hashtable::iterator +hashtable:: +insert_multi_noresize(const value_type& value) +{ + const auto n = hash(value_traits::get_key(value)); + auto first = buckets_[n]; + auto tmp = create_node(value); + for (auto cur = first; cur; cur = cur->next) + { + if (is_equal(value_traits::get_key(cur->value), value_traits::get_key(value))) + { // 如果链表中存在相同键值的节点就马上插入,然后返回 + tmp->next = cur->next; + cur->next = tmp; + ++size_; + return iterator(tmp, this); + } + } + // 否则插入在链表头部 + tmp->next = first; + buckets_[n] = tmp; + ++size_; + return iterator(tmp, this); +} + +// 删除迭代器所指的节点 +template +void hashtable:: +erase(const_iterator position) +{ + auto p = position.node; + if (p) + { + const auto n = hash(value_traits::get_key(p->value)); + auto cur = buckets_[n]; + if (cur == p) + { // p 位于链表头部 + buckets_[n] = cur->next; + destroy_node(cur); + --size_; + } + else + { + auto next = cur->next; + while (next) + { + if (next == p) + { + cur->next = next->next; + destroy_node(next); + --size_; + break; + } + else + { + cur = next; + next = cur->next; + } + } + } + } +} + +// 删除[first, last)内的节点 +template +void hashtable:: +erase(const_iterator first, const_iterator last) +{ + if (first.node == last.node) + return; + auto first_bucket = first.node + ? hash(value_traits::get_key(first.node->value)) + : bucket_size_; + auto last_bucket = last.node + ? hash(value_traits::get_key(last.node->value)) + : bucket_size_; + if (first_bucket == last_bucket) + { // 如果在 bucket 在同一个位置 + erase_bucket(first_bucket, first.node, last.node); + } + else + { + erase_bucket(first_bucket, first.node, nullptr); + for (auto n = first_bucket + 1; n < last_bucket; ++n) + { + if(buckets_[n] != nullptr) + erase_bucket(n, nullptr); + } + if (last_bucket != bucket_size_) + { + erase_bucket(last_bucket, last.node); + } + } +} + +// 删除键值为 key 的节点 +template +typename hashtable::size_type +hashtable:: +erase_multi(const key_type& key) +{ + auto p = equal_range_multi(key); + if (p.first.node != nullptr) + { + erase(p.first, p.second); + return mystl::distance(p.first, p.second); + } + return 0; +} + +template +typename hashtable::size_type +hashtable:: +erase_unique(const key_type& key) +{ + const auto n = hash(key); + auto first = buckets_[n]; + if (first) + { + if (is_equal(value_traits::get_key(first->value), key)) + { + buckets_[n] = first->next; + destroy_node(first); + --size_; + return 1; + } + else + { + auto next = first->next; + while (next) + { + if (is_equal(value_traits::get_key(next->value), key)) + { + first->next = next->next; + destroy_node(next); + --size_; + return 1; + } + first = next; + next = first->next; + } + } + } + return 0; +} + +// 清空 hashtable +template +void hashtable:: +clear() +{ + if (size_ != 0) + { + for (size_type i = 0; i < bucket_size_; ++i) + { + node_ptr cur = buckets_[i]; + while (cur != nullptr) + { + node_ptr next = cur->next; + destroy_node(cur); + cur = next; + } + buckets_[i] = nullptr; + } + size_ = 0; + } +} + +// 在某个 bucket 节点的个数 +template +typename hashtable::size_type +hashtable:: +bucket_size(size_type n) const noexcept +{ + size_type result = 0; + for (auto cur = buckets_[n]; cur; cur = cur->next) + { + ++result; + } + return result; +} + +// 重新对元素进行一遍哈希,插入到新的位置 +template +void hashtable:: +rehash(size_type count) +{ + auto n = ht_next_prime(count); + if (n > bucket_size_) + { + replace_bucket(n); + } + else + { + if ((float)size_ / (float)n < max_load_factor() - 0.25f && + (float)n < (float)bucket_size_ * 0.75) // worth rehash + { + replace_bucket(n); + } + } +} + +// 查找键值为 key 的节点,返回其迭代器 +template +typename hashtable::iterator +hashtable:: +find(const key_type& key) +{ + const auto n = hash(key); + node_ptr first = buckets_[n]; + for (; first && !is_equal(value_traits::get_key(first->value), key); first = first->next) {} + return iterator(first, this); +} + +template +typename hashtable::const_iterator +hashtable:: +find(const key_type& key) const +{ + const auto n = hash(key); + node_ptr first = buckets_[n]; + for (; first && !is_equal(value_traits::get_key(first->value), key); first = first->next) {} + return M_cit(first); +} + +// 查找键值为 key 出现的次数 +template +typename hashtable::size_type +hashtable:: +count(const key_type& key) const +{ + const auto n = hash(key); + size_type result = 0; + for (node_ptr cur = buckets_[n]; cur; cur = cur->next) + { + if (is_equal(value_traits::get_key(cur->value), key)) + ++result; + } + return result; +} + +// 查找与键值 key 相等的区间,返回一个 pair,指向相等区间的首尾 +template +pair::iterator, + typename hashtable::iterator> +hashtable:: +equal_range_multi(const key_type& key) +{ + const auto n = hash(key); + for (node_ptr first = buckets_[n]; first; first = first->next) + { + if (is_equal(value_traits::get_key(first->value), key)) + { // 如果出现相等的键值 + for (node_ptr second = first->next; second; second = second->next) + { + if (!is_equal(value_traits::get_key(second->value), key)) + return mystl::make_pair(iterator(first, this), iterator(second, this)); + } + for (auto m = n + 1; m < bucket_size_; ++m) + { // 整个链表都相等,查找下一个链表出现的位置 + if (buckets_[m]) + return mystl::make_pair(iterator(first, this), iterator(buckets_[m], this)); + } + return mystl::make_pair(iterator(first, this), end()); + } + } + return mystl::make_pair(end(), end()); +} + +template +pair::const_iterator, + typename hashtable::const_iterator> +hashtable:: +equal_range_multi(const key_type& key) const +{ + const auto n = hash(key); + for (node_ptr first = buckets_[n]; first; first = first->next) + { + if (is_equal(value_traits::get_key(first->value), key)) + { + for (node_ptr second = first->next; second; second = second->next) + { + if (!is_equal(value_traits::get_key(second->value), key)) + return mystl::make_pair(M_cit(first), M_cit(second)); + } + for (auto m = n + 1; m < bucket_size_; ++m) + { // 整个链表都相等,查找下一个链表出现的位置 + if (buckets_[m]) + return mystl::make_pair(M_cit(first), M_cit(buckets_[m])); + } + return mystl::make_pair(M_cit(first), cend()); + } + } + return mystl::make_pair(cend(), cend()); +} + +template +pair::iterator, + typename hashtable::iterator> +hashtable:: +equal_range_unique(const key_type& key) +{ + const auto n = hash(key); + for (node_ptr first = buckets_[n]; first; first = first->next) + { + if (is_equal(value_traits::get_key(first->value), key)) + { + if (first->next) + return mystl::make_pair(iterator(first, this), iterator(first->next, this)); + for (auto m = n + 1; m < bucket_size_; ++m) + { // 整个链表都相等,查找下一个链表出现的位置 + if (buckets_[m]) + return mystl::make_pair(iterator(first, this), iterator(buckets_[m], this)); + } + return mystl::make_pair(iterator(first, this), end()); + } + } + return mystl::make_pair(end(), end()); +} + +template +pair::const_iterator, + typename hashtable::const_iterator> +hashtable:: +equal_range_unique(const key_type& key) const +{ + const auto n = hash(key); + for (node_ptr first = buckets_[n]; first; first = first->next) + { + if (is_equal(value_traits::get_key(first->value), key)) + { + if (first->next) + return mystl::make_pair(M_cit(first), M_cit(first->next)); + for (auto m = n + 1; m < bucket_size_; ++m) + { // 整个链表都相等,查找下一个链表出现的位置 + if (buckets_[m]) + return mystl::make_pair(M_cit(first), M_cit(buckets_[m])); + } + return mystl::make_pair(M_cit(first), cend()); + } + } + return mystl::make_pair(cend(), cend()); +} + +// 交换 hashtable +template +void hashtable:: +swap(hashtable& rhs) noexcept +{ + if (this != &rhs) + { + buckets_.swap(rhs.buckets_); + mystl::swap(bucket_size_, rhs.bucket_size_); + mystl::swap(size_, rhs.size_); + mystl::swap(mlf_, rhs.mlf_); + mystl::swap(hash_, rhs.hash_); + mystl::swap(equal_, rhs.equal_); + } +} + +/****************************************************************************************/ +// helper function + +// init 函数 +template +void hashtable:: +init(size_type n) +{ + const auto bucket_nums = next_size(n); + try + { + buckets_.reserve(bucket_nums); + buckets_.assign(bucket_nums, nullptr); + } + catch (...) + { + bucket_size_ = 0; + size_ = 0; + throw; + } + bucket_size_ = buckets_.size(); +} + +// copy_init 函数 +template +void hashtable:: +copy_init(const hashtable& ht) +{ + bucket_size_ = 0; + buckets_.reserve(ht.bucket_size_); + buckets_.assign(ht.bucket_size_, nullptr); + try + { + for (size_type i = 0; i < ht.bucket_size_; ++i) + { + node_ptr cur = ht.buckets_[i]; + if (cur) + { // 如果某 bucket 存在链表 + auto copy = create_node(cur->value); + buckets_[i] = copy; + for (auto next = cur->next; next; cur = next, next = cur->next) + { //复制链表 + copy->next = create_node(next->value); + copy = copy->next; + } + copy->next = nullptr; + } + } + bucket_size_ = ht.bucket_size_; + mlf_ = ht.mlf_; + size_ = ht.size_; + } + catch (...) + { + clear(); + } +} + +// create_node 函数 +template +template +typename hashtable::node_ptr +hashtable:: +create_node(Args&& ...args) +{ + node_ptr tmp = node_allocator::allocate(1); + try + { + data_allocator::construct(mystl::address_of(tmp->value), mystl::forward(args)...); + tmp->next = nullptr; + } + catch (...) + { + node_allocator::deallocate(tmp); + throw; + } + return tmp; +} + +// destroy_node 函数 +template +void hashtable:: +destroy_node(node_ptr node) +{ + data_allocator::destroy(mystl::address_of(node->value)); + node_allocator::deallocate(node); + node = nullptr; +} + +// next_size 函数 +template +typename hashtable::size_type +hashtable::next_size(size_type n) const +{ + return ht_next_prime(n); +} + +// hash 函数 +template +typename hashtable::size_type +hashtable:: +hash(const key_type& key, size_type n) const +{ + return hash_(key) % n; +} + +template +typename hashtable::size_type +hashtable:: +hash(const key_type& key) const +{ + return hash_(key) % bucket_size_; +} + +// rehash_if_need 函数 +template +void hashtable:: +rehash_if_need(size_type n) +{ + if (static_cast(size_ + n) > (float)bucket_size_ * max_load_factor()) + rehash(size_ + n); +} + +// copy_insert +template +template +void hashtable:: +copy_insert_multi(InputIter first, InputIter last, mystl::input_iterator_tag) +{ + rehash_if_need(mystl::distance(first, last)); + for (; first != last; ++first) + insert_multi_noresize(*first); +} + +template +template +void hashtable:: +copy_insert_multi(ForwardIter first, ForwardIter last, mystl::forward_iterator_tag) +{ + size_type n = mystl::distance(first, last); + rehash_if_need(n); + for (; n > 0; --n, ++first) + insert_multi_noresize(*first); +} + +template +template +void hashtable:: +copy_insert_unique(InputIter first, InputIter last, mystl::input_iterator_tag) +{ + rehash_if_need(mystl::distance(first, last)); + for (; first != last; ++first) + insert_unique_noresize(*first); +} + +template +template +void hashtable:: +copy_insert_unique(ForwardIter first, ForwardIter last, mystl::forward_iterator_tag) +{ + size_type n = mystl::distance(first, last); + rehash_if_need(n); + for (; n > 0; --n, ++first) + insert_unique_noresize(*first); +} + +// insert_node 函数 +template +typename hashtable::iterator +hashtable:: +insert_node_multi(node_ptr np) +{ + const auto n = hash(value_traits::get_key(np->value)); + auto cur = buckets_[n]; + if (cur == nullptr) + { + buckets_[n] = np; + ++size_; + return iterator(np, this); + } + for (; cur; cur = cur->next) + { + if (is_equal(value_traits::get_key(cur->value), value_traits::get_key(np->value))) + { + np->next = cur->next; + cur->next = np; + ++size_; + return iterator(np, this); + } + } + np->next = buckets_[n]; + buckets_[n] = np; + ++size_; + return iterator(np, this); +} + +// insert_node_unique 函数 +template +pair::iterator, bool> +hashtable:: +insert_node_unique(node_ptr np) +{ + const auto n = hash(value_traits::get_key(np->value)); + auto cur = buckets_[n]; + if (cur == nullptr) + { + buckets_[n] = np; + ++size_; + return mystl::make_pair(iterator(np, this), true); + } + for (; cur; cur = cur->next) + { + if (is_equal(value_traits::get_key(cur->value), value_traits::get_key(np->value))) + { + return mystl::make_pair(iterator(cur, this), false); + } + } + np->next = buckets_[n]; + buckets_[n] = np; + ++size_; + return mystl::make_pair(iterator(np, this), true); +} + +// replace_bucket 函数 +template +void hashtable:: +replace_bucket(size_type bucket_count) +{ + bucket_type bucket(bucket_count); + if (size_ != 0) + { + for (size_type i = 0; i < bucket_size_; ++i) + { + for (auto first = buckets_[i]; first; first = first->next) + { + auto tmp = create_node(first->value); + const auto n = hash(value_traits::get_key(first->value), bucket_count); + auto f = bucket[n]; + bool is_inserted = false; + for (auto cur = f; cur; cur = cur->next) + { + if (is_equal(value_traits::get_key(cur->value), value_traits::get_key(first->value))) + { + tmp->next = cur->next; + cur->next = tmp; + is_inserted = true; + break; + } + } + if (!is_inserted) + { + tmp->next = f; + bucket[n] = tmp; + } + } + } + } + buckets_.swap(bucket); + bucket_size_ = buckets_.size(); +} + +// erase_bucket 函数 +// 在第 n 个 bucket 内,删除 [first, last) 的节点 +template +void hashtable:: +erase_bucket(size_type n, node_ptr first, node_ptr last) +{ + auto cur = buckets_[n]; + if (cur == first) + { + erase_bucket(n, last); + } + else + { + node_ptr next = cur->next; + for (; next != first; cur = next, next = cur->next) {} + while (next != last) + { + cur->next = next->next; + destroy_node(next); + next = cur->next; + --size_; + } + } +} + +// erase_bucket 函数 +// 在第 n 个 bucket 内,删除 [buckets_[n], last) 的节点 +template +void hashtable:: +erase_bucket(size_type n, node_ptr last) +{ + auto cur = buckets_[n]; + while (cur != last) + { + auto next = cur->next; + destroy_node(cur); + cur = next; + --size_; + } + buckets_[n] = last; +} + +// equal_to 函数 +template +bool hashtable::equal_to_multi(const hashtable& other) +{ + if (size_ != other.size_) + return false; + for (auto f = begin(), l = end(); f != l;) + { + auto p1 = equal_range_multi(value_traits::get_key(*f)); + auto p2 = other.equal_range_multi(value_traits::get_key(*f)); + if (mystl::distance(p1.first, p1.last) != mystl::distance(p2.first, p2.last) || + !mystl::is_permutation(p1.first, p2.last, p2.first, p2.last)) + return false; + f = p1.last; + } + return true; +} + +template +bool hashtable::equal_to_unique(const hashtable& other) +{ + if (size_ != other.size_) + return false; + for (auto f = begin(), l = end(); f != l; ++f) + { + auto res = other.find(value_traits::get_key(*f)); + if (res.node == nullptr || *res != *f) + return false; + } + return true; +} + +// 重载 mystl 的 swap +template +void swap(hashtable& lhs, + hashtable& rhs) noexcept +{ + lhs.swap(rhs); +} + +} // namespace mystl +#endif // !MYTINYSTL_HASHTABLE_H_ + diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/heap_algo.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/heap_algo.h new file mode 100644 index 0000000..5ab74e2 --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/heap_algo.h @@ -0,0 +1,227 @@ +#ifndef MYTINYSTL_HEAP_ALGO_H_ +#define MYTINYSTL_HEAP_ALGO_H_ + +// 这个头文件包含 heap 的四个算法 : push_heap, pop_heap, sort_heap, make_heap + +#include "iterator.h" + +namespace mystl +{ + +/*****************************************************************************************/ +// push_heap +// 该函数接受两个迭代器,表示一个 heap 容器的首尾,并且新元素已经插入到底部容器的最尾端,调整 heap +/*****************************************************************************************/ +template +void push_heap_aux(RandomIter first, Distance holeIndex, Distance topIndex, T value) +{ + auto parent = (holeIndex - 1) / 2; + while (holeIndex > topIndex && *(first + parent) < value) + { + // 使用 operator<,所以 heap 为 max-heap + *(first + holeIndex) = *(first + parent); + holeIndex = parent; + parent = (holeIndex - 1) / 2; + } + *(first + holeIndex) = value; +} + +template +void push_heap_d(RandomIter first, RandomIter last, Distance*) +{ + mystl::push_heap_aux(first, (last - first) - 1, static_cast(0), *(last - 1)); +} + +template +void push_heap(RandomIter first, RandomIter last) +{ // 新元素应该已置于底部容器的最尾端 + mystl::push_heap_d(first, last, distance_type(first)); +} + +// 重载版本使用函数对象 comp 代替比较操作 +template +void push_heap_aux(RandomIter first, Distance holeIndex, Distance topIndex, T value, + Compared comp) +{ + auto parent = (holeIndex - 1) / 2; + while (holeIndex > topIndex && comp(*(first + parent), value)) + { + *(first + holeIndex) = *(first + parent); + holeIndex = parent; + parent = (holeIndex - 1) / 2; + } + *(first + holeIndex) = value; +} + +template +void push_heap_d(RandomIter first, RandomIter last, Distance*, Compared comp) +{ + mystl::push_heap_aux(first, (last - first) - 1, static_cast(0), + *(last - 1), comp); +} + +template +void push_heap(RandomIter first, RandomIter last, Compared comp) +{ + mystl::push_heap_d(first, last, distance_type(first), comp); +} + +/*****************************************************************************************/ +// pop_heap +// 该函数接受两个迭代器,表示 heap 容器的首尾,将 heap 的根节点取出放到容器尾部,调整 heap +/*****************************************************************************************/ +template +void adjust_heap(RandomIter first, Distance holeIndex, Distance len, T value) +{ + // 先进行下溯(percolate down)过程 + auto topIndex = holeIndex; + auto rchild = 2 * holeIndex + 2; + while (rchild < len) + { + if (*(first + rchild) < *(first + rchild - 1)) + --rchild; + *(first + holeIndex) = *(first + rchild); + holeIndex = rchild; + rchild = 2 * (rchild + 1); + } + if (rchild == len) + { // 如果没有右子节点 + *(first + holeIndex) = *(first + (rchild - 1)); + holeIndex = rchild - 1; + } + // 再执行一次上溯(percolate up)过程 + mystl::push_heap_aux(first, holeIndex, topIndex, value); +} + +template +void pop_heap_aux(RandomIter first, RandomIter last, RandomIter result, T value, + Distance*) +{ + // 先将首值调至尾节点,然后调整[first, last - 1)使之重新成为一个 max-heap + *result = *first; + mystl::adjust_heap(first, static_cast(0), last - first, value); +} + +template +void pop_heap(RandomIter first, RandomIter last) +{ + mystl::pop_heap_aux(first, last - 1, last - 1, *(last - 1), distance_type(first)); +} + +// 重载版本使用函数对象 comp 代替比较操作 +template +void adjust_heap(RandomIter first, Distance holeIndex, Distance len, T value, + Compared comp) +{ + // 先进行下溯(percolate down)过程 + auto topIndex = holeIndex; + auto rchild = 2 * holeIndex + 2; + while (rchild < len) + { + if (comp(*(first + rchild), *(first + rchild - 1))) --rchild; + *(first + holeIndex) = *(first + rchild); + holeIndex = rchild; + rchild = 2 * (rchild + 1); + } + if (rchild == len) + { + *(first + holeIndex) = *(first + (rchild - 1)); + holeIndex = rchild - 1; + } + // 再执行一次上溯(percolate up)过程 + mystl::push_heap_aux(first, holeIndex, topIndex, value, comp); +} + +template +void pop_heap_aux(RandomIter first, RandomIter last, RandomIter result, + T value, Distance*, Compared comp) +{ + *result = *first; // 先将尾指设置成首值,即尾指为欲求结果 + mystl::adjust_heap(first, static_cast(0), last - first, value, comp); +} + +template +void pop_heap(RandomIter first, RandomIter last, Compared comp) +{ + mystl::pop_heap_aux(first, last - 1, last - 1, *(last - 1), + distance_type(first), comp); +} + +/*****************************************************************************************/ +// sort_heap +// 该函数接受两个迭代器,表示 heap 容器的首尾,不断执行 pop_heap 操作,直到首尾最多相差1 +/*****************************************************************************************/ +template +void sort_heap(RandomIter first, RandomIter last) +{ + // 每执行一次 pop_heap,最大的元素都被放到尾部,直到容器最多只有一个元素,完成排序 + while (last - first > 1) + { + mystl::pop_heap(first, last--); + } +} + +// 重载版本使用函数对象 comp 代替比较操作 +template +void sort_heap(RandomIter first, RandomIter last, Compared comp) +{ + while (last - first > 1) + { + mystl::pop_heap(first, last--, comp); + } +} + +/*****************************************************************************************/ +// make_heap +// 该函数接受两个迭代器,表示 heap 容器的首尾,把容器内的数据变为一个 heap +/*****************************************************************************************/ +template +void make_heap_aux(RandomIter first, RandomIter last, Distance*) +{ + if (last - first < 2) + return; + auto len = last - first; + auto holeIndex = (len - 2) / 2; + while (true) + { + // 重排以 holeIndex 为首的子树 + mystl::adjust_heap(first, holeIndex, len, *(first + holeIndex)); + if (holeIndex == 0) + return; + holeIndex--; + } +} + +template +void make_heap(RandomIter first, RandomIter last) +{ + mystl::make_heap_aux(first, last, distance_type(first));; +} + +// 重载版本使用函数对象 comp 代替比较操作 +template +void make_heap_aux(RandomIter first, RandomIter last, Distance*, Compared comp) +{ + if (last - first < 2) + return; + auto len = last - first; + auto holeIndex = (len - 2) / 2; + while (true) + { + // 重排以 holeIndex 为首的子树 + mystl::adjust_heap(first, holeIndex, len, *(first + holeIndex), comp); + if (holeIndex == 0) + return; + holeIndex--; + } +} + +template +void make_heap(RandomIter first, RandomIter last, Compared comp) +{ + mystl::make_heap_aux(first, last, distance_type(first), comp); +} + +} // namespace mystl +#endif // !MYTINYSTL_HEAP_ALGO_H_ + diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/iterator.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/iterator.h new file mode 100644 index 0000000..28a9a69 --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/iterator.h @@ -0,0 +1,366 @@ +#ifndef MYTINYSTL_ITERATOR_H_ +#define MYTINYSTL_ITERATOR_H_ + +// 这个头文件用于迭代器设计,包含了一些模板结构体与全局函数, + +#include + +#include "type_traits.h" + +namespace mystl +{ + +// 五种迭代器类型 +struct input_iterator_tag {}; +struct output_iterator_tag {}; +struct forward_iterator_tag : public input_iterator_tag {}; +struct bidirectional_iterator_tag : public forward_iterator_tag {}; +struct random_access_iterator_tag : public bidirectional_iterator_tag {}; + +// iterator 模板 +template + struct iterator +{ + typedef Category iterator_category; + typedef T value_type; + typedef Pointer pointer; + typedef Reference reference; + typedef Distance difference_type; +}; + +// iterator traits + +template +struct has_iterator_cat +{ +private: + struct two { char a; char b; }; + template static two test(...); + template static char test(typename U::iterator_category* = 0); +public: + static const bool value = sizeof(test(0)) == sizeof(char); +}; + +template +struct iterator_traits_impl {}; + +template +struct iterator_traits_impl +{ + typedef typename Iterator::iterator_category iterator_category; + typedef typename Iterator::value_type value_type; + typedef typename Iterator::pointer pointer; + typedef typename Iterator::reference reference; + typedef typename Iterator::difference_type difference_type; +}; + +template +struct iterator_traits_helper {}; + +template +struct iterator_traits_helper + : public iterator_traits_impl::value || + std::is_convertible::value> +{ +}; + +// 萃取迭代器的特性 +template +struct iterator_traits + : public iterator_traits_helper::value> {}; + +// 针对原生指针的偏特化版本 +template +struct iterator_traits +{ + typedef random_access_iterator_tag iterator_category; + typedef T value_type; + typedef T* pointer; + typedef T& reference; + typedef ptrdiff_t difference_type; +}; + +template +struct iterator_traits +{ + typedef random_access_iterator_tag iterator_category; + typedef T value_type; + typedef const T* pointer; + typedef const T& reference; + typedef ptrdiff_t difference_type; +}; + +template >::value> +struct has_iterator_cat_of + : public m_bool_constant::iterator_category, U>::value> +{ +}; + +// 萃取某种迭代器 +template +struct has_iterator_cat_of : public m_false_type {}; + +template +struct is_input_iterator : public has_iterator_cat_of {}; + +template +struct is_output_iterator : public has_iterator_cat_of {}; + +template +struct is_forward_iterator : public has_iterator_cat_of {}; + +template +struct is_bidirectional_iterator : public has_iterator_cat_of {}; + +template +struct is_random_access_iterator : public has_iterator_cat_of {}; + +template +struct is_iterator : + public m_bool_constant::value || + is_output_iterator::value> +{ +}; + +// 萃取某个迭代器的 category +template +typename iterator_traits::iterator_category +iterator_category(const Iterator&) +{ + typedef typename iterator_traits::iterator_category Category; + return Category(); +} + +// 萃取某个迭代器的 distance_type +template +typename iterator_traits::difference_type* +distance_type(const Iterator&) +{ + return static_cast::difference_type*>(0); +} + +// 萃取某个迭代器的 value_type +template +typename iterator_traits::value_type* +value_type(const Iterator&) +{ + return static_cast::value_type*>(0); +} + +// 以下函数用于计算迭代器间的距离 + +// distance 的 input_iterator_tag 的版本 +template +typename iterator_traits::difference_type +distance_dispatch(InputIterator first, InputIterator last, input_iterator_tag) +{ + typename iterator_traits::difference_type n = 0; + while (first != last) + { + ++first; + ++n; + } + return n; +} + +// distance 的 random_access_iterator_tag 的版本 +template +typename iterator_traits::difference_type +distance_dispatch(RandomIter first, RandomIter last, + random_access_iterator_tag) +{ + return last - first; +} + +template +typename iterator_traits::difference_type +distance(InputIterator first, InputIterator last) +{ + return distance_dispatch(first, last, iterator_category(first)); +} + +// 以下函数用于让迭代器前进 n 个距离 + +// advance 的 input_iterator_tag 的版本 +template +void advance_dispatch(InputIterator& i, Distance n, input_iterator_tag) +{ + while (n--) + ++i; +} + +// advance 的 bidirectional_iterator_tag 的版本 +template +void advance_dispatch(BidirectionalIterator& i, Distance n, bidirectional_iterator_tag) +{ + if (n >= 0) + while (n--) ++i; + else + while (n++) --i; +} + +// advance 的 random_access_iterator_tag 的版本 +template +void advance_dispatch(RandomIter& i, Distance n, random_access_iterator_tag) +{ + i += n; +} + +template +void advance(InputIterator& i, Distance n) +{ + advance_dispatch(i, n, iterator_category(i)); +} + +/*****************************************************************************************/ + +// 模板类 : reverse_iterator +// 代表反向迭代器,使前进为后退,后退为前进 +template +class reverse_iterator +{ +private: + Iterator current; // 记录对应的正向迭代器 + +public: + // 反向迭代器的五种相应型别 + typedef typename iterator_traits::iterator_category iterator_category; + typedef typename iterator_traits::value_type value_type; + typedef typename iterator_traits::difference_type difference_type; + typedef typename iterator_traits::pointer pointer; + typedef typename iterator_traits::reference reference; + + typedef Iterator iterator_type; + typedef reverse_iterator self; + +public: + // 构造函数 + reverse_iterator() {} + explicit reverse_iterator(iterator_type i) :current(i) {} + reverse_iterator(const self& rhs) :current(rhs.current) {} + +public: + // 取出对应的正向迭代器 + iterator_type base() const + { return current; } + + // 重载操作符 + reference operator*() const + { // 实际对应正向迭代器的前一个位置 + auto tmp = current; + return *--tmp; + } + pointer operator->() const + { + return &(operator*()); + } + + // 前进(++)变为后退(--) + self& operator++() + { + --current; + return *this; + } + self operator++(int) + { + self tmp = *this; + --current; + return tmp; + } + // 后退(--)变为前进(++) + self& operator--() + { + ++current; + return *this; + } + self operator--(int) + { + self tmp = *this; + ++current; + return tmp; + } + + self& operator+=(difference_type n) + { + current -= n; + return *this; + } + self operator+(difference_type n) const + { + return self(current - n); + } + self& operator-=(difference_type n) + { + current += n; + return *this; + } + self operator-(difference_type n) const + { + return self(current + n); + } + + reference operator[](difference_type n) const + { + return *(*this + n); + } +}; + +// 重载 operator- +template +typename reverse_iterator::difference_type +operator-(const reverse_iterator& lhs, + const reverse_iterator& rhs) +{ + return rhs.base() - lhs.base(); +} + +// 重载比较操作符 +template +bool operator==(const reverse_iterator& lhs, + const reverse_iterator& rhs) +{ + return lhs.base() == rhs.base(); +} + +template +bool operator<(const reverse_iterator& lhs, + const reverse_iterator& rhs) +{ + return rhs.base() < lhs.base(); +} + +template +bool operator!=(const reverse_iterator& lhs, + const reverse_iterator& rhs) +{ + return !(lhs == rhs); +} + +template +bool operator>(const reverse_iterator& lhs, + const reverse_iterator& rhs) +{ + return rhs < lhs; +} + +template +bool operator<=(const reverse_iterator& lhs, + const reverse_iterator& rhs) +{ + return !(rhs < lhs); +} + +template +bool operator>=(const reverse_iterator& lhs, + const reverse_iterator& rhs) +{ + return !(lhs < rhs); +} + +} // namespace mystl + +#endif // !MYTINYSTL_ITERATOR_H_ + diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/list.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/list.h new file mode 100644 index 0000000..e6bfc1c --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/list.h @@ -0,0 +1,1210 @@ +#ifndef MYTINYSTL_LIST_H_ +#define MYTINYSTL_LIST_H_ + +// 这个头文件包含了一个模板类 list +// list : 双向链表 + +// notes: +// +// 异常保证: +// mystl::list 满足基本异常保证,部分函数无异常保证,并对以下等函数做强异常安全保证: +// * emplace_front +// * emplace_back +// * emplace +// * push_front +// * push_back +// * insert + +#include + +#include "iterator.h" +#include "memory.h" +#include "functional.h" +#include "util.h" +#include "exceptdef.h" + +namespace mystl +{ + +template struct list_node_base; +template struct list_node; + +template +struct node_traits +{ + typedef list_node_base* base_ptr; + typedef list_node* node_ptr; +}; + +// list 的节点结构 + +template +struct list_node_base +{ + typedef typename node_traits::base_ptr base_ptr; + typedef typename node_traits::node_ptr node_ptr; + + base_ptr prev; // 前一节点 + base_ptr next; // 下一节点 + + list_node_base() = default; + + node_ptr as_node() + { + return static_cast(self()); + } + + void unlink() + { + prev = next = self(); + } + + base_ptr self() + { + return static_cast(&*this); + } +}; + +template +struct list_node : public list_node_base +{ + typedef typename node_traits::base_ptr base_ptr; + typedef typename node_traits::node_ptr node_ptr; + + T value; // 数据域 + + list_node() = default; + list_node(const T& v) + :value(v) + { + } + list_node(T&& v) + :value(mystl::move(v)) + { + } + + base_ptr as_base() + { + return static_cast(&*this); + } + node_ptr self() + { + return static_cast(&*this); + } +}; + +// list 的迭代器设计 +template +struct list_iterator : public mystl::iterator +{ + typedef T value_type; + typedef T* pointer; + typedef T& reference; + typedef typename node_traits::base_ptr base_ptr; + typedef typename node_traits::node_ptr node_ptr; + typedef list_iterator self; + + base_ptr node_; // 指向当前节点 + + // 构造函数 + list_iterator() = default; + list_iterator(base_ptr x) + :node_(x) {} + list_iterator(node_ptr x) + :node_(x->as_base()) {} + list_iterator(const list_iterator& rhs) + :node_(rhs.node_) {} + + // 重载操作符 + reference operator*() const { return node_->as_node()->value; } + pointer operator->() const { return &(operator*()); } + + self& operator++() + { + MYSTL_DEBUG(node_ != nullptr); + node_ = node_->next; + return *this; + } + self operator++(int) + { + self tmp = *this; + ++*this; + return tmp; + } + self& operator--() + { + MYSTL_DEBUG(node_ != nullptr); + node_ = node_->prev; + return *this; + } + self operator--(int) + { + self tmp = *this; + --*this; + return tmp; + } + + // 重载比较操作符 + bool operator==(const self& rhs) const { return node_ == rhs.node_; } + bool operator!=(const self& rhs) const { return node_ != rhs.node_; } +}; + +template +struct list_const_iterator : public iterator +{ + typedef T value_type; + typedef const T* pointer; + typedef const T& reference; + typedef typename node_traits::base_ptr base_ptr; + typedef typename node_traits::node_ptr node_ptr; + typedef list_const_iterator self; + + base_ptr node_; + + list_const_iterator() = default; + list_const_iterator(base_ptr x) + :node_(x) {} + list_const_iterator(node_ptr x) + :node_(x->as_base()) {} + list_const_iterator(const list_iterator& rhs) + :node_(rhs.node_) {} + list_const_iterator(const list_const_iterator& rhs) + :node_(rhs.node_) {} + + reference operator*() const { return node_->as_node()->value; } + pointer operator->() const { return &(operator*()); } + + self& operator++() + { + MYSTL_DEBUG(node_ != nullptr); + node_ = node_->next; + return *this; + } + self operator++(int) + { + self tmp = *this; + ++*this; + return tmp; + } + self& operator--() + { + MYSTL_DEBUG(node_ != nullptr); + node_ = node_->prev; + return *this; + } + self operator--(int) + { + self tmp = *this; + --*this; + return tmp; + } + + // 重载比较操作符 + bool operator==(const self& rhs) const { return node_ == rhs.node_; } + bool operator!=(const self& rhs) const { return node_ != rhs.node_; } +}; + +// 模板类: list +// 模板参数 T 代表数据类型 +template +class list +{ +public: + // list 的嵌套型别定义 + typedef mystl::allocator allocator_type; + typedef mystl::allocator data_allocator; + typedef mystl::allocator> base_allocator; + typedef mystl::allocator> node_allocator; + + typedef typename allocator_type::value_type value_type; + typedef typename allocator_type::pointer pointer; + typedef typename allocator_type::const_pointer const_pointer; + typedef typename allocator_type::reference reference; + typedef typename allocator_type::const_reference const_reference; + typedef typename allocator_type::size_type size_type; + typedef typename allocator_type::difference_type difference_type; + + typedef list_iterator iterator; + typedef list_const_iterator const_iterator; + typedef mystl::reverse_iterator reverse_iterator; + typedef mystl::reverse_iterator const_reverse_iterator; + + typedef typename node_traits::base_ptr base_ptr; + typedef typename node_traits::node_ptr node_ptr; + + allocator_type get_allocator() { return node_allocator(); } + +private: + base_ptr node_; // 指向末尾节点 + size_type size_; // 大小 + +public: + // 构造、复制、移动、析构函数 + list() + { fill_init(0, value_type()); } + + explicit list(size_type n) + { fill_init(n, value_type()); } + + list(size_type n, const T& value) + { fill_init(n, value); } + + template ::value, int>::type = 0> + list(Iter first, Iter last) + { copy_init(first, last); } + + list(std::initializer_list ilist) + { copy_init(ilist.begin(), ilist.end()); } + + list(const list& rhs) + { copy_init(rhs.cbegin(), rhs.cend()); } + + list(list&& rhs) noexcept + :node_(rhs.node_), size_(rhs.size_) + { + rhs.node_ = nullptr; + rhs.size_ = 0; + } + + list& operator=(const list& rhs) + { + if (this != &rhs) + { + assign(rhs.begin(), rhs.end()); + } + return *this; + } + + list& operator=(list&& rhs) noexcept + { + clear(); + splice(end(), rhs); + return *this; + } + + list& operator=(std::initializer_list ilist) + { + list tmp(ilist.begin(), ilist.end()); + swap(tmp); + return *this; + } + + ~list() + { + if (node_) + { + clear(); + base_allocator::deallocate(node_); + node_ = nullptr; + size_ = 0; + } + } + +public: + // 迭代器相关操作 + iterator begin() noexcept + { return node_->next; } + const_iterator begin() const noexcept + { return node_->next; } + iterator end() noexcept + { return node_; } + const_iterator end() const noexcept + { return node_; } + + reverse_iterator rbegin() noexcept + { return reverse_iterator(end()); } + const_reverse_iterator rbegin() const noexcept + { return reverse_iterator(end()); } + reverse_iterator rend() noexcept + { return reverse_iterator(begin()); } + const_reverse_iterator rend() const noexcept + { return reverse_iterator(begin()); } + + const_iterator cbegin() const noexcept + { return begin(); } + const_iterator cend() const noexcept + { return end(); } + const_reverse_iterator crbegin() const noexcept + { return rbegin(); } + const_reverse_iterator crend() const noexcept + { return rend(); } + + // 容量相关操作 + bool empty() const noexcept + { return node_->next == node_; } + + size_type size() const noexcept + { return size_; } + + size_type max_size() const noexcept + { return static_cast(-1); } + + // 访问元素相关操作 + reference front() + { + MYSTL_DEBUG(!empty()); + return *begin(); + } + + const_reference front() const + { + MYSTL_DEBUG(!empty()); + return *begin(); + } + + reference back() + { + MYSTL_DEBUG(!empty()); + return *(--end()); + } + + const_reference back() const + { + MYSTL_DEBUG(!empty()); + return *(--end()); + } + + // 调整容器相关操作 + + // assign + + void assign(size_type n, const value_type& value) + { fill_assign(n, value); } + + template ::value, int>::type = 0> + void assign(Iter first, Iter last) + { copy_assign(first, last); } + + void assign(std::initializer_list ilist) + { copy_assign(ilist.begin(), ilist.end()); } + + // emplace_front / emplace_back / emplace + + template + void emplace_front(Args&& ...args) + { + THROW_LENGTH_ERROR_IF(size_ > max_size() - 1, "list's size too big"); + auto link_node = create_node(mystl::forward(args)...); + link_nodes_at_front(link_node->as_base(), link_node->as_base()); + ++size_; + } + + template + void emplace_back(Args&& ...args) + { + THROW_LENGTH_ERROR_IF(size_ > max_size() - 1, "list's size too big"); + auto link_node = create_node(mystl::forward(args)...); + link_nodes_at_back(link_node->as_base(), link_node->as_base()); + ++size_; + } + + template + iterator emplace(const_iterator pos, Args&& ...args) + { + THROW_LENGTH_ERROR_IF(size_ > max_size() - 1, "list's size too big"); + auto link_node = create_node(mystl::forward(args)...); + link_nodes(pos.node_, link_node->as_base(), link_node->as_base()); + ++size_; + return iterator(link_node); + } + + // insert + + iterator insert(const_iterator pos, const value_type& value) + { + THROW_LENGTH_ERROR_IF(size_ > max_size() - 1, "list's size too big"); + auto link_node = create_node(value); + ++size_; + return link_iter_node(pos, link_node->as_base()); + } + + iterator insert(const_iterator pos, value_type&& value) + { + THROW_LENGTH_ERROR_IF(size_ > max_size() - 1, "list's size too big"); + auto link_node = create_node(mystl::move(value)); + ++size_; + return link_iter_node(pos, link_node->as_base()); + } + + iterator insert(const_iterator pos, size_type n, const value_type& value) + { + THROW_LENGTH_ERROR_IF(size_ > max_size() - n, "list's size too big"); + return fill_insert(pos, n, value); + } + + template ::value, int>::type = 0> + iterator insert(const_iterator pos, Iter first, Iter last) + { + size_type n = mystl::distance(first, last); + THROW_LENGTH_ERROR_IF(size_ > max_size() - n, "list's size too big"); + return copy_insert(pos, n, first); + } + + // push_front / push_back + + void push_front(const value_type& value) + { + THROW_LENGTH_ERROR_IF(size_ > max_size() - 1, "list's size too big"); + auto link_node = create_node(value); + link_nodes_at_front(link_node->as_base(), link_node->as_base()); + ++size_; + } + + void push_front(value_type&& value) + { + emplace_front(mystl::move(value)); + } + + void push_back(const value_type& value) + { + THROW_LENGTH_ERROR_IF(size_ > max_size() - 1, "list's size too big"); + auto link_node = create_node(value); + link_nodes_at_back(link_node->as_base(), link_node->as_base()); + ++size_; + } + + void push_back(value_type&& value) + { + emplace_back(mystl::move(value)); + } + + // pop_front / pop_back + + void pop_front() + { + MYSTL_DEBUG(!empty()); + auto n = node_->next; + unlink_nodes(n, n); + destroy_node(n->as_node()); + --size_; + } + + void pop_back() + { + MYSTL_DEBUG(!empty()); + auto n = node_->prev; + unlink_nodes(n, n); + destroy_node(n->as_node()); + --size_; + } + + // erase / clear + + iterator erase(const_iterator pos); + iterator erase(const_iterator first, const_iterator last); + + void clear(); + + // resize + + void resize(size_type new_size) { resize(new_size, value_type()); } + void resize(size_type new_size, const value_type& value); + + void swap(list& rhs) noexcept + { + mystl::swap(node_, rhs.node_); + mystl::swap(size_, rhs.size_); + } + + // list 相关操作 + + void splice(const_iterator pos, list& other); + void splice(const_iterator pos, list& other, const_iterator it); + void splice(const_iterator pos, list& other, const_iterator first, const_iterator last); + + void remove(const value_type& value) + { remove_if([&](const value_type& v) {return v == value; }); } + template + void remove_if(UnaryPredicate pred); + + void unique() + { unique(mystl::equal_to()); } + template + void unique(BinaryPredicate pred); + + void merge(list& x) + { merge(x, mystl::less()); } + template + void merge(list& x, Compare comp); + + void sort() + { list_sort(begin(), end(), size(), mystl::less()); } + template + void sort(Compared comp) + { list_sort(begin(), end(), size(), comp); } + + void reverse(); + +private: + // helper functions + + // create / destroy node + template + node_ptr create_node(Args&& ...agrs); + void destroy_node(node_ptr p); + + // initialize + void fill_init(size_type n, const value_type& value); + template + void copy_init(Iter first, Iter last); + + // link / unlink + iterator link_iter_node(const_iterator pos, base_ptr node); + void link_nodes(base_ptr p, base_ptr first, base_ptr last); + void link_nodes_at_front(base_ptr first, base_ptr last); + void link_nodes_at_back(base_ptr first, base_ptr last); + void unlink_nodes(base_ptr f, base_ptr l); + + // assign + void fill_assign(size_type n, const value_type& value); + template + void copy_assign(Iter first, Iter last); + + // insert + iterator fill_insert(const_iterator pos, size_type n, const value_type& value); + template + iterator copy_insert(const_iterator pos, size_type n, Iter first); + + // sort + template + iterator list_sort(iterator first, iterator last, size_type n, Compared comp); + +}; + +/*****************************************************************************************/ + +// 删除 pos 处的元素 +template +typename list::iterator +list::erase(const_iterator pos) +{ + MYSTL_DEBUG(pos != cend()); + auto n = pos.node_; + auto next = n->next; + unlink_nodes(n, n); + destroy_node(n->as_node()); + --size_; + return iterator(next); +} + +// 删除 [first, last) 内的元素 +template +typename list::iterator +list::erase(const_iterator first, const_iterator last) +{ + if (first != last) + { + unlink_nodes(first.node_, last.node_->prev); + while (first != last) + { + auto cur = first.node_; + ++first; + destroy_node(cur->as_node()); + --size_; + } + } + return iterator(last.node_); +} + +// 清空 list +template +void list::clear() +{ + if (size_ != 0) + { + auto cur = node_->next; + for (base_ptr next = cur->next; cur != node_; cur = next, next = cur->next) + { + destroy_node(cur->as_node()); + } + node_->unlink(); + size_ = 0; + } +} + +// 重置容器大小 +template +void list::resize(size_type new_size, const value_type& value) +{ + auto i = begin(); + size_type len = 0; + while (i != end() && len < new_size) + { + ++i; + ++len; + } + if (len == new_size) + { + erase(i, node_); + } + else + { + insert(node_, new_size - len, value); + } +} + +// 将 list x 接合于 pos 之前 +template +void list::splice(const_iterator pos, list& x) +{ + MYSTL_DEBUG(this != &x); + if (!x.empty()) + { + THROW_LENGTH_ERROR_IF(size_ > max_size() - x.size_, "list's size too big"); + + auto f = x.node_->next; + auto l = x.node_->prev; + + x.unlink_nodes(f, l); + link_nodes(pos.node_, f, l); + + size_ += x.size_; + x.size_ = 0; + } +} + +// 将 it 所指的节点接合于 pos 之前 +template +void list::splice(const_iterator pos, list& x, const_iterator it) +{ + if (pos.node_ != it.node_ && pos.node_ != it.node_->next) + { + THROW_LENGTH_ERROR_IF(size_ > max_size() - 1, "list's size too big"); + + auto f = it.node_; + + x.unlink_nodes(f, f); + link_nodes(pos.node_, f, f); + + ++size_; + --x.size_; + } +} + +// 将 list x 的 [first, last) 内的节点接合于 pos 之前 +template +void list::splice(const_iterator pos, list& x, const_iterator first, const_iterator last) +{ + if (first != last && this != &x) + { + size_type n = mystl::distance(first, last); + THROW_LENGTH_ERROR_IF(size_ > max_size() - n, "list's size too big"); + auto f = first.node_; + auto l = last.node_->prev; + + x.unlink_nodes(f, l); + link_nodes(pos.node_, f, l); + + size_ += n; + x.size_ -= n; + } +} + +// 将另一元操作 pred 为 true 的所有元素移除 +template +template +void list::remove_if(UnaryPredicate pred) +{ + auto f = begin(); + auto l = end(); + for (auto next = f; f != l; f = next) + { + ++next; + if (pred(*f)) + { + erase(f); + } + } +} + +// 移除 list 中满足 pred 为 true 重复元素 +template +template +void list::unique(BinaryPredicate pred) +{ + auto i = begin(); + auto e = end(); + auto j = i; + ++j; + while (j != e) + { + if (pred(*i, *j)) + { + erase(j); + } + else + { + i = j; + } + j = i; + ++j; + } +} + +// 与另一个 list 合并,按照 comp 为 true 的顺序 +template +template +void list::merge(list& x, Compare comp) +{ + if (this != &x) + { + THROW_LENGTH_ERROR_IF(size_ > max_size() - x.size_, "list's size too big"); + + auto f1 = begin(); + auto l1 = end(); + auto f2 = x.begin(); + auto l2 = x.end(); + + while (f1 != l1 && f2 != l2) + { + if (comp(*f2, *f1)) + { + // 使 comp 为 true 的一段区间 + auto next = f2; + ++next; + for (; next != l2 && comp(*next, *f1); ++next) + ; + auto f = f2.node_; + auto l = next.node_->prev; + f2 = next; + + // link node + x.unlink_nodes(f, l); + link_nodes(f1.node_, f, l); + ++f1; + } + else + { + ++f1; + } + } + // 连接剩余部分 + if (f2 != l2) + { + auto f = f2.node_; + auto l = l2.node_->prev; + x.unlink_nodes(f, l); + link_nodes(l1.node_, f, l); + } + + size_ += x.size_; + x.size_ = 0; + } +} + +// 将 list 反转 +template +void list::reverse() +{ + if (size_ <= 1) + { + return; + } + auto i = begin(); + auto e = end(); + while (i.node_ != e.node_) + { + mystl::swap(i.node_->prev, i.node_->next); + i.node_ = i.node_->prev; + } + mystl::swap(e.node_->prev, e.node_->next); +} + +/*****************************************************************************************/ +// helper function + +// 创建结点 +template +template +typename list::node_ptr +list::create_node(Args&& ...args) +{ + node_ptr p = node_allocator::allocate(1); + try + { + data_allocator::construct(mystl::address_of(p->value), mystl::forward(args)...); + p->prev = nullptr; + p->next = nullptr; + } + catch (...) + { + node_allocator::deallocate(p); + throw; + } + return p; +} + +// 销毁结点 +template +void list::destroy_node(node_ptr p) +{ + data_allocator::destroy(mystl::address_of(p->value)); + node_allocator::deallocate(p); +} + +// 用 n 个元素初始化容器 +template +void list::fill_init(size_type n, const value_type& value) +{ + node_ = base_allocator::allocate(1); + node_->unlink(); + size_ = n; + try + { + for (; n > 0; --n) + { + auto node = create_node(value); + link_nodes_at_back(node->as_base(), node->as_base()); + } + } + catch (...) + { + clear(); + base_allocator::deallocate(node_); + node_ = nullptr; + throw; + } +} + +// 以 [first, last) 初始化容器 +template +template +void list::copy_init(Iter first, Iter last) +{ + node_ = base_allocator::allocate(1); + node_->unlink(); + size_type n = mystl::distance(first, last); + size_ = n; + try + { + for (; n > 0; --n, ++first) + { + auto node = create_node(*first); + link_nodes_at_back(node->as_base(), node->as_base()); + } + } + catch (...) + { + clear(); + base_allocator::deallocate(node_); + node_ = nullptr; + throw; + } +} + +// 在 pos 处连接一个节点 +template +typename list::iterator +list::link_iter_node(const_iterator pos, base_ptr link_node) +{ + if (pos == node_->next) + { + link_nodes_at_front(link_node, link_node); + } + else if (pos == node_) + { + link_nodes_at_back(link_node, link_node); + } + else + { + link_nodes(pos.node_, link_node, link_node); + } + return iterator(link_node); +} + +// 在 pos 处连接 [first, last] 的结点 +template +void list::link_nodes(base_ptr pos, base_ptr first, base_ptr last) +{ + pos->prev->next = first; + first->prev = pos->prev; + pos->prev = last; + last->next = pos; +} + +// 在头部连接 [first, last] 结点 +template +void list::link_nodes_at_front(base_ptr first, base_ptr last) +{ + first->prev = node_; + last->next = node_->next; + last->next->prev = last; + node_->next = first; +} + +// 在尾部连接 [first, last] 结点 +template +void list::link_nodes_at_back(base_ptr first, base_ptr last) +{ + last->next = node_; + first->prev = node_->prev; + first->prev->next = first; + node_->prev = last; +} + +// 容器与 [first, last] 结点断开连接 +template +void list::unlink_nodes(base_ptr first, base_ptr last) +{ + first->prev->next = last->next; + last->next->prev = first->prev; +} + +// 用 n 个元素为容器赋值 +template +void list::fill_assign(size_type n, const value_type& value) +{ + auto i = begin(); + auto e = end(); + for (; n > 0 && i != e; --n, ++i) + { + *i = value; + } + if (n > 0) + { + insert(e, n, value); + } + else + { + erase(i, e); + } +} + +// 复制[f2, l2)为容器赋值 +template +template +void list::copy_assign(Iter f2, Iter l2) +{ + auto f1 = begin(); + auto l1 = end(); + for (; f1 != l1 && f2 != l2; ++f1, ++f2) + { + *f1 = *f2; + } + if (f2 == l2) + { + erase(f1, l1); + } + else + { + insert(l1, f2, l2); + } +} + +// 在 pos 处插入 n 个元素 +template +typename list::iterator +list::fill_insert(const_iterator pos, size_type n, const value_type& value) +{ + iterator r(pos.node_); + if (n != 0) + { + const auto add_size = n; + auto node = create_node(value); + node->prev = nullptr; + r = iterator(node); + iterator end = r; + try + { + // 前面已经创建了一个节点,还需 n - 1 个 + for (--n; n > 0; --n, ++end) + { + auto next = create_node(value); + end.node_->next = next->as_base(); // link node + next->prev = end.node_; + } + size_ += add_size; + } + catch (...) + { + auto enode = end.node_; + while (true) + { + auto prev = enode->prev; + destroy_node(enode->as_node()); + if (prev == nullptr) + break; + enode = prev; + } + throw; + } + link_nodes(pos.node_, r.node_, end.node_); + } + return r; +} + +// 在 pos 处插入 [first, last) 的元素 +template +template +typename list::iterator +list::copy_insert(const_iterator pos, size_type n, Iter first) +{ + iterator r(pos.node_); + if (n != 0) + { + const auto add_size = n; + auto node = create_node(*first); + node->prev = nullptr; + r = iterator(node); + iterator end = r; + try + { + for (--n, ++first; n > 0; --n, ++first, ++end) + { + auto next = create_node(*first); + end.node_->next = next->as_base(); // link node + next->prev = end.node_; + } + size_ += add_size; + } + catch (...) + { + auto enode = end.node_; + while (true) + { + auto prev = enode->prev; + destroy_node(enode->as_node()); + if (prev == nullptr) + break; + enode = prev; + } + throw; + } + link_nodes(pos.node_, r.node_, end.node_); + } + return r; +} + +// 对 list 进行归并排序,返回一个迭代器指向区间最小元素的位置 +template +template +typename list::iterator +list::list_sort(iterator f1, iterator l2, size_type n, Compared comp) +{ + if (n < 2) + return f1; + + if (n == 2) + { + if (comp(*--l2, *f1)) + { + auto ln = l2.node_; + unlink_nodes(ln, ln); + link_nodes(f1.node_, ln, ln); + return l2; + } + return f1; + } + + auto n2 = n / 2; + auto l1 = f1; + mystl::advance(l1, n2); + auto result = f1 = list_sort(f1, l1, n2, comp); // 前半段的最小位置 + auto f2 = l1 = list_sort(l1, l2, n - n2, comp); // 后半段的最小位置 + + // 把较小的一段区间移到前面 + if (comp(*f2, *f1)) + { + auto m = f2; + ++m; + for (; m != l2 && comp(*m, *f1); ++m) + ; + auto f = f2.node_; + auto l = m.node_->prev; + result = f2; + l1 = f2 = m; + unlink_nodes(f, l); + m = f1; + ++m; + link_nodes(f1.node_, f, l); + f1 = m; + } + else + { + ++f1; + } + + // 合并两段有序区间 + while (f1 != l1 && f2 != l2) + { + if (comp(*f2, *f1)) + { + auto m = f2; + ++m; + for (; m != l2 && comp(*m, *f1); ++m) + ; + auto f = f2.node_; + auto l = m.node_->prev; + if (l1 == f2) + l1 = m; + f2 = m; + unlink_nodes(f, l); + m = f1; + ++m; + link_nodes(f1.node_, f, l); + f1 = m; + } + else + { + ++f1; + } + } + return result; +} + +// 重载比较操作符 +template +bool operator==(const list& lhs, const list& rhs) +{ + auto f1 = lhs.cbegin(); + auto f2 = rhs.cbegin(); + auto l1 = lhs.cend(); + auto l2 = rhs.cend(); + for (; f1 != l1 && f2 != l2 && *f1 == *f2; ++f1, ++f2) + ; + return f1 == l1 && f2 == l2; +} + +template +bool operator<(const list& lhs, const list& rhs) +{ + return mystl::lexicographical_compare(lhs.cbegin(), lhs.cend(), rhs.cbegin(), rhs.cend()); +} + +template +bool operator!=(const list& lhs, const list& rhs) +{ + return !(lhs == rhs); +} + +template +bool operator>(const list& lhs, const list& rhs) +{ + return rhs < lhs; +} + +template +bool operator<=(const list& lhs, const list& rhs) +{ + return !(rhs < lhs); +} + +template +bool operator>=(const list& lhs, const list& rhs) +{ + return !(lhs < rhs); +} + +// 重载 mystl 的 swap +template +void swap(list& lhs, list& rhs) noexcept +{ + lhs.swap(rhs); +} + +} // namespace mystl +#endif // !MYTINYSTL_LIST_H_ + diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/map.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/map.h new file mode 100644 index 0000000..da61c59 --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/map.h @@ -0,0 +1,549 @@ +#ifndef MYTINYSTL_MAP_H_ +#define MYTINYSTL_MAP_H_ + +// 这个头文件包含了两个模板类 map 和 multimap +// map : 映射,元素具有键值和实值,会根据键值大小自动排序,键值不允许重复 +// multimap : 映射,元素具有键值和实值,会根据键值大小自动排序,键值允许重复 + +// notes: +// +// 异常保证: +// mystl::map / mystl::multimap 满足基本异常保证,对以下等函数做强异常安全保证: +// * emplace +// * emplace_hint +// * insert + +#include "rb_tree.h" + +namespace mystl +{ + +// 模板类 map,键值不允许重复 +// 参数一代表键值类型,参数二代表实值类型,参数三代表键值的比较方式,缺省使用 mystl::less +template > +class map +{ +public: + // map 的嵌套型别定义 + typedef Key key_type; + typedef T mapped_type; + typedef mystl::pair value_type; + typedef Compare key_compare; + + // 定义一个 functor,用来进行元素比较 + class value_compare : public binary_function + { + friend class map; + private: + Compare comp; + value_compare(Compare c) : comp(c) {} + public: + bool operator()(const value_type& lhs, const value_type& rhs) const + { + return comp(lhs.first, rhs.first); // 比较键值的大小 + } + }; + +private: + // 以 mystl::rb_tree 作为底层机制 + typedef mystl::rb_tree base_type; + base_type tree_; + +public: + // 使用 rb_tree 的型别 + typedef typename base_type::node_type node_type; + typedef typename base_type::pointer pointer; + typedef typename base_type::const_pointer const_pointer; + typedef typename base_type::reference reference; + typedef typename base_type::const_reference const_reference; + typedef typename base_type::iterator iterator; + typedef typename base_type::const_iterator const_iterator; + typedef typename base_type::reverse_iterator reverse_iterator; + typedef typename base_type::const_reverse_iterator const_reverse_iterator; + typedef typename base_type::size_type size_type; + typedef typename base_type::difference_type difference_type; + typedef typename base_type::allocator_type allocator_type; + +public: + // 构造、复制、移动、赋值函数 + + map() = default; + + template + map(InputIterator first, InputIterator last) + :tree_() + { tree_.insert_unique(first, last); } + + map(std::initializer_list ilist) + :tree_() + { tree_.insert_unique(ilist.begin(), ilist.end()); } + + map(const map& rhs) + :tree_(rhs.tree_) + { + } + map(map&& rhs) noexcept + :tree_(mystl::move(rhs.tree_)) + { + } + + map& operator=(const map& rhs) + { + tree_ = rhs.tree_; + return *this; + } + map& operator=(map&& rhs) + { + tree_ = mystl::move(rhs.tree_); + return *this; + } + + map& operator=(std::initializer_list ilist) + { + tree_.clear(); + tree_.insert_unique(ilist.begin(), ilist.end()); + return *this; + } + + // 相关接口 + + key_compare key_comp() const { return tree_.key_comp(); } + value_compare value_comp() const { return value_compare(tree_.key_comp()); } + allocator_type get_allocator() const { return tree_.get_allocator(); } + + // 迭代器相关 + + iterator begin() noexcept + { return tree_.begin(); } + const_iterator begin() const noexcept + { return tree_.begin(); } + iterator end() noexcept + { return tree_.end(); } + const_iterator end() const noexcept + { return tree_.end(); } + + reverse_iterator rbegin() noexcept + { return reverse_iterator(end()); } + const_reverse_iterator rbegin() const noexcept + { return const_reverse_iterator(end()); } + reverse_iterator rend() noexcept + { return reverse_iterator(begin()); } + const_reverse_iterator rend() const noexcept + { return const_reverse_iterator(begin()); } + + const_iterator cbegin() const noexcept + { return begin(); } + const_iterator cend() const noexcept + { return end(); } + const_reverse_iterator crbegin() const noexcept + { return rbegin(); } + const_reverse_iterator crend() const noexcept + { return rend(); } + + // 容量相关 + bool empty() const noexcept { return tree_.empty(); } + size_type size() const noexcept { return tree_.size(); } + size_type max_size() const noexcept { return tree_.max_size(); } + + // 访问元素相关 + + // 若键值不存在,at 会抛出一个异常 + mapped_type& at(const key_type& key) + { + iterator it = lower_bound(key); + // it->first >= key + THROW_OUT_OF_RANGE_IF(it == end() || key_comp()(it->first, key), + "map no such element exists"); + return it->second; + } + const mapped_type& at(const key_type& key) const + { + const_iterator it = lower_bound(key); + // it->first >= key + THROW_OUT_OF_RANGE_IF(it == end() || key_comp()(it->first, key), + "map no such element exists"); + return it->second; + } + + mapped_type& operator[](const key_type& key) + { + iterator it = lower_bound(key); + // it->first >= key + if (it == end() || key_comp()(key, it->first)) + it = emplace_hint(it, key, T{}); + return it->second; + } + mapped_type& operator[](key_type&& key) + { + iterator it = lower_bound(key); + // it->first >= key + if (it == end() || key_comp()(key, it->first)) + it = emplace_hint(it, mystl::move(key), T{}); + return it->second; + } + + // 插入删除相关 + + template + pair emplace(Args&& ...args) + { + return tree_.emplace_unique(mystl::forward(args)...); + } + + template + iterator emplace_hint(iterator hint, Args&& ...args) + { + return tree_.emplace_unique_use_hint(hint, mystl::forward(args)...); + } + + pair insert(const value_type& value) + { + return tree_.insert_unique(value); + } + pair insert(value_type&& value) + { + return tree_.insert_unique(mystl::move(value)); + } + + iterator insert(iterator hint, const value_type& value) + { + return tree_.insert_unique(hint, value); + } + iterator insert(iterator hint, value_type&& value) + { + return tree_.insert_unique(hint, mystl::move(value)); + } + + template + void insert(InputIterator first, InputIterator last) + { + tree_.insert_unique(first, last); + } + + void erase(iterator position) { tree_.erase(position); } + size_type erase(const key_type& key) { return tree_.erase_unique(key); } + void erase(iterator first, iterator last) { tree_.erase(first, last); } + + void clear() { tree_.clear(); } + + // map 相关操作 + + iterator find(const key_type& key) { return tree_.find(key); } + const_iterator find(const key_type& key) const { return tree_.find(key); } + + size_type count(const key_type& key) const { return tree_.count_unique(key); } + + iterator lower_bound(const key_type& key) { return tree_.lower_bound(key); } + const_iterator lower_bound(const key_type& key) const { return tree_.lower_bound(key); } + + iterator upper_bound(const key_type& key) { return tree_.upper_bound(key); } + const_iterator upper_bound(const key_type& key) const { return tree_.upper_bound(key); } + + pair + equal_range(const key_type& key) + { return tree_.equal_range_unique(key); } + + pair + equal_range(const key_type& key) const + { return tree_.equal_range_unique(key); } + + void swap(map& rhs) noexcept + { tree_.swap(rhs.tree_); } + +public: + friend bool operator==(const map& lhs, const map& rhs) { return lhs.tree_ == rhs.tree_; } + friend bool operator< (const map& lhs, const map& rhs) { return lhs.tree_ < rhs.tree_; } +}; + +// 重载比较操作符 +template +bool operator==(const map& lhs, const map& rhs) +{ + return lhs == rhs; +} + +template +bool operator<(const map& lhs, const map& rhs) +{ + return lhs < rhs; +} + +template +bool operator!=(const map& lhs, const map& rhs) +{ + return !(lhs == rhs); +} + +template +bool operator>(const map& lhs, const map& rhs) +{ + return rhs < lhs; +} + +template +bool operator<=(const map& lhs, const map& rhs) +{ + return !(rhs < lhs); +} + +template +bool operator>=(const map& lhs, const map& rhs) +{ + return !(lhs < rhs); +} + +// 重载 mystl 的 swap +template +void swap(map& lhs, map& rhs) noexcept +{ + lhs.swap(rhs); +} + +/*****************************************************************************************/ + +// 模板类 multimap,键值允许重复 +// 参数一代表键值类型,参数二代表实值类型,参数三代表键值的比较方式,缺省使用 mystl::less +template > +class multimap +{ +public: + // multimap 的型别定义 + typedef Key key_type; + typedef T mapped_type; + typedef mystl::pair value_type; + typedef Compare key_compare; + + // 定义一个 functor,用来进行元素比较 + class value_compare : public binary_function + { + friend class multimap; + private: + Compare comp; + value_compare(Compare c) : comp(c) {} + public: + bool operator()(const value_type& lhs, const value_type& rhs) const + { + return comp(lhs.first, rhs.first); + } + }; + +private: + // 用 mystl::rb_tree 作为底层机制 + typedef mystl::rb_tree base_type; + base_type tree_; + +public: + // 使用 rb_tree 的型别 + typedef typename base_type::node_type node_type; + typedef typename base_type::pointer pointer; + typedef typename base_type::const_pointer const_pointer; + typedef typename base_type::reference reference; + typedef typename base_type::const_reference const_reference; + typedef typename base_type::iterator iterator; + typedef typename base_type::const_iterator const_iterator; + typedef typename base_type::reverse_iterator reverse_iterator; + typedef typename base_type::const_reverse_iterator const_reverse_iterator; + typedef typename base_type::size_type size_type; + typedef typename base_type::difference_type difference_type; + typedef typename base_type::allocator_type allocator_type; + +public: + // 构造、复制、移动函数 + + multimap() = default; + + template + multimap(InputIterator first, InputIterator last) + :tree_() + { tree_.insert_multi(first, last); } + multimap(std::initializer_list ilist) + :tree_() + { tree_.insert_multi(ilist.begin(), ilist.end()); } + + multimap(const multimap& rhs) + :tree_(rhs.tree_) + { + } + multimap(multimap&& rhs) noexcept + :tree_(mystl::move(rhs.tree_)) + { + } + + multimap& operator=(const multimap& rhs) + { + tree_ = rhs.tree_; + return *this; + } + multimap& operator=(multimap&& rhs) + { + tree_ = mystl::move(rhs.tree_); + return *this; + } + + multimap& operator=(std::initializer_list ilist) + { + tree_.clear(); + tree_.insert_multi(ilist.begin(), ilist.end()); + return *this; + } + + // 相关接口 + + key_compare key_comp() const { return tree_.key_comp(); } + value_compare value_comp() const { return value_compare(tree_.key_comp()); } + allocator_type get_allocator() const { return tree_.get_allocator(); } + + // 迭代器相关 + + iterator begin() noexcept + { return tree_.begin(); } + const_iterator begin() const noexcept + { return tree_.begin(); } + iterator end() noexcept + { return tree_.end(); } + const_iterator end() const noexcept + { return tree_.end(); } + + reverse_iterator rbegin() noexcept + { return reverse_iterator(end()); } + const_reverse_iterator rbegin() const noexcept + { return const_reverse_iterator(end()); } + reverse_iterator rend() noexcept + { return reverse_iterator(begin()); } + const_reverse_iterator rend() const noexcept + { return const_reverse_iterator(begin()); } + + const_iterator cbegin() const noexcept + { return begin(); } + const_iterator cend() const noexcept + { return end(); } + const_reverse_iterator crbegin() const noexcept + { return rbegin(); } + const_reverse_iterator crend() const noexcept + { return rend(); } + + // 容量相关 + bool empty() const noexcept { return tree_.empty(); } + size_type size() const noexcept { return tree_.size(); } + size_type max_size() const noexcept { return tree_.max_size(); } + + // 插入删除操作 + + template + iterator emplace(Args&& ...args) + { + return tree_.emplace_multi(mystl::forward(args)...); + } + + template + iterator emplace_hint(iterator hint, Args&& ...args) + { + return tree_.emplace_multi_use_hint(hint, mystl::forward(args)...); + } + + iterator insert(const value_type& value) + { + return tree_.insert_multi(value); + } + iterator insert(value_type&& value) + { + return tree_.insert_multi(mystl::move(value)); + } + + iterator insert(iterator hint, const value_type& value) + { + return tree_.insert_multi(hint, value); + } + iterator insert(iterator hint, value_type&& value) + { + return tree_.insert_multi(hint, mystl::move(value)); + } + + template + void insert(InputIterator first, InputIterator last) + { + tree_.insert_multi(first, last); + } + + void erase(iterator position) { tree_.erase(position); } + size_type erase(const key_type& key) { return tree_.erase_multi(key); } + void erase(iterator first, iterator last) { tree_.erase(first, last); } + + void clear() { tree_.clear(); } + + // multimap 相关操作 + + iterator find(const key_type& key) { return tree_.find(key); } + const_iterator find(const key_type& key) const { return tree_.find(key); } + + size_type count(const key_type& key) const { return tree_.count_multi(key); } + + iterator lower_bound(const key_type& key) { return tree_.lower_bound(key); } + const_iterator lower_bound(const key_type& key) const { return tree_.lower_bound(key); } + + iterator upper_bound(const key_type& key) { return tree_.upper_bound(key); } + const_iterator upper_bound(const key_type& key) const { return tree_.upper_bound(key); } + + pair + equal_range(const key_type& key) + { return tree_.equal_range_multi(key); } + + pair + equal_range(const key_type& key) const + { return tree_.equal_range_multi(key); } + + void swap(multimap& rhs) noexcept + { tree_.swap(rhs.tree_); } + +public: + friend bool operator==(const multimap& lhs, const multimap& rhs) { return lhs.tree_ == rhs.tree_; } + friend bool operator< (const multimap& lhs, const multimap& rhs) { return lhs.tree_ < rhs.tree_; } +}; + +// 重载比较操作符 +template +bool operator==(const multimap& lhs, const multimap& rhs) +{ + return lhs == rhs; +} + +template +bool operator<(const multimap& lhs, const multimap& rhs) +{ + return lhs < rhs; +} + +template +bool operator!=(const multimap& lhs, const multimap& rhs) +{ + return !(lhs == rhs); +} + +template +bool operator>(const multimap& lhs, const multimap& rhs) +{ + return rhs < lhs; +} + +template +bool operator<=(const multimap& lhs, const multimap& rhs) +{ + return !(rhs < lhs); +} + +template +bool operator>=(const multimap& lhs, const multimap& rhs) +{ + return !(lhs < rhs); +} + +// 重载 mystl 的 swap +template +void swap(multimap& lhs, multimap& rhs) noexcept +{ + lhs.swap(rhs); +} + +} // namespace mystl +#endif // !MYTINYSTL_MAP_H_ + diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/memory.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/memory.h new file mode 100644 index 0000000..c24e42c --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/memory.h @@ -0,0 +1,208 @@ +#ifndef MYTINYSTL_MEMORY_H_ +#define MYTINYSTL_MEMORY_H_ + +// 这个头文件负责更高级的动态内存管理 +// 包含一些基本函数、空间配置器、未初始化的储存空间管理,以及一个模板类 auto_ptr + +#include +#include +#include + +#include "algobase.h" +#include "allocator.h" +#include "construct.h" +#include "uninitialized.h" + +namespace mystl +{ + +// 获取对象地址 +template +constexpr Tp* address_of(Tp& value) noexcept +{ + return &value; +} + +// 获取 / 释放 临时缓冲区 + +template +pair get_buffer_helper(ptrdiff_t len, T*) +{ + if (len > static_cast(INT_MAX / sizeof(T))) + len = INT_MAX / sizeof(T); + while (len > 0) + { + T* tmp = static_cast(malloc(static_cast(len) * sizeof(T))); + if (tmp) + return pair(tmp, len); + len /= 2; // 申请失败时减少 len 的大小 + } + return pair(nullptr, 0); +} + +template +pair get_temporary_buffer(ptrdiff_t len) +{ + return get_buffer_helper(len, static_cast(0)); +} + +template +pair get_temporary_buffer(ptrdiff_t len, T*) +{ + return get_buffer_helper(len, static_cast(0)); +} + +template +void release_temporary_buffer(T* ptr) +{ + free(ptr); +} + +// -------------------------------------------------------------------------------------- +// 类模板 : temporary_buffer +// 进行临时缓冲区的申请与释放 +template +class temporary_buffer +{ +private: + ptrdiff_t original_len; // 缓冲区申请的大小 + ptrdiff_t len; // 缓冲区实际的大小 + T* buffer; // 指向缓冲区的指针 + +public: + // 构造、析构函数 + temporary_buffer(ForwardIterator first, ForwardIterator last); + + ~temporary_buffer() + { + mystl::destroy(buffer, buffer + len); + free(buffer); + } + +public: + + ptrdiff_t size() const noexcept { return len; } + ptrdiff_t requested_size() const noexcept { return original_len; } + T* begin() noexcept { return buffer; } + T* end() noexcept { return buffer + len; } + +private: + void allocate_buffer(); + void initialize_buffer(const T&, std::true_type) {} + void initialize_buffer(const T& value, std::false_type) + { mystl::uninitialized_fill_n(buffer, len, value); } + +private: + temporary_buffer(const temporary_buffer&); + void operator=(const temporary_buffer&); +}; + +// 构造函数 +template +temporary_buffer:: +temporary_buffer(ForwardIterator first, ForwardIterator last) +{ + try + { + len = mystl::distance(first, last); + allocate_buffer(); + if (len > 0) + { + initialize_buffer(*first, std::is_trivially_default_constructible()); + } + } + catch (...) + { + free(buffer); + buffer = nullptr; + len = 0; + } +} + +// allocate_buffer 函数 +template +void temporary_buffer::allocate_buffer() +{ + original_len = len; + if (len > static_cast(INT_MAX / sizeof(T))) + len = INT_MAX / sizeof(T); + while (len > 0) + { + buffer = static_cast(malloc(len * sizeof(T))); + if (buffer) + break; + len /= 2; // 申请失败时减少申请空间大小 + } +} + +// -------------------------------------------------------------------------------------- +// 模板类: auto_ptr +// 一个具有严格对象所有权的小型智能指针 +template +class auto_ptr +{ +public: + typedef T elem_type; + +private: + T* m_ptr; // 实际指针 + +public: + // 构造、复制、析构函数 + explicit auto_ptr(T* p = nullptr) :m_ptr(p) {} + auto_ptr(auto_ptr& rhs) :m_ptr(rhs.release()) {} + template + auto_ptr(auto_ptr& rhs) : m_ptr(rhs.release()) {} + + auto_ptr& operator=(auto_ptr& rhs) + { + if (this != &rhs) + { + delete m_ptr; + m_ptr = rhs.release(); + } + return *this; + } + template + auto_ptr& operator=(auto_ptr& rhs) + { + if (this->get() != rhs.get()) + { + delete m_ptr; + m_ptr = rhs.release(); + } + return *this; + } + + ~auto_ptr() { delete m_ptr; } + +public: + // 重载 operator* 和 operator-> + T& operator*() const { return *m_ptr; } + T* operator->() const { return m_ptr; } + + // 获得指针 + T* get() const { return m_ptr; } + + // 释放指针 + T* release() + { + T* tmp = m_ptr; + m_ptr = nullptr; + return tmp; + } + + // 重置指针 + void reset(T* p = nullptr) + { + if (m_ptr != p) + { + delete m_ptr; + m_ptr = p; + } + } +}; + +} // namespace mystl +#endif // !MYTINYSTL_MEMORY_H_ + diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/numeric.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/numeric.h new file mode 100644 index 0000000..8d6cbb6 --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/numeric.h @@ -0,0 +1,155 @@ +#ifndef MYTINYSTL_NUMERIC_H_ +#define MYTINYSTL_NUMERIC_H_ + +// 这个头文件包含了 mystl 的数值算法 + +#include "iterator.h" + +namespace mystl +{ + +/*****************************************************************************************/ +// accumulate +// 版本1:以初值 init 对每个元素进行累加 +// 版本2:以初值 init 对每个元素进行二元操作 +/*****************************************************************************************/ +// 版本1 +template +T accumulate(InputIter first, InputIter last, T init) +{ + for (; first != last; ++first) + { + init += *first; + } + return init; +} + +// 版本2 +template +T accumulate(InputIter first, InputIter last, T init, BinaryOp binary_op) +{ + for (; first != last; ++first) + { + init = binary_op(init, *first); + } + return init; +} + +/*****************************************************************************************/ +// adjacent_difference +// 版本1:计算相邻元素的差值,结果保存到以 result 为起始的区间上 +// 版本2:自定义相邻元素的二元操作 +/*****************************************************************************************/ +// 版本1 +template +OutputIter adjacent_difference(InputIter first, InputIter last, OutputIter result) +{ + if (first == last) return result; + *result = *first; // 记录第一个元素 + auto value = *first; + while (++first != last) + { + auto tmp = *first; + *++result = tmp - value; + value = tmp; + } + return ++result; +} + +// 版本2 +template +OutputIter adjacent_difference(InputIter first, InputIter last, OutputIter result, + BinaryOp binary_op) +{ + if (first == last) return result; + *result = *first; // 记录第一个元素 + auto value = *first; + while (++first != last) + { + auto tmp = *first; + *++result = binary_op(tmp, value); + value = tmp; + } + return ++result; +} + +/*****************************************************************************************/ +// inner_product +// 版本1:以 init 为初值,计算两个区间的内积 +// 版本2:自定义 operator+ 和 operator* +/*****************************************************************************************/ +// 版本1 +template +T inner_product(InputIter1 first1, InputIter1 last1, InputIter2 first2, T init) +{ + for (; first1 != last1; ++first1, ++first2) + { + init = init + (*first1 * *first2); + } + return init; +} + +// 版本2 +template +T inner_product(InputIter1 first1, InputIter1 last1, InputIter2 first2, T init, + BinaryOp1 binary_op1, BinaryOp2 binary_op2) +{ + for (; first1 != last1; ++first1, ++first2) + { + init = binary_op1(init, binary_op2(*first1, *first2)); + } + return init; +} + +/*****************************************************************************************/ +// iota +// 填充[first, last),以 value 为初值开始递增 +/*****************************************************************************************/ +template +void iota(ForwardIter first, ForwardIter last, T value) +{ + while (first != last) + { + *first++ = value; + ++value; + } +} + +/*****************************************************************************************/ +// partial_sum +// 版本1:计算局部累计求和,结果保存到以 result 为起始的区间上 +// 版本2:进行局部进行自定义二元操作 +/*****************************************************************************************/ +template +OutputIter partial_sum(InputIter first, InputIter last, OutputIter result) +{ + if (first == last) return result; + *result = *first; // 记录第一个元素 + auto value = *first; + while (++first != last) + { + value = value + *first; + *++result = value; + } + return ++result; +} + +// 版本2 +template +OutputIter partial_sum(InputIter first, InputIter last, OutputIter result, + BinaryOp binary_op) +{ + if (first == last) return result; + *result = *first; //记录第一个元素 + auto value = *first; + while (++first != last) + { + value = binary_op(value, *first); + *++result = value; + } + return ++result; +} + +} // namespace mystl +#endif // !MYTINYSTL_NUMERIC_H_ + diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/queue.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/queue.h new file mode 100644 index 0000000..6a4a939 --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/queue.h @@ -0,0 +1,364 @@ +#ifndef MYTINYSTL_QUEUE_H_ +#define MYTINYSTL_QUEUE_H_ + +// 这个头文件包含了两个模板类 queue 和 priority_queue +// queue : 队列 +// priority_queue : 优先队列 + +#include "deque.h" +#include "vector.h" +#include "functional.h" +#include "heap_algo.h" + +namespace mystl +{ + +// 模板类 queue +// 参数一代表数据类型,参数二代表底层容器类型,缺省使用 mystl::deque 作为底层容器 +template > +class queue +{ +public: + typedef Container container_type; + // 使用底层容器的型别 + typedef typename Container::value_type value_type; + typedef typename Container::size_type size_type; + typedef typename Container::reference reference; + typedef typename Container::const_reference const_reference; + + static_assert(std::is_same::value, + "the value_type of Container should be same with T"); +private: + container_type c_; // 用底层容器表现 queue + +public: + // 构造、复制、移动函数 + + queue() = default; + + explicit queue(size_type n) + :c_(n) + { + } + queue(size_type n, const value_type& value) + :c_(n, value) + { + } + + template + queue(IIter first, IIter last) + :c_(first, last) + { + } + + queue(std::initializer_list ilist) + :c_(ilist.begin(), ilist.end()) + { + } + + queue(const Container& c) + :c_(c) + { + } + queue(Container&& c) noexcept(std::is_nothrow_move_constructible::value) + :c_(mystl::move(c)) + { + } + + queue(const queue& rhs) + :c_(rhs.c_) + { + } + queue(queue&& rhs) noexcept(std::is_nothrow_move_constructible::value) + :c_(mystl::move(rhs.c_)) + { + } + + queue& operator=(const queue& rhs) + { + c_ = rhs.c_; + return *this; + } + queue& operator=(queue&& rhs) noexcept(std::is_nothrow_move_assignable::value) + { + c_ = mystl::move(rhs.c_); + return *this; + } + + queue& operator=(std::initializer_list ilist) + { + c_ = ilist; + return *this; + } + + ~queue() = default; + + // 访问元素相关操作 + reference front() { return c_.front(); } + const_reference front() const { return c_.front(); } + reference back() { return c_.back(); } + const_reference back() const { return c_.back(); } + + // 容量相关操作 + bool empty() const noexcept { return c_.empty(); } + size_type size() const noexcept { return c_.size(); } + + // 修改容器相关操作 + template + void emplace(Args&& ...args) + { c_.emplace_back(mystl::forward(args)...); } + + void push(const value_type& value) + { c_.push_back(value); } + void push(value_type&& value) + { c_.emplace_back(mystl::move(value)); } + + void pop() + { c_.pop_front(); } + + void clear() + { + while (!empty()) + pop(); + } + + void swap(queue& rhs) noexcept(noexcept(mystl::swap(c_, rhs.c_))) + { mystl::swap(c_, rhs.c_); } + +public: + friend bool operator==(const queue& lhs, const queue& rhs) { return lhs.c_ == rhs.c_; } + friend bool operator< (const queue& lhs, const queue& rhs) { return lhs.c_ < rhs.c_; } +}; + +// 重载比较操作符 +template +bool operator==(const queue& lhs, const queue& rhs) +{ + return lhs == rhs; +} + +template +bool operator!=(const queue& lhs, const queue& rhs) +{ + return !(lhs == rhs); +} + +template +bool operator<(const queue& lhs, const queue& rhs) +{ + return lhs < rhs; +} + +template +bool operator>(const queue& lhs, const queue& rhs) +{ + return rhs < lhs; +} + +template +bool operator<=(const queue& lhs, const queue& rhs) +{ + return !(rhs < lhs); +} + +template +bool operator>=(const queue& lhs, const queue& rhs) +{ + return !(lhs < rhs); +} + +// 重载 mystl 的 swap +template +void swap(queue& lhs, queue& rhs) noexcept(noexcept(lhs.swap(rhs))) +{ + lhs.swap(rhs); +} + +/*****************************************************************************************/ + +// 模板类 priority_queue +// 参数一代表数据类型,参数二代表容器类型,缺省使用 mystl::vector 作为底层容器 +// 参数三代表比较权值的方式,缺省使用 mystl::less 作为比较方式 +template , + class Compare = mystl::less> +class priority_queue +{ +public: + typedef Container container_type; + typedef Compare value_compare; + // 使用底层容器的型别 + typedef typename Container::value_type value_type; + typedef typename Container::size_type size_type; + typedef typename Container::reference reference; + typedef typename Container::const_reference const_reference; + + static_assert(std::is_same::value, + "the value_type of Container should be same with T"); + +private: + container_type c_; // 用底层容器来表现 priority_queue + value_compare comp_; // 权值比较的标准 + +public: + // 构造、复制、移动函数 + priority_queue() = default; + + priority_queue(const Compare& c) + :c_(), comp_(c) + { + } + + explicit priority_queue(size_type n) + :c_(n) + { + mystl::make_heap(c_.begin(), c_.end(), comp_); + } + priority_queue(size_type n, const value_type& value) + :c_(n, value) + { + mystl::make_heap(c_.begin(), c_.end(), comp_); + } + + template + priority_queue(IIter first, IIter last) + :c_(first, last) + { + mystl::make_heap(c_.begin(), c_.end(), comp_); + } + + priority_queue(std::initializer_list ilist) + :c_(ilist) + { + mystl::make_heap(c_.begin(), c_.end(), comp_); + } + + priority_queue(const Container& s) + :c_(s) + { + mystl::make_heap(c_.begin(), c_.end(), comp_); + } + priority_queue(Container&& s) + :c_(mystl::move(s)) + { + mystl::make_heap(c_.begin(), c_.end(), comp_); + } + + priority_queue(const priority_queue& rhs) + :c_(rhs.c_), comp_(rhs.comp_) + { + mystl::make_heap(c_.begin(), c_.end(), comp_); + } + priority_queue(priority_queue&& rhs) + :c_(mystl::move(rhs.c_)), comp_(rhs.comp_) + { + mystl::make_heap(c_.begin(), c_.end(), comp_); + } + + priority_queue& operator=(const priority_queue& rhs) + { + c_ = rhs.c_; + comp_ = rhs.comp_; + mystl::make_heap(c_.begin(), c_.end(), comp_); + return *this; + } + priority_queue& operator=(priority_queue&& rhs) + { + c_ = mystl::move(rhs.c_); + comp_ = rhs.comp_; + mystl::make_heap(c_.begin(), c_.end(), comp_); + return *this; + } + priority_queue& operator=(std::initializer_list ilist) + { + c_ = ilist; + comp_ = value_compare(); + mystl::make_heap(c_.begin(), c_.end(), comp_); + return *this; + } + + ~priority_queue() = default; + +public: + + // 访问元素相关操作 + const_reference top() const { return c_.front(); } + + // 容量相关操作 + bool empty() const noexcept { return c_.empty(); } + size_type size() const noexcept { return c_.size(); } + + // 修改容器相关操作 + template + void emplace(Args&& ...args) + { + c_.emplace_back(mystl::forward(args)...); + mystl::push_heap(c_.begin(), c_.end(), comp_); + } + + void push(const value_type& value) + { + c_.push_back(value); + mystl::push_heap(c_.begin(), c_.end(), comp_); + } + void push(value_type&& value) + { + c_.push_back(mystl::move(value)); + mystl::push_heap(c_.begin(), c_.end(), comp_); + } + + void pop() + { + mystl::pop_heap(c_.begin(), c_.end(), comp_); + c_.pop_back(); + } + + void clear() + { + while (!empty()) + pop(); + } + + void swap(priority_queue& rhs) noexcept(noexcept(mystl::swap(c_, rhs.c_)) && + noexcept(mystl::swap(comp_, rhs.comp_))) + { + mystl::swap(c_, rhs.c_); + mystl::swap(comp_, rhs.comp_); + } + +public: + friend bool operator==(const priority_queue& lhs, const priority_queue& rhs) + { + return lhs.c_ == rhs.c_; + } + friend bool operator!=(const priority_queue& lhs, const priority_queue& rhs) + { + return lhs.c_ != rhs.c_; + } +}; + +// 重载比较操作符 +template +bool operator==(priority_queue& lhs, + priority_queue& rhs) +{ + return lhs == rhs; +} + +template +bool operator!=(priority_queue& lhs, + priority_queue& rhs) +{ + return lhs != rhs; +} + +// 重载 mystl 的 swap +template +void swap(priority_queue& lhs, + priority_queue& rhs) noexcept(noexcept(lhs.swap(rhs))) +{ + lhs.swap(rhs); +} + +} // namespace mystl +#endif // !MYTINYSTL_QUEUE_H_ + diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/rb_tree.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/rb_tree.h new file mode 100644 index 0000000..908e778 --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/rb_tree.h @@ -0,0 +1,1738 @@ +#ifndef MYTINYSTL_RB_TREE_H_ +#define MYTINYSTL_RB_TREE_H_ + +// 这个头文件包含一个模板类 rb_tree +// rb_tree : 红黑树 + +#include + +#include + +#include "functional.h" +#include "iterator.h" +#include "memory.h" +#include "type_traits.h" +#include "exceptdef.h" + +namespace mystl +{ + +// rb tree 节点颜色的类型 + +typedef bool rb_tree_color_type; + +static constexpr rb_tree_color_type rb_tree_red = false; +static constexpr rb_tree_color_type rb_tree_black = true; + +// forward declaration + +template struct rb_tree_node_base; +template struct rb_tree_node; + +template struct rb_tree_iterator; +template struct rb_tree_const_iterator; + +// rb tree value traits + +template +struct rb_tree_value_traits_imp +{ + typedef T key_type; + typedef T mapped_type; + typedef T value_type; + + template + static const key_type& get_key(const Ty& value) + { + return value; + } + + template + static const value_type& get_value(const Ty& value) + { + return value; + } +}; + +template +struct rb_tree_value_traits_imp +{ + typedef typename std::remove_cv::type key_type; + typedef typename T::second_type mapped_type; + typedef T value_type; + + template + static const key_type& get_key(const Ty& value) + { + return value.first; + } + + template + static const value_type& get_value(const Ty& value) + { + return value; + } +}; + +template +struct rb_tree_value_traits +{ + static constexpr bool is_map = mystl::is_pair::value; + + typedef rb_tree_value_traits_imp value_traits_type; + + typedef typename value_traits_type::key_type key_type; + typedef typename value_traits_type::mapped_type mapped_type; + typedef typename value_traits_type::value_type value_type; + + template + static const key_type& get_key(const Ty& value) + { + return value_traits_type::get_key(value); + } + + template + static const value_type& get_value(const Ty& value) + { + return value_traits_type::get_value(value); + } +}; + +// rb tree node traits + +template +struct rb_tree_node_traits +{ + typedef rb_tree_color_type color_type; + + typedef rb_tree_value_traits value_traits; + typedef typename value_traits::key_type key_type; + typedef typename value_traits::mapped_type mapped_type; + typedef typename value_traits::value_type value_type; + + typedef rb_tree_node_base* base_ptr; + typedef rb_tree_node* node_ptr; +}; + +// rb tree 的节点设计 + +template +struct rb_tree_node_base +{ + typedef rb_tree_color_type color_type; + typedef rb_tree_node_base* base_ptr; + typedef rb_tree_node* node_ptr; + + base_ptr parent; // 父节点 + base_ptr left; // 左子节点 + base_ptr right; // 右子节点 + color_type color; // 节点颜色 + + base_ptr get_base_ptr() + { + return &*this; + } + + node_ptr get_node_ptr() + { + return reinterpret_cast(&*this); + } + + node_ptr& get_node_ref() + { + return reinterpret_cast(*this); + } +}; + +template +struct rb_tree_node :public rb_tree_node_base +{ + typedef rb_tree_node_base* base_ptr; + typedef rb_tree_node* node_ptr; + + T value; // 节点值 + + base_ptr get_base_ptr() + { + return static_cast(&*this); + } + + node_ptr get_node_ptr() + { + return &*this; + } +}; + +// rb tree traits + +template +struct rb_tree_traits +{ + typedef rb_tree_value_traits value_traits; + + typedef typename value_traits::key_type key_type; + typedef typename value_traits::mapped_type mapped_type; + typedef typename value_traits::value_type value_type; + + typedef value_type* pointer; + typedef value_type& reference; + typedef const value_type* const_pointer; + typedef const value_type& const_reference; + + typedef rb_tree_node_base base_type; + typedef rb_tree_node node_type; + + typedef base_type* base_ptr; + typedef node_type* node_ptr; +}; + +// rb tree 的迭代器设计 + +template +struct rb_tree_iterator_base :public mystl::iterator +{ + typedef typename rb_tree_traits::base_ptr base_ptr; + + base_ptr node; // 指向节点本身 + + rb_tree_iterator_base() :node(nullptr) {} + + // 使迭代器前进 + void inc() + { + if (node->right != nullptr) + { + node = rb_tree_min(node->right); + } + else + { // 如果没有右子节点 + auto y = node->parent; + while (y->right == node) + { + node = y; + y = y->parent; + } + if (node->right != y) // 应对“寻找根节点的下一节点,而根节点没有右子节点”的特殊情况 + node = y; + } + } + + // 使迭代器后退 + void dec() + { + if (node->parent->parent == node && rb_tree_is_red(node)) + { // 如果 node 为 header + node = node->right; // 指向整棵树的 max 节点 + } + else if (node->left != nullptr) + { + node = rb_tree_max(node->left); + } + else + { // 非 header 节点,也无左子节点 + auto y = node->parent; + while (node == y->left) + { + node = y; + y = y->parent; + } + node = y; + } + } + + bool operator==(const rb_tree_iterator_base& rhs) { return node == rhs.node; } + bool operator!=(const rb_tree_iterator_base& rhs) { return node != rhs.node; } +}; + +template +struct rb_tree_iterator :public rb_tree_iterator_base +{ + typedef rb_tree_traits tree_traits; + + typedef typename tree_traits::value_type value_type; + typedef typename tree_traits::pointer pointer; + typedef typename tree_traits::reference reference; + typedef typename tree_traits::base_ptr base_ptr; + typedef typename tree_traits::node_ptr node_ptr; + + typedef rb_tree_iterator iterator; + typedef rb_tree_const_iterator const_iterator; + typedef iterator self; + + using rb_tree_iterator_base::node; + + // 构造函数 + rb_tree_iterator() {} + rb_tree_iterator(base_ptr x) { node = x; } + rb_tree_iterator(node_ptr x) { node = x; } + rb_tree_iterator(const iterator& rhs) { node = rhs.node; } + rb_tree_iterator(const const_iterator& rhs) { node = rhs.node; } + + // 重载操作符 + reference operator*() const { return node->get_node_ptr()->value; } + pointer operator->() const { return &(operator*()); } + + self& operator++() + { + this->inc(); + return *this; + } + self operator++(int) + { + self tmp(*this); + this->inc(); + return tmp; + } + self& operator--() + { + this->dec(); + return *this; + } + self operator--(int) + { + self tmp(*this); + this->dec(); + return tmp; + } +}; + +template +struct rb_tree_const_iterator :public rb_tree_iterator_base +{ + typedef rb_tree_traits tree_traits; + + typedef typename tree_traits::value_type value_type; + typedef typename tree_traits::const_pointer pointer; + typedef typename tree_traits::const_reference reference; + typedef typename tree_traits::base_ptr base_ptr; + typedef typename tree_traits::node_ptr node_ptr; + + typedef rb_tree_iterator iterator; + typedef rb_tree_const_iterator const_iterator; + typedef const_iterator self; + + using rb_tree_iterator_base::node; + + // 构造函数 + rb_tree_const_iterator() {} + rb_tree_const_iterator(base_ptr x) { node = x; } + rb_tree_const_iterator(node_ptr x) { node = x; } + rb_tree_const_iterator(const iterator& rhs) { node = rhs.node; } + rb_tree_const_iterator(const const_iterator& rhs) { node = rhs.node; } + + // 重载操作符 + reference operator*() const { return node->get_node_ptr()->value; } + pointer operator->() const { return &(operator*()); } + + self& operator++() + { + this->inc(); + return *this; + } + self operator++(int) + { + self tmp(*this); + this->inc(); + return tmp; + } + self& operator--() + { + this->dec(); + return *this; + } + self operator--(int) + { + self tmp(*this); + this->dec(); + return tmp; + } +}; + +// tree algorithm + +template +NodePtr rb_tree_min(NodePtr x) noexcept +{ + while (x->left != nullptr) + x = x->left; + return x; +} + +template +NodePtr rb_tree_max(NodePtr x) noexcept +{ + while (x->right != nullptr) + x = x->right; + return x; +} + +template +bool rb_tree_is_lchild(NodePtr node) noexcept +{ + return node == node->parent->left; +} + +template +bool rb_tree_is_red(NodePtr node) noexcept +{ + return node->color == rb_tree_red; +} + +template +void rb_tree_set_black(NodePtr& node) noexcept +{ + node->color = rb_tree_black; +} + +template +void rb_tree_set_red(NodePtr& node) noexcept +{ + node->color = rb_tree_red; +} + +template +NodePtr rb_tree_next(NodePtr node) noexcept +{ + if (node->right != nullptr) + return rb_tree_min(node->right); + while (!rb_tree_is_lchild(node)) + node = node->parent; + return node->parent; +} + +/*---------------------------------------*\ +| p p | +| / \ / \ | +| x d rotate left y d | +| / \ ===========> / \ | +| a y x c | +| / \ / \ | +| b c a b | +\*---------------------------------------*/ +// 左旋,参数一为左旋点,参数二为根节点 +template +void rb_tree_rotate_left(NodePtr x, NodePtr& root) noexcept +{ + auto y = x->right; // y 为 x 的右子节点 + x->right = y->left; + if (y->left != nullptr) + y->left->parent = x; + y->parent = x->parent; + + if (x == root) + { // 如果 x 为根节点,让 y 顶替 x 成为根节点 + root = y; + } + else if (rb_tree_is_lchild(x)) + { // 如果 x 是左子节点 + x->parent->left = y; + } + else + { // 如果 x 是右子节点 + x->parent->right = y; + } + // 调整 x 与 y 的关系 + y->left = x; + x->parent = y; +} + +/*----------------------------------------*\ +| p p | +| / \ / \ | +| d x rotate right d y | +| / \ ===========> / \ | +| y a b x | +| / \ / \ | +| b c c a | +\*----------------------------------------*/ +// 右旋,参数一为右旋点,参数二为根节点 +template +void rb_tree_rotate_right(NodePtr x, NodePtr& root) noexcept +{ + auto y = x->left; + x->left = y->right; + if (y->right) + y->right->parent = x; + y->parent = x->parent; + + if (x == root) + { // 如果 x 为根节点,让 y 顶替 x 成为根节点 + root = y; + } + else if (rb_tree_is_lchild(x)) + { // 如果 x 是右子节点 + x->parent->left = y; + } + else + { // 如果 x 是左子节点 + x->parent->right = y; + } + // 调整 x 与 y 的关系 + y->right = x; + x->parent = y; +} + +// 插入节点后使 rb tree 重新平衡,参数一为新增节点,参数二为根节点 +// +// case 1: 新增节点位于根节点,令新增节点为黑 +// case 2: 新增节点的父节点为黑,没有破坏平衡,直接返回 +// case 3: 父节点和叔叔节点都为红,令父节点和叔叔节点为黑,祖父节点为红, +// 然后令祖父节点为当前节点,继续处理 +// case 4: 父节点为红,叔叔节点为 NIL 或黑色,父节点为左(右)孩子,当前节点为右(左)孩子, +// 让父节点成为当前节点,再以当前节点为支点左(右)旋 +// case 5: 父节点为红,叔叔节点为 NIL 或黑色,父节点为左(右)孩子,当前节点为左(右)孩子, +// 让父节点变为黑色,祖父节点变为红色,以祖父节点为支点右(左)旋 +// +// 参考博客: http://blog.csdn.net/v_JULY_v/article/details/6105630 +// http://blog.csdn.net/v_JULY_v/article/details/6109153 +template +void rb_tree_insert_rebalance(NodePtr x, NodePtr& root) noexcept +{ + rb_tree_set_red(x); // 新增节点为红色 + while (x != root && rb_tree_is_red(x->parent)) + { + if (rb_tree_is_lchild(x->parent)) + { // 如果父节点是左子节点 + auto uncle = x->parent->parent->right; + if (uncle != nullptr && rb_tree_is_red(uncle)) + { // case 3: 父节点和叔叔节点都为红 + rb_tree_set_black(x->parent); + rb_tree_set_black(uncle); + x = x->parent->parent; + rb_tree_set_red(x); + } + else + { // 无叔叔节点或叔叔节点为黑 + if (!rb_tree_is_lchild(x)) + { // case 4: 当前节点 x 为右子节点 + x = x->parent; + rb_tree_rotate_left(x, root); + } + // 都转换成 case 5: 当前节点为左子节点 + rb_tree_set_black(x->parent); + rb_tree_set_red(x->parent->parent); + rb_tree_rotate_right(x->parent->parent, root); + break; + } + } + else // 如果父节点是右子节点,对称处理 + { + auto uncle = x->parent->parent->left; + if (uncle != nullptr && rb_tree_is_red(uncle)) + { // case 3: 父节点和叔叔节点都为红 + rb_tree_set_black(x->parent); + rb_tree_set_black(uncle); + x = x->parent->parent; + rb_tree_set_red(x); + // 此时祖父节点为红,可能会破坏红黑树的性质,令当前节点为祖父节点,继续处理 + } + else + { // 无叔叔节点或叔叔节点为黑 + if (rb_tree_is_lchild(x)) + { // case 4: 当前节点 x 为左子节点 + x = x->parent; + rb_tree_rotate_right(x, root); + } + // 都转换成 case 5: 当前节点为左子节点 + rb_tree_set_black(x->parent); + rb_tree_set_red(x->parent->parent); + rb_tree_rotate_left(x->parent->parent, root); + break; + } + } + } + rb_tree_set_black(root); // 根节点永远为黑 +} + +// 删除节点后使 rb tree 重新平衡,参数一为要删除的节点,参数二为根节点,参数三为最小节点,参数四为最大节点 +// +// 参考博客: http://blog.csdn.net/v_JULY_v/article/details/6105630 +// http://blog.csdn.net/v_JULY_v/article/details/6109153 +template +NodePtr rb_tree_erase_rebalance(NodePtr z, NodePtr& root, NodePtr& leftmost, NodePtr& rightmost) +{ + // y 是可能的替换节点,指向最终要删除的节点 + auto y = (z->left == nullptr || z->right == nullptr) ? z : rb_tree_next(z); + // x 是 y 的一个独子节点或 NIL 节点 + auto x = y->left != nullptr ? y->left : y->right; + // xp 为 x 的父节点 + NodePtr xp = nullptr; + + // y != z 说明 z 有两个非空子节点,此时 y 指向 z 右子树的最左节点,x 指向 y 的右子节点。 + // 用 y 顶替 z 的位置,用 x 顶替 y 的位置,最后用 y 指向 z + if (y != z) + { + z->left->parent = y; + y->left = z->left; + + // 如果 y 不是 z 的右子节点,那么 z 的右子节点一定有左孩子 + if (y != z->right) + { // x 替换 y 的位置 + xp = y->parent; + if (x != nullptr) + x->parent = y->parent; + + y->parent->left = x; + y->right = z->right; + z->right->parent = y; + } + else + { + xp = y; + } + + // 连接 y 与 z 的父节点 + if (root == z) + root = y; + else if (rb_tree_is_lchild(z)) + z->parent->left = y; + else + z->parent->right = y; + y->parent = z->parent; + mystl::swap(y->color, z->color); + y = z; + } + // y == z 说明 z 至多只有一个孩子 + else + { + xp = y->parent; + if (x) + x->parent = y->parent; + + // 连接 x 与 z 的父节点 + if (root == z) + root = x; + else if (rb_tree_is_lchild(z)) + z->parent->left = x; + else + z->parent->right = x; + + // 此时 z 有可能是最左节点或最右节点,更新数据 + if (leftmost == z) + leftmost = x == nullptr ? xp : rb_tree_min(x); + if (rightmost == z) + rightmost = x == nullptr ? xp : rb_tree_max(x); + } + + // 此时,y 指向要删除的节点,x 为替代节点,从 x 节点开始调整。 + // 如果删除的节点为红色,树的性质没有被破坏,否则按照以下情况调整(x 为左子节点为例): + // case 1: 兄弟节点为红色,令父节点为红,兄弟节点为黑,进行左(右)旋,继续处理 + // case 2: 兄弟节点为黑色,且两个子节点都为黑色或 NIL,令兄弟节点为红,父节点成为当前节点,继续处理 + // case 3: 兄弟节点为黑色,左子节点为红色或 NIL,右子节点为黑色或 NIL, + // 令兄弟节点为红,兄弟节点的左子节点为黑,以兄弟节点为支点右(左)旋,继续处理 + // case 4: 兄弟节点为黑色,右子节点为红色,令兄弟节点为父节点的颜色,父节点为黑色,兄弟节点的右子节点 + // 为黑色,以父节点为支点左(右)旋,树的性质调整完成,算法结束 + if (!rb_tree_is_red(y)) + { // x 为黑色时,调整,否则直接将 x 变为黑色即可 + while (x != root && (x == nullptr || !rb_tree_is_red(x))) + { + if (x == xp->left) + { // 如果 x 为左子节点 + auto brother = xp->right; + if (rb_tree_is_red(brother)) + { // case 1 + rb_tree_set_black(brother); + rb_tree_set_red(xp); + rb_tree_rotate_left(xp, root); + brother = xp->right; + } + // case 1 转为为了 case 2、3、4 中的一种 + if ((brother->left == nullptr || !rb_tree_is_red(brother->left)) && + (brother->right == nullptr || !rb_tree_is_red(brother->right))) + { // case 2 + rb_tree_set_red(brother); + x = xp; + xp = xp->parent; + } + else + { + if (brother->right == nullptr || !rb_tree_is_red(brother->right)) + { // case 3 + if (brother->left != nullptr) + rb_tree_set_black(brother->left); + rb_tree_set_red(brother); + rb_tree_rotate_right(brother, root); + brother = xp->right; + } + // 转为 case 4 + brother->color = xp->color; + rb_tree_set_black(xp); + if (brother->right != nullptr) + rb_tree_set_black(brother->right); + rb_tree_rotate_left(xp, root); + break; + } + } + else // x 为右子节点,对称处理 + { + auto brother = xp->left; + if (rb_tree_is_red(brother)) + { // case 1 + rb_tree_set_black(brother); + rb_tree_set_red(xp); + rb_tree_rotate_right(xp, root); + brother = xp->left; + } + if ((brother->left == nullptr || !rb_tree_is_red(brother->left)) && + (brother->right == nullptr || !rb_tree_is_red(brother->right))) + { // case 2 + rb_tree_set_red(brother); + x = xp; + xp = xp->parent; + } + else + { + if (brother->left == nullptr || !rb_tree_is_red(brother->left)) + { // case 3 + if (brother->right != nullptr) + rb_tree_set_black(brother->right); + rb_tree_set_red(brother); + rb_tree_rotate_left(brother, root); + brother = xp->left; + } + // 转为 case 4 + brother->color = xp->color; + rb_tree_set_black(xp); + if (brother->left != nullptr) + rb_tree_set_black(brother->left); + rb_tree_rotate_right(xp, root); + break; + } + } + } + if (x != nullptr) + rb_tree_set_black(x); + } + return y; +} + +// 模板类 rb_tree +// 参数一代表数据类型,参数二代表键值比较类型 +template +class rb_tree +{ +public: + // rb_tree 的嵌套型别定义 + + typedef rb_tree_traits tree_traits; + typedef rb_tree_value_traits value_traits; + + typedef typename tree_traits::base_type base_type; + typedef typename tree_traits::base_ptr base_ptr; + typedef typename tree_traits::node_type node_type; + typedef typename tree_traits::node_ptr node_ptr; + typedef typename tree_traits::key_type key_type; + typedef typename tree_traits::mapped_type mapped_type; + typedef typename tree_traits::value_type value_type; + typedef Compare key_compare; + + typedef mystl::allocator allocator_type; + typedef mystl::allocator data_allocator; + typedef mystl::allocator base_allocator; + typedef mystl::allocator node_allocator; + + typedef typename allocator_type::pointer pointer; + typedef typename allocator_type::const_pointer const_pointer; + typedef typename allocator_type::reference reference; + typedef typename allocator_type::const_reference const_reference; + typedef typename allocator_type::size_type size_type; + typedef typename allocator_type::difference_type difference_type; + + typedef rb_tree_iterator iterator; + typedef rb_tree_const_iterator const_iterator; + typedef mystl::reverse_iterator reverse_iterator; + typedef mystl::reverse_iterator const_reverse_iterator; + + allocator_type get_allocator() const { return node_allocator(); } + key_compare key_comp() const { return key_comp_; } + +private: + // 用以下三个数据表现 rb tree + base_ptr header_; // 特殊节点,与根节点互为对方的父节点 + size_type node_count_; // 节点数 + key_compare key_comp_; // 节点键值比较的准则 + +private: + // 以下三个函数用于取得根节点,最小节点和最大节点 + base_ptr& root() const { return header_->parent; } + base_ptr& leftmost() const { return header_->left; } + base_ptr& rightmost() const { return header_->right; } + +public: + // 构造、复制、析构函数 + rb_tree() { rb_tree_init(); } + + rb_tree(const rb_tree& rhs); + rb_tree(rb_tree&& rhs) noexcept; + + rb_tree& operator=(const rb_tree& rhs); + rb_tree& operator=(rb_tree&& rhs); + + ~rb_tree() { clear(); } + +public: + // 迭代器相关操作 + + iterator begin() noexcept + { return leftmost(); } + const_iterator begin() const noexcept + { return leftmost(); } + iterator end() noexcept + { return header_; } + const_iterator end() const noexcept + { return header_; } + + reverse_iterator rbegin() noexcept + { return reverse_iterator(end()); } + const_reverse_iterator rbegin() const noexcept + { return const_reverse_iterator(end()); } + reverse_iterator rend() noexcept + { return reverse_iterator(begin()); } + const_reverse_iterator rend() const noexcept + { return const_reverse_iterator(begin()); } + + const_iterator cbegin() const noexcept + { return begin(); } + const_iterator cend() const noexcept + { return end(); } + const_reverse_iterator crbegin() const noexcept + { return rbegin(); } + const_reverse_iterator crend() const noexcept + { return rend(); } + + // 容量相关操作 + + bool empty() const noexcept { return node_count_ == 0; } + size_type size() const noexcept { return node_count_; } + size_type max_size() const noexcept { return static_cast(-1); } + + // 插入删除相关操作 + + // emplace + + template + iterator emplace_multi(Args&& ...args); + + template + mystl::pair emplace_unique(Args&& ...args); + + template + iterator emplace_multi_use_hint(iterator hint, Args&& ...args); + + template + iterator emplace_unique_use_hint(iterator hint, Args&& ...args); + + // insert + + iterator insert_multi(const value_type& value); + iterator insert_multi(value_type&& value) + { + return emplace_multi(mystl::move(value)); + } + + iterator insert_multi(iterator hint, const value_type& value) + { + return emplace_multi_use_hint(hint, value); + } + iterator insert_multi(iterator hint, value_type&& value) + { + return emplace_multi_use_hint(hint, mystl::move(value)); + } + + template + void insert_multi(InputIterator first, InputIterator last) + { + size_type n = mystl::distance(first, last); + THROW_LENGTH_ERROR_IF(node_count_ > max_size() - n, "rb_tree's size too big"); + for (; n > 0; --n, ++first) + insert_multi(end(), *first); + } + + mystl::pair insert_unique(const value_type& value); + mystl::pair insert_unique(value_type&& value) + { + return emplace_unique(mystl::move(value)); + } + + iterator insert_unique(iterator hint, const value_type& value) + { + return emplace_unique_use_hint(hint, value); + } + iterator insert_unique(iterator hint, value_type&& value) + { + return emplace_unique_use_hint(hint, mystl::move(value)); + } + + template + void insert_unique(InputIterator first, InputIterator last) + { + size_type n = mystl::distance(first, last); + THROW_LENGTH_ERROR_IF(node_count_ > max_size() - n, "rb_tree's size too big"); + for (; n > 0; --n, ++first) + insert_unique(end(), *first); + } + + // erase + + iterator erase(iterator hint); + + size_type erase_multi(const key_type& key); + size_type erase_unique(const key_type& key); + + void erase(iterator first, iterator last); + + void clear(); + + // rb_tree 相关操作 + + iterator find(const key_type& key); + const_iterator find(const key_type& key) const; + + size_type count_multi(const key_type& key) const + { + auto p = equal_range_multi(key); + return static_cast(mystl::distance(p.first, p.second)); + } + size_type count_unique(const key_type& key) const + { + return find(key) != end() ? 1 : 0; + } + + iterator lower_bound(const key_type& key); + const_iterator lower_bound(const key_type& key) const; + + iterator upper_bound(const key_type& key); + const_iterator upper_bound(const key_type& key) const; + + mystl::pair + equal_range_multi(const key_type& key) + { + return mystl::pair(lower_bound(key), upper_bound(key)); + } + mystl::pair + equal_range_multi(const key_type& key) const + { + return mystl::pair(lower_bound(key), upper_bound(key)); + } + + mystl::pair + equal_range_unique(const key_type& key) + { + iterator it = find(key); + auto next = it; + return it == end() ? mystl::make_pair(it, it) : mystl::make_pair(it, ++next); + } + mystl::pair + equal_range_unique(const key_type& key) const + { + const_iterator it = find(key); + auto next = it; + return it == end() ? mystl::make_pair(it, it) : mystl::make_pair(it, ++next); + } + + void swap(rb_tree& rhs) noexcept; + +private: + + // node related + template + node_ptr create_node(Args&&... args); + node_ptr clone_node(base_ptr x); + void destroy_node(node_ptr p); + + // init / reset + void rb_tree_init(); + void reset(); + + // get insert pos + mystl::pair + get_insert_multi_pos(const key_type& key); + mystl::pair, bool> + get_insert_unique_pos(const key_type& key); + + // insert value / insert node + iterator insert_value_at(base_ptr x, const value_type& value, bool add_to_left); + iterator insert_node_at(base_ptr x, node_ptr node, bool add_to_left); + + // insert use hint + iterator insert_multi_use_hint(iterator hint, key_type key, node_ptr node); + iterator insert_unique_use_hint(iterator hint, key_type key, node_ptr node); + + // copy tree / erase tree + base_ptr copy_from(base_ptr x, base_ptr p); + void erase_since(base_ptr x); +}; + +/*****************************************************************************************/ + +// 复制构造函数 +template +rb_tree:: +rb_tree(const rb_tree& rhs) +{ + rb_tree_init(); + if (rhs.node_count_ != 0) + { + root() = copy_from(rhs.root(), header_); + leftmost() = rb_tree_min(root()); + rightmost() = rb_tree_max(root()); + } + node_count_ = rhs.node_count_; + key_comp_ = rhs.key_comp_; +} + +// 移动构造函数 +template +rb_tree:: +rb_tree(rb_tree&& rhs) noexcept + :header_(mystl::move(rhs.header_)), + node_count_(rhs.node_count_), + key_comp_(rhs.key_comp_) +{ + rhs.reset(); +} + +// 复制赋值操作符 +template +rb_tree& +rb_tree:: +operator=(const rb_tree& rhs) +{ + if (this != &rhs) + { + clear(); + + if (rhs.node_count_ != 0) + { + root() = copy_from(rhs.root(), header_); + leftmost() = rb_tree_min(root()); + rightmost() = rb_tree_max(root()); + } + + node_count_ = rhs.node_count_; + key_comp_ = rhs.key_comp_; + } + return *this; +} + +// 移动赋值操作符 +template +rb_tree& +rb_tree:: +operator=(rb_tree&& rhs) +{ + clear(); + header_ = mystl::move(rhs.header_); + node_count_ = rhs.node_count_; + key_comp_ = rhs.key_comp_; + rhs.reset(); + return *this; +} + +// 就地插入元素,键值允许重复 +template +template +typename rb_tree::iterator +rb_tree:: +emplace_multi(Args&& ...args) +{ + THROW_LENGTH_ERROR_IF(node_count_ > max_size() - 1, "rb_tree's size too big"); + node_ptr np = create_node(mystl::forward(args)...); + auto res = get_insert_multi_pos(value_traits::get_key(np->value)); + return insert_node_at(res.first, np, res.second); +} + +// 就地插入元素,键值不允许重复 +template +template +mystl::pair::iterator, bool> +rb_tree:: +emplace_unique(Args&& ...args) +{ + THROW_LENGTH_ERROR_IF(node_count_ > max_size() - 1, "rb_tree's size too big"); + node_ptr np = create_node(mystl::forward(args)...); + auto res = get_insert_unique_pos(value_traits::get_key(np->value)); + if (res.second) + { // 插入成功 + return mystl::make_pair(insert_node_at(res.first.first, np, res.first.second), true); + } + destroy_node(np); + return mystl::make_pair(iterator(res.first.first), false); +} + +// 就地插入元素,键值允许重复,当 hint 位置与插入位置接近时,插入操作的时间复杂度可以降低 +template +template +typename rb_tree::iterator +rb_tree:: +emplace_multi_use_hint(iterator hint, Args&& ...args) +{ + THROW_LENGTH_ERROR_IF(node_count_ > max_size() - 1, "rb_tree's size too big"); + node_ptr np = create_node(mystl::forward(args)...); + if (node_count_ == 0) + { + return insert_node_at(header_, np, true); + } + key_type key = value_traits::get_key(np->value); + if (hint == begin()) + { // 位于 begin 处 + if (key_comp_(key, value_traits::get_key(*hint))) + { + return insert_node_at(hint.node, np, true); + } + else + { + auto pos = get_insert_multi_pos(key); + return insert_node_at(pos.first, np, pos.second); + } + } + else if (hint == end()) + { // 位于 end 处 + if (!key_comp_(key, value_traits::get_key(rightmost()->get_node_ptr()->value))) + { + return insert_node_at(rightmost(), np, false); + } + else + { + auto pos = get_insert_multi_pos(key); + return insert_node_at(pos.first, np, pos.second); + } + } + return insert_multi_use_hint(hint, key, np); +} + +// 就地插入元素,键值不允许重复,当 hint 位置与插入位置接近时,插入操作的时间复杂度可以降低 +template +template +typename rb_tree::iterator +rb_tree:: +emplace_unique_use_hint(iterator hint, Args&& ...args) +{ + THROW_LENGTH_ERROR_IF(node_count_ > max_size() - 1, "rb_tree's size too big"); + node_ptr np = create_node(mystl::forward(args)...); + if (node_count_ == 0) + { + return insert_node_at(header_, np, true); + } + key_type key = value_traits::get_key(np->value); + if (hint == begin()) + { // 位于 begin 处 + if (key_comp_(key, value_traits::get_key(*hint))) + { + return insert_node_at(hint.node, np, true); + } + else + { + auto pos = get_insert_unique_pos(key); + if (!pos.second) + { + destroy_node(np); + return pos.first.first; + } + return insert_node_at(pos.first.first, np, pos.first.second); + } + } + else if (hint == end()) + { // 位于 end 处 + if (key_comp_(value_traits::get_key(rightmost()->get_node_ptr()->value), key)) + { + return insert_node_at(rightmost(), np, false); + } + else + { + auto pos = get_insert_unique_pos(key); + if (!pos.second) + { + destroy_node(np); + return pos.first.first; + } + return insert_node_at(pos.first.first, np, pos.first.second); + } + } + return insert_unique_use_hint(hint, key, np); +} + +// 插入元素,节点键值允许重复 +template +typename rb_tree::iterator +rb_tree:: +insert_multi(const value_type& value) +{ + THROW_LENGTH_ERROR_IF(node_count_ > max_size() - 1, "rb_tree's size too big"); + auto res = get_insert_multi_pos(value_traits::get_key(value)); + return insert_value_at(res.first, value, res.second); +} + +// 插入新值,节点键值不允许重复,返回一个 pair,若插入成功,pair 的第二参数为 true,否则为 false +template +mystl::pair::iterator, bool> +rb_tree:: +insert_unique(const value_type& value) +{ + THROW_LENGTH_ERROR_IF(node_count_ > max_size() - 1, "rb_tree's size too big"); + auto res = get_insert_unique_pos(value_traits::get_key(value)); + if (res.second) + { // 插入成功 + return mystl::make_pair(insert_value_at(res.first.first, value, res.first.second), true); + } + return mystl::make_pair(res.first.first, false); +} + +// 删除 hint 位置的节点 +template +typename rb_tree::iterator +rb_tree:: +erase(iterator hint) +{ + auto node = hint.node->get_node_ptr(); + iterator next(node); + ++next; + + rb_tree_erase_rebalance(hint.node, root(), leftmost(), rightmost()); + destroy_node(node); + --node_count_; + return next; +} + +// 删除键值等于 key 的元素,返回删除的个数 +template +typename rb_tree::size_type +rb_tree:: +erase_multi(const key_type& key) +{ + auto p = equal_range_multi(key); + size_type n = mystl::distance(p.first, p.second); + erase(p.first, p.second); + return n; +} + +// 删除键值等于 key 的元素,返回删除的个数 +template +typename rb_tree::size_type +rb_tree:: +erase_unique(const key_type& key) +{ + auto it = find(key); + if (it != end()) + { + erase(it); + return 1; + } + return 0; +} + +// 删除[first, last)区间内的元素 +template +void rb_tree:: +erase(iterator first, iterator last) +{ + if (first == begin() && last == end()) + { + clear(); + } + else + { + while (first != last) + erase(first++); + } +} + +// 清空 rb tree +template +void rb_tree:: +clear() +{ + if (node_count_ != 0) + { + erase_since(root()); + leftmost() = header_; + root() = nullptr; + rightmost() = header_; + node_count_ = 0; + } +} + +// 查找键值为 k 的节点,返回指向它的迭代器 +template +typename rb_tree::iterator +rb_tree:: +find(const key_type& key) +{ + auto y = header_; // 最后一个不小于 key 的节点 + auto x = root(); + while (x != nullptr) + { + if (!key_comp_(value_traits::get_key(x->get_node_ptr()->value), key)) + { // key 小于等于 x 键值,向左走 + y = x, x = x->left; + } + else + { // key 大于 x 键值,向右走 + x = x->right; + } + } + iterator j = iterator(y); + return (j == end() || key_comp_(key, value_traits::get_key(*j))) ? end() : j; +} + +template +typename rb_tree::const_iterator +rb_tree:: +find(const key_type& key) const +{ + auto y = header_; // 最后一个不小于 key 的节点 + auto x = root(); + while (x != nullptr) + { + if (!key_comp_(value_traits::get_key(x->get_node_ptr()->value), key)) + { // key 小于等于 x 键值,向左走 + y = x, x = x->left; + } + else + { // key 大于 x 键值,向右走 + x = x->right; + } + } + const_iterator j = const_iterator(y); + return (j == end() || key_comp_(key, value_traits::get_key(*j))) ? end() : j; +} + +// 键值不小于 key 的第一个位置 +template +typename rb_tree::iterator +rb_tree:: +lower_bound(const key_type& key) +{ + auto y = header_; + auto x = root(); + while (x != nullptr) + { + if (!key_comp_(value_traits::get_key(x->get_node_ptr()->value), key)) + { // key <= x + y = x, x = x->left; + } + else + { + x = x->right; + } + } + return iterator(y); +} + +template +typename rb_tree::const_iterator +rb_tree:: +lower_bound(const key_type& key) const +{ + auto y = header_; + auto x = root(); + while (x != nullptr) + { + if (!key_comp_(value_traits::get_key(x->get_node_ptr()->value), key)) + { // key <= x + y = x, x = x->left; + } + else + { + x = x->right; + } + } + return const_iterator(y); +} + +// 键值不小于 key 的最后一个位置 +template +typename rb_tree::iterator +rb_tree:: +upper_bound(const key_type& key) +{ + auto y = header_; + auto x = root(); + while (x != nullptr) + { + if (key_comp_(key, value_traits::get_key(x->get_node_ptr()->value))) + { // key < x + y = x, x = x->left; + } + else + { + x = x->right; + } + } + return iterator(y); +} + +template +typename rb_tree::const_iterator +rb_tree:: +upper_bound(const key_type& key) const +{ + auto y = header_; + auto x = root(); + while (x != nullptr) + { + if (key_comp_(key, value_traits::get_key(x->get_node_ptr()->value))) + { // key < x + y = x, x = x->left; + } + else + { + x = x->right; + } + } + return const_iterator(y); +} + +// 交换 rb tree +template +void rb_tree:: +swap(rb_tree& rhs) noexcept +{ + if (this != &rhs) + { + mystl::swap(header_, rhs.header_); + mystl::swap(node_count_, rhs.node_count_); + mystl::swap(key_comp_, rhs.key_comp_); + } +} + +/*****************************************************************************************/ +// helper function + +// 创建一个结点 +template +template +typename rb_tree::node_ptr +rb_tree:: +create_node(Args&&... args) +{ + auto tmp = node_allocator::allocate(1); + try + { + data_allocator::construct(mystl::address_of(tmp->value), mystl::forward(args)...); + tmp->left = nullptr; + tmp->right = nullptr; + tmp->parent = nullptr; + } + catch (...) + { + node_allocator::deallocate(tmp); + throw; + } + return tmp; +} + +// 复制一个结点 +template +typename rb_tree::node_ptr +rb_tree:: +clone_node(base_ptr x) +{ + node_ptr tmp = create_node(x->get_node_ptr()->value); + tmp->color = x->color; + tmp->left = nullptr; + tmp->right = nullptr; + return tmp; +} + +// 销毁一个结点 +template +void rb_tree:: +destroy_node(node_ptr p) +{ + data_allocator::destroy(&p->value); + node_allocator::deallocate(p); +} + +// 初始化容器 +template +void rb_tree:: +rb_tree_init() +{ + header_ = base_allocator::allocate(1); + header_->color = rb_tree_red; // header_ 节点颜色为红,与 root 区分 + root() = nullptr; + leftmost() = header_; + rightmost() = header_; + node_count_ = 0; +} + +// reset 函数 +template +void rb_tree::reset() +{ + header_ = nullptr; + node_count_ = 0; +} + +// get_insert_multi_pos 函数 +template +mystl::pair::base_ptr, bool> +rb_tree::get_insert_multi_pos(const key_type& key) +{ + auto x = root(); + auto y = header_; + bool add_to_left = true; + while (x != nullptr) + { + y = x; + add_to_left = key_comp_(key, value_traits::get_key(x->get_node_ptr()->value)); + x = add_to_left ? x->left : x->right; + } + return mystl::make_pair(y, add_to_left); +} + +// get_insert_unique_pos 函数 +template +mystl::pair::base_ptr, bool>, bool> +rb_tree::get_insert_unique_pos(const key_type& key) +{ // 返回一个 pair,第一个值为一个 pair,包含插入点的父节点和一个 bool 表示是否在左边插入, + // 第二个值为一个 bool,表示是否插入成功 + auto x = root(); + auto y = header_; + bool add_to_left = true; // 树为空时也在 header_ 左边插入 + while (x != nullptr) + { + y = x; + add_to_left = key_comp_(key, value_traits::get_key(x->get_node_ptr()->value)); + x = add_to_left ? x->left : x->right; + } + iterator j = iterator(y); // 此时 y 为插入点的父节点 + if (add_to_left) + { + if (y == header_ || j == begin()) + { // 如果树为空树或插入点在最左节点处,肯定可以插入新的节点 + return mystl::make_pair(mystl::make_pair(y, true), true); + } + else + { // 否则,如果存在重复节点,那么 --j 就是重复的值 + --j; + } + } + if (key_comp_(value_traits::get_key(*j), key)) + { // 表明新节点没有重复 + return mystl::make_pair(mystl::make_pair(y, add_to_left), true); + } + // 进行至此,表示新节点与现有节点键值重复 + return mystl::make_pair(mystl::make_pair(y, add_to_left), false); +} + +// insert_value_at 函数 +// x 为插入点的父节点, value 为要插入的值,add_to_left 表示是否在左边插入 +template +typename rb_tree::iterator +rb_tree:: +insert_value_at(base_ptr x, const value_type& value, bool add_to_left) +{ + node_ptr node = create_node(value); + node->parent = x; + auto base_node = node->get_base_ptr(); + if (x == header_) + { + root() = base_node; + leftmost() = base_node; + rightmost() = base_node; + } + else if (add_to_left) + { + x->left = base_node; + if (leftmost() == x) + leftmost() = base_node; + } + else + { + x->right = base_node; + if (rightmost() == x) + rightmost() = base_node; + } + rb_tree_insert_rebalance(base_node, root()); + ++node_count_; + return iterator(node); +} + +// 在 x 节点处插入新的节点 +// x 为插入点的父节点, node 为要插入的节点,add_to_left 表示是否在左边插入 +template +typename rb_tree::iterator +rb_tree:: +insert_node_at(base_ptr x, node_ptr node, bool add_to_left) +{ + node->parent = x; + auto base_node = node->get_base_ptr(); + if (x == header_) + { + root() = base_node; + leftmost() = base_node; + rightmost() = base_node; + } + else if (add_to_left) + { + x->left = base_node; + if (leftmost() == x) + leftmost() = base_node; + } + else + { + x->right = base_node; + if (rightmost() == x) + rightmost() = base_node; + } + rb_tree_insert_rebalance(base_node, root()); + ++node_count_; + return iterator(node); +} + +// 插入元素,键值允许重复,使用 hint +template +typename rb_tree::iterator +rb_tree:: +insert_multi_use_hint(iterator hint, key_type key, node_ptr node) +{ + // 在 hint 附近寻找可插入的位置 + auto np = hint.node; + auto before = hint; + --before; + auto bnp = before.node; + if (!key_comp_(key, value_traits::get_key(*before)) && + !key_comp_(value_traits::get_key(*hint), key)) + { // before <= node <= hint + if (bnp->right == nullptr) + { + return insert_node_at(bnp, node, false); + } + else if (np->left == nullptr) + { + return insert_node_at(np, node, true); + } + } + auto pos = get_insert_multi_pos(key); + return insert_node_at(pos.first, node, pos.second); +} + +// 插入元素,键值不允许重复,使用 hint +template +typename rb_tree::iterator +rb_tree:: +insert_unique_use_hint(iterator hint, key_type key, node_ptr node) +{ + // 在 hint 附近寻找可插入的位置 + auto np = hint.node; + auto before = hint; + --before; + auto bnp = before.node; + if (key_comp_(value_traits::get_key(*before), key) && + key_comp_(key, value_traits::get_key(*hint))) + { // before < node < hint + if (bnp->right == nullptr) + { + return insert_node_at(bnp, node, false); + } + else if (np->left == nullptr) + { + return insert_node_at(np, node, true); + } + } + auto pos = get_insert_unique_pos(key); + if (!pos.second) + { + destroy_node(node); + return pos.first.first; + } + return insert_node_at(pos.first.first, node, pos.first.second); +} + +// copy_from 函数 +// 递归复制一颗树,节点从 x 开始,p 为 x 的父节点 +template +typename rb_tree::base_ptr +rb_tree::copy_from(base_ptr x, base_ptr p) +{ + auto top = clone_node(x); + top->parent = p; + try + { + if (x->right) + top->right = copy_from(x->right, top); + p = top; + x = x->left; + while (x != nullptr) + { + auto y = clone_node(x); + p->left = y; + y->parent = p; + if (x->right) + y->right = copy_from(x->right, y); + p = y; + x = x->left; + } + } + catch (...) + { + erase_since(top); + throw; + } + return top; +} + +// erase_since 函数 +// 从 x 节点开始删除该节点及其子树 +template +void rb_tree:: +erase_since(base_ptr x) +{ + while (x != nullptr) + { + erase_since(x->right); + auto y = x->left; + destroy_node(x->get_node_ptr()); + x = y; + } +} + +// 重载比较操作符 +template +bool operator==(const rb_tree& lhs, const rb_tree& rhs) +{ + return lhs.size() == rhs.size() && mystl::equal(lhs.begin(), lhs.end(), rhs.begin()); +} + +template +bool operator<(const rb_tree& lhs, const rb_tree& rhs) +{ + return mystl::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); +} + +template +bool operator!=(const rb_tree& lhs, const rb_tree& rhs) +{ + return !(lhs == rhs); +} + +template +bool operator>(const rb_tree& lhs, const rb_tree& rhs) +{ + return rhs < lhs; +} + +template +bool operator<=(const rb_tree& lhs, const rb_tree& rhs) +{ + return !(rhs < lhs); +} + +template +bool operator>=(const rb_tree& lhs, const rb_tree& rhs) +{ + return !(lhs < rhs); +} + +// 重载 mystl 的 swap +template +void swap(rb_tree& lhs, rb_tree& rhs) noexcept +{ + lhs.swap(rhs); +} + +} // namespace mystl +#endif // !MYTINYSTL_RB_TREE_H_ + diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/set.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/set.h new file mode 100644 index 0000000..3aa8434 --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/set.h @@ -0,0 +1,477 @@ +#ifndef MYTINYSTL_SET_H_ +#define MYTINYSTL_SET_H_ + +// 这个头文件包含两个模板类 set 和 multiset +// set : 集合,键值即实值,集合内元素会自动排序,键值不允许重复 +// multiset : 集合,键值即实值,集合内元素会自动排序,键值允许重复 + +// notes: +// +// 异常保证: +// mystl::set / mystl::multiset 满足基本异常保证,对以下等函数做强异常安全保证: +// * emplace +// * emplace_hint +// * insert + +#include "rb_tree.h" + +namespace mystl +{ + +// 模板类 set,键值不允许重复 +// 参数一代表键值类型,参数二代表键值比较方式,缺省使用 mystl::less +template > +class set +{ +public: + typedef Key key_type; + typedef Key value_type; + typedef Compare key_compare; + typedef Compare value_compare; + +private: + // 以 mystl::rb_tree 作为底层机制 + typedef mystl::rb_tree base_type; + base_type tree_; + +public: + // 使用 rb_tree 定义的型别 + typedef typename base_type::node_type node_type; + typedef typename base_type::const_pointer pointer; + typedef typename base_type::const_pointer const_pointer; + typedef typename base_type::const_reference reference; + typedef typename base_type::const_reference const_reference; + typedef typename base_type::const_iterator iterator; + typedef typename base_type::const_iterator const_iterator; + typedef typename base_type::const_reverse_iterator reverse_iterator; + typedef typename base_type::const_reverse_iterator const_reverse_iterator; + typedef typename base_type::size_type size_type; + typedef typename base_type::difference_type difference_type; + typedef typename base_type::allocator_type allocator_type; + +public: + // 构造、复制、移动函数 + set() = default; + + template + set(InputIterator first, InputIterator last) + :tree_() + { tree_.insert_unique(first, last); } + set(std::initializer_list ilist) + :tree_() + { tree_.insert_unique(ilist.begin(), ilist.end()); } + + set(const set& rhs) + :tree_(rhs.tree_) + { + } + set(set&& rhs) noexcept + :tree_(mystl::move(rhs.tree_)) + { + } + + set& operator=(const set& rhs) + { + tree_ = rhs.tree_; + return *this; + } + set& operator=(set&& rhs) + { + tree_ = mystl::move(rhs.tree_); + return *this; + } + set& operator=(std::initializer_list ilist) + { + tree_.clear(); + tree_.insert_unique(ilist.begin(), ilist.end()); + return *this; + } + + // 相关接口 + + key_compare key_comp() const { return tree_.key_comp(); } + value_compare value_comp() const { return tree_.key_comp(); } + allocator_type get_allocator() const { return tree_.get_allocator(); } + + // 迭代器相关 + + iterator begin() noexcept + { return tree_.begin(); } + const_iterator begin() const noexcept + { return tree_.begin(); } + iterator end() noexcept + { return tree_.end(); } + const_iterator end() const noexcept + { return tree_.end(); } + + reverse_iterator rbegin() noexcept + { return reverse_iterator(end()); } + const_reverse_iterator rbegin() const noexcept + { return const_reverse_iterator(end()); } + reverse_iterator rend() noexcept + { return reverse_iterator(begin()); } + const_reverse_iterator rend() const noexcept + { return const_reverse_iterator(begin()); } + + const_iterator cbegin() const noexcept + { return begin(); } + const_iterator cend() const noexcept + { return end(); } + const_reverse_iterator crbegin() const noexcept + { return rbegin(); } + const_reverse_iterator crend() const noexcept + { return rend(); } + + // 容量相关 + bool empty() const noexcept { return tree_.empty(); } + size_type size() const noexcept { return tree_.size(); } + size_type max_size() const noexcept { return tree_.max_size(); } + + // 插入删除操作 + + template + pair emplace(Args&& ...args) + { + return tree_.emplace_unique(mystl::forward(args)...); + } + + template + iterator emplace_hint(iterator hint, Args&& ...args) + { + return tree_.emplace_unique_use_hint(hint, mystl::forward(args)...); + } + + pair insert(const value_type& value) + { + return tree_.insert_unique(value); + } + pair insert(value_type&& value) + { + return tree_.insert_unique(mystl::move(value)); + } + + iterator insert(iterator hint, const value_type& value) + { + return tree_.insert_unique(hint, value); + } + iterator insert(iterator hint, value_type&& value) + { + return tree_.insert_unique(hint, mystl::move(value)); + } + + template + void insert(InputIterator first, InputIterator last) + { + tree_.insert_unique(first, last); + } + + void erase(iterator position) { tree_.erase(position); } + size_type erase(const key_type& key) { return tree_.erase_unique(key); } + void erase(iterator first, iterator last) { tree_.erase(first, last); } + + void clear() { tree_.clear(); } + + // set 相关操作 + + iterator find(const key_type& key) { return tree_.find(key); } + const_iterator find(const key_type& key) const { return tree_.find(key); } + + size_type count(const key_type& key) const { return tree_.count_unique(key); } + + iterator lower_bound(const key_type& key) { return tree_.lower_bound(key); } + const_iterator lower_bound(const key_type& key) const { return tree_.lower_bound(key); } + + iterator upper_bound(const key_type& key) { return tree_.upper_bound(key); } + const_iterator upper_bound(const key_type& key) const { return tree_.upper_bound(key); } + + pair + equal_range(const key_type& key) + { return tree_.equal_range_unique(key); } + + pair + equal_range(const key_type& key) const + { return tree_.equal_range_unique(key); } + + void swap(set& rhs) noexcept + { tree_.swap(rhs.tree_); } + +public: + friend bool operator==(const set& lhs, const set& rhs) { return lhs.tree_ == rhs.tree_; } + friend bool operator< (const set& lhs, const set& rhs) { return lhs.tree_ < rhs.tree_; } +}; + +// 重载比较操作符 +template +bool operator==(const set& lhs, const set& rhs) +{ + return lhs == rhs; +} + +template +bool operator<(const set& lhs, const set& rhs) +{ + return lhs < rhs; +} + +template +bool operator!=(const set& lhs, const set& rhs) +{ + return !(lhs == rhs); +} + +template +bool operator>(const set& lhs, const set& rhs) +{ + return rhs < lhs; +} + +template +bool operator<=(const set& lhs, const set& rhs) +{ + return !(rhs < lhs); +} + +template +bool operator>=(const set& lhs, const set& rhs) +{ + return !(lhs < rhs); +} + +// 重载 mystl 的 swap +template +void swap(set& lhs, set& rhs) noexcept +{ + lhs.swap(rhs); +} + +/*****************************************************************************************/ + +// 模板类 multiset,键值允许重复 +// 参数一代表键值类型,参数二代表键值比较方式,缺省使用 mystl::less +template > +class multiset +{ +public: + typedef Key key_type; + typedef Key value_type; + typedef Compare key_compare; + typedef Compare value_compare; + +private: + // 以 mystl::rb_tree 作为底层机制 + typedef mystl::rb_tree base_type; + base_type tree_; // 以 rb_tree 表现 multiset + +public: + // 使用 rb_tree 定义的型别 + typedef typename base_type::node_type node_type; + typedef typename base_type::const_pointer pointer; + typedef typename base_type::const_pointer const_pointer; + typedef typename base_type::const_reference reference; + typedef typename base_type::const_reference const_reference; + typedef typename base_type::const_iterator iterator; + typedef typename base_type::const_iterator const_iterator; + typedef typename base_type::const_reverse_iterator reverse_iterator; + typedef typename base_type::const_reverse_iterator const_reverse_iterator; + typedef typename base_type::size_type size_type; + typedef typename base_type::difference_type difference_type; + typedef typename base_type::allocator_type allocator_type; + +public: + // 构造、复制、移动函数 + multiset() = default; + + template + multiset(InputIterator first, InputIterator last) + :tree_() + { tree_.insert_multi(first, last); } + multiset(std::initializer_list ilist) + :tree_() + { tree_.insert_multi(ilist.begin(), ilist.end()); } + + multiset(const multiset& rhs) + :tree_(rhs.tree_) + { + } + multiset(multiset&& rhs) noexcept + :tree_(mystl::move(rhs.tree_)) + { + } + + multiset& operator=(const multiset& rhs) + { + tree_ = rhs.tree_; + return *this; + } + multiset& operator=(multiset&& rhs) + { + tree_ = mystl::move(rhs.tree_); + return *this; + } + multiset& operator=(std::initializer_list ilist) + { + tree_.clear(); + tree_.insert_multi(ilist.begin(), ilist.end()); + return *this; + } + + // 相关接口 + + key_compare key_comp() const { return tree_.key_comp(); } + value_compare value_comp() const { return tree_.key_comp(); } + allocator_type get_allocator() const { return tree_.get_allocator(); } + + // 迭代器相关 + + iterator begin() noexcept + { return tree_.begin(); } + const_iterator begin() const noexcept + { return tree_.begin(); } + iterator end() noexcept + { return tree_.end(); } + const_iterator end() const noexcept + { return tree_.end(); } + + reverse_iterator rbegin() noexcept + { return reverse_iterator(end()); } + const_reverse_iterator rbegin() const noexcept + { return const_reverse_iterator(end()); } + reverse_iterator rend() noexcept + { return reverse_iterator(begin()); } + const_reverse_iterator rend() const noexcept + { return const_reverse_iterator(begin()); } + + const_iterator cbegin() const noexcept + { return begin(); } + const_iterator cend() const noexcept + { return end(); } + const_reverse_iterator crbegin() const noexcept + { return rbegin(); } + const_reverse_iterator crend() const noexcept + { return rend(); } + + // 容量相关 + bool empty() const noexcept { return tree_.empty(); } + size_type size() const noexcept { return tree_.size(); } + size_type max_size() const noexcept { return tree_.max_size(); } + + // 插入删除操作 + + template + iterator emplace(Args&& ...args) + { + return tree_.emplace_multi(mystl::forward(args)...); + } + + template + iterator emplace_hint(iterator hint, Args&& ...args) + { + return tree_.emplace_multi_use_hint(hint, mystl::forward(args)...); + } + + iterator insert(const value_type& value) + { + return tree_.insert_multi(value); + } + iterator insert(value_type&& value) + { + return tree_.insert_multi(mystl::move(value)); + } + + iterator insert(iterator hint, const value_type& value) + { + return tree_.insert_multi(hint, value); + } + iterator insert(iterator hint, value_type&& value) + { + return tree_.insert_multi(hint, mystl::move(value)); + } + + template + void insert(InputIterator first, InputIterator last) + { + tree_.insert_multi(first, last); + } + + void erase(iterator position) { tree_.erase(position); } + size_type erase(const key_type& key) { return tree_.erase_multi(key); } + void erase(iterator first, iterator last) { tree_.erase(first, last); } + + void clear() { tree_.clear(); } + + // multiset 相关操作 + + iterator find(const key_type& key) { return tree_.find(key); } + const_iterator find(const key_type& key) const { return tree_.find(key); } + + size_type count(const key_type& key) const { return tree_.count_multi(key); } + + iterator lower_bound(const key_type& key) { return tree_.lower_bound(key); } + const_iterator lower_bound(const key_type& key) const { return tree_.lower_bound(key); } + + iterator upper_bound(const key_type& key) { return tree_.upper_bound(key); } + const_iterator upper_bound(const key_type& key) const { return tree_.upper_bound(key); } + + pair + equal_range(const key_type& key) + { return tree_.equal_range_multi(key); } + + pair + equal_range(const key_type& key) const + { return tree_.equal_range_multi(key); } + + void swap(multiset& rhs) noexcept + { tree_.swap(rhs.tree_); } + +public: + friend bool operator==(const multiset& lhs, const multiset& rhs) { return lhs.tree_ == rhs.tree_; } + friend bool operator< (const multiset& lhs, const multiset& rhs) { return lhs.tree_ < rhs.tree_; } +}; + +// 重载比较操作符 +template +bool operator==(const multiset& lhs, const multiset& rhs) +{ + return lhs == rhs; +} + +template +bool operator<(const multiset& lhs, const multiset& rhs) +{ + return lhs < rhs; +} + +template +bool operator!=(const multiset& lhs, const multiset& rhs) +{ + return !(lhs == rhs); +} + +template +bool operator>(const multiset& lhs, const multiset& rhs) +{ + return rhs < lhs; +} + +template +bool operator<=(const multiset& lhs, const multiset& rhs) +{ + return !(rhs < lhs); +} + +template +bool operator>=(const multiset& lhs, const multiset& rhs) +{ + return !(lhs < rhs); +} + +// 重载 mystl 的 swap +template +void swap(multiset& lhs, multiset& rhs) noexcept +{ + lhs.swap(rhs); +} + +} // namespace mystl +#endif // !MYTINYSTL_SET_H_ + diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/set_algo.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/set_algo.h new file mode 100644 index 0000000..8abc16d --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/set_algo.h @@ -0,0 +1,253 @@ +#ifndef MYTINYSTL_SET_ALGO_H_ +#define MYTINYSTL_SET_ALGO_H_ + +// 这个头文件包含 set 的四种算法: union, intersection, difference, symmetric_difference +// 所有函数都要求序列有序 + +#include "algobase.h" +#include "iterator.h" + +namespace mystl +{ + +/*****************************************************************************************/ +// set_union +// 计算 S1∪S2 的结果并保存到 result 中,返回一个迭代器指向输出结果的尾部 +/*****************************************************************************************/ +template +OutputIter set_union(InputIter1 first1, InputIter1 last1, + InputIter2 first2, InputIter2 last2, + OutputIter result) +{ + while (first1 != last1 && first2 != last2) + { + if (*first1 < *first2) + { + *result = *first1; + ++first1; + } + else if (*first2 < *first1) + { + *result = *first2; + ++first2; + } + else + { + *result = *first1; + ++first1; + ++first2; + } + ++result; + } + // 将剩余元素拷贝到 result + return mystl::copy(first2, last2, mystl::copy(first1, last1, result)); +} + +// 重载版本使用函数对象 comp 代替比较操作 +template +OutputIter set_union(InputIter1 first1, InputIter1 last1, + InputIter2 first2, InputIter2 last2, + OutputIter result, Compared comp) +{ + while (first1 != last1 && first2 != last2) + { + if (comp(*first1, *first2)) + { + *result = *first1; + ++first1; + } + else if (comp(*first2, *first1)) + { + *result = *first2; + ++first2; + } + else + { + *result = *first1; + ++first1; + ++first2; + } + ++result; + } + // 将剩余元素拷贝到 result + return mystl::copy(first2, last2, mystl::copy(first1, last1, result)); +} + +/*****************************************************************************************/ +// set_intersection +// 计算 S1∩S2 的结果并保存到 result 中,返回一个迭代器指向输出结果的尾部 +/*****************************************************************************************/ +template +OutputIter set_intersection(InputIter1 first1, InputIter1 last1, + InputIter2 first2, InputIter2 last2, + OutputIter result) +{ + while (first1 != last1 && first2 != last2) + { + if (*first1 < *first2) + { + ++first1; + } + else if (*first2 < *first1) + { + ++first2; + } + else + { + *result = *first1; + ++first1; + ++first2; + ++result; + } + } + return result; +} + +// 重载版本使用函数对象 comp 代替比较操作 +template +OutputIter set_intersection(InputIter1 first1, InputIter1 last1, + InputIter2 first2, InputIter2 last2, + OutputIter result, Compared comp) +{ + while (first1 != last1 && first2 != last2) + { + if (comp(*first1, *first2)) + { + ++first1; + } + else if (comp(*first2, *first1)) + { + ++first2; + } + else + { + *result = *first1; + ++first1; + ++first2; + ++result; + } + } + return result; +} + +/*****************************************************************************************/ +// set_difference +// 计算 S1-S2 的结果并保存到 result 中,返回一个迭代器指向输出结果的尾部 +/*****************************************************************************************/ +template +OutputIter set_difference(InputIter1 first1, InputIter1 last1, + InputIter2 first2, InputIter2 last2, + OutputIter result) +{ + while (first1 != last1 && first2 != last2) + { + if (*first1 < *first2) + { + *result = *first1; + ++first1; + ++result; + } + else if (*first2 < *first1) + { + ++first2; + } + else + { + ++first1; + ++first2; + } + } + return mystl::copy(first1, last1, result); +} + +// 重载版本使用函数对象 comp 代替比较操作 +template +OutputIter set_difference(InputIter1 first1, InputIter1 last1, + InputIter2 first2, InputIter2 last2, + OutputIter result, Compared comp) +{ + while (first1 != last1 && first2 != last2) + { + if (comp(*first1, *first2)) + { + *result = *first1; + ++first1; + ++result; + } + else if (comp(*first2, *first1)) + { + ++first2; + } + else + { + ++first1; + ++first2; + } + } + return mystl::copy(first1, last1, result); +} + +/*****************************************************************************************/ +// set_symmetric_difference +// 计算 (S1-S2)∪(S2-S1) 的结果并保存到 result 中,返回一个迭代器指向输出结果的尾部 +/*****************************************************************************************/ +template +OutputIter set_symmetric_difference(InputIter1 first1, InputIter1 last1, + InputIter2 first2, InputIter2 last2, + OutputIter result) +{ + while (first1 != last1 && first2 != last2) + { + if (*first1 < *first2) + { + *result = *first1; + ++first1; + ++result; + } + else if (*first2 < *first1) + { + *result = *first2; + ++first2; + ++result; + } + else + { + ++first1; + ++first2; + } + } + return mystl::copy(first2, last2, mystl::copy(first1, last1, result)); +} + +// 重载版本使用函数对象 comp 代替比较操作 +template +OutputIter set_symmetric_difference(InputIter1 first1, InputIter1 last1, + InputIter2 first2, InputIter2 last2, + OutputIter result, Compared comp) +{ + while (first1 != last1 && first2 != last2) + { + if (comp(*first1, *first2)) + { + *result = *first1; + ++first1; + ++result; + } + else if (comp(*first2, *first1)) + { + *result = *first2; + ++first2; + ++result; + } + else + { + ++first1; + ++first2; + } + } + return mystl::copy(first2, last2, mystl::copy(first1, last1, result)); +} + +} // namespace mystl +#endif // !MYTINYSTL_SET_ALGO_H_ + diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/stack.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/stack.h new file mode 100644 index 0000000..39cb284 --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/stack.h @@ -0,0 +1,173 @@ +#ifndef MYTINYSTL_STACK_H_ +#define MYTINYSTL_STACK_H_ +//这是个头文件 +// 这个头文件包含了一个模板类 stack +// stack : 栈 + +#include "deque.h" + +namespace mystl +{ + +// 模板类 stack +// 参数一代表数据类型,参数二代表底层容器类型,缺省使用 mystl::deque 作为底层容器 +template > +class stack +{ +public: + typedef Container container_type; + // 使用底层容器的型别 + typedef typename Container::value_type value_type; + typedef typename Container::size_type size_type; + typedef typename Container::reference reference; + typedef typename Container::const_reference const_reference; + + static_assert(std::is_same::value, + "the value_type of Container should be same with T"); +private: + container_type c_; // 用底层容器表现 stack + +public: + // 构造、复制、移动函数 + stack() = default; + + explicit stack(size_type n) + :c_(n) + { + } + stack(size_type n, const value_type& value) + :c_(n, value) + { + } + + template + stack(IIter first, IIter last) + : c_(first, last) + { + } + + stack(std::initializer_list ilist) + :c_(ilist.begin(), ilist.end()) + { + } + + stack(const Container& c) + :c_(c) + { + } + stack(Container&& c) noexcept(std::is_nothrow_move_constructible::value) + :c_(mystl::move(c)) + { + } + + stack(const stack& rhs) + :c_(rhs.c_) + { + } + stack(stack&& rhs) noexcept(std::is_nothrow_move_constructible::value) + :c_(mystl::move(rhs.c_)) + { + } + + stack& operator=(const stack& rhs) + { + c_ = rhs.c_; + return *this; + } + stack& operator=(stack&& rhs) noexcept(std::is_nothrow_move_assignable::value) + { + c_ = mystl::move(rhs.c_); + return *this; + } + + stack& operator=(std::initializer_list ilist) + { + c_ = ilist; + return *this; + } + + ~stack() = default; + + // 访问元素相关操作 + reference top() { return c_.back(); } + const_reference top() const { return c_.back(); } + + // 容量相关操作 + bool empty() const noexcept { return c_.empty(); } + size_type size() const noexcept { return c_.size(); } + + // 修改容器相关操作 + + template + void emplace(Args&& ...args) + { c_.emplace_back(mystl::forward(args)...); } + + void push(const value_type& value) + { c_.push_back(value); } + void push(value_type&& value) + { c_.push_back(mystl::move(value)); } + + void pop() + { c_.pop_back(); } + + void clear() + { + while (!empty()) + pop(); + } + + void swap(stack& rhs) noexcept(noexcept(mystl::swap(c_, rhs.c_))) + { mystl::swap(c_, rhs.c_); } + +public: + friend bool operator==(const stack& lhs, const stack& rhs) { return lhs.c_ == rhs.c_; } + friend bool operator< (const stack& lhs, const stack& rhs) { return lhs.c_ < rhs.c_; } +}; + +// 重载比较操作符 +template +bool operator==(const stack& lhs, const stack& rhs) +{ + return lhs == rhs; +} + +template +bool operator<(const stack& lhs, const stack& rhs) +{ + return lhs < rhs; +} + +template +bool operator!=(const stack& lhs, const stack& rhs) +{ + return !(lhs == rhs); +} + +template +bool operator>(const stack& lhs, const stack& rhs) +{ + return rhs < lhs; +} + +template +bool operator<=(const stack& lhs, const stack& rhs) +{ + return !(rhs < lhs); +} + +template +bool operator>=(const stack& lhs, const stack& rhs) +{ + return !(lhs < rhs); +} + +// 重载 mystl 的 swap +template +void swap(stack& lhs, stack& rhs) noexcept(noexcept(lhs.swap(rhs))) +{ + lhs.swap(rhs); +} + +} // namespace mystl +#endif // !MYTINYSTL_STACK_H_ + diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/type_traits.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/type_traits.h new file mode 100644 index 0000000..69d35ec --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/type_traits.h @@ -0,0 +1,45 @@ +#ifndef MYTINYSTL_TYPE_TRAITS_H_ +#define MYTINYSTL_TYPE_TRAITS_H_ + +// 这个头文件用于提取类型信息 + +// use standard header for type_traits +#include + +namespace mystl +{ + +// helper struct + +template +struct m_integral_constant +{ + static constexpr T value = v; +}; + +template +using m_bool_constant = m_integral_constant; + +typedef m_bool_constant m_true_type; +typedef m_bool_constant m_false_type; + +/*****************************************************************************************/ +// type traits + +// is_pair + +// --- forward declaration begin +template +struct pair; +// --- forward declaration end + +template +struct is_pair : mystl::m_false_type {}; + +template +struct is_pair> : mystl::m_true_type {}; + +} // namespace mystl + +#endif // !MYTINYSTL_TYPE_TRAITS_H_ + diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/uninitialized.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/uninitialized.h new file mode 100644 index 0000000..910196e --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/uninitialized.h @@ -0,0 +1,256 @@ +#ifndef MYTINYSTL_UNINITIALIZED_H_ +#define MYTINYSTL_UNINITIALIZED_H_ + +// 这个头文件用于对未初始化空间构造元素 + +#include "algobase.h" +#include "construct.h" +#include "iterator.h" +#include "type_traits.h" +#include "util.h" + +namespace mystl +{ + +/*****************************************************************************************/ +// uninitialized_copy +// 把 [first, last) 上的内容复制到以 result 为起始处的空间,返回复制结束的位置 +/*****************************************************************************************/ +template +ForwardIter +unchecked_uninit_copy(InputIter first, InputIter last, ForwardIter result, std::true_type) +{ + return mystl::copy(first, last, result); +} + +template +ForwardIter +unchecked_uninit_copy(InputIter first, InputIter last, ForwardIter result, std::false_type) +{ + auto cur = result; + try + { + for (; first != last; ++first, ++cur) + { + mystl::construct(&*cur, *first); + } + } + catch (...) + { + for (; result != cur; --cur) + mystl::destroy(&*cur); + } + return cur; +} + +template +ForwardIter uninitialized_copy(InputIter first, InputIter last, ForwardIter result) +{ + return mystl::unchecked_uninit_copy(first, last, result, + std::is_trivially_copy_assignable< + typename iterator_traits:: + value_type>{}); +} + +/*****************************************************************************************/ +// uninitialized_copy_n +// 把 [first, first + n) 上的内容复制到以 result 为起始处的空间,返回复制结束的位置 +/*****************************************************************************************/ +template +ForwardIter +unchecked_uninit_copy_n(InputIter first, Size n, ForwardIter result, std::true_type) +{ + return mystl::copy_n(first, n, result).second; +} + +template +ForwardIter +unchecked_uninit_copy_n(InputIter first, Size n, ForwardIter result, std::false_type) +{ + auto cur = result; + try + { + for (; n > 0; --n, ++cur, ++first) + { + mystl::construct(&*cur, *first); + } + } + catch (...) + { + for (; result != cur; --cur) + mystl::destroy(&*cur); + } + return cur; +} + +template +ForwardIter uninitialized_copy_n(InputIter first, Size n, ForwardIter result) +{ + return mystl::unchecked_uninit_copy_n(first, n, result, + std::is_trivially_copy_assignable< + typename iterator_traits:: + value_type>{}); +} + +/*****************************************************************************************/ +// uninitialized_fill +// 在 [first, last) 区间内填充元素值 +/*****************************************************************************************/ +template +void +unchecked_uninit_fill(ForwardIter first, ForwardIter last, const T& value, std::true_type) +{ + mystl::fill(first, last, value); +} + +template +void +unchecked_uninit_fill(ForwardIter first, ForwardIter last, const T& value, std::false_type) +{ + auto cur = first; + try + { + for (; cur != last; ++cur) + { + mystl::construct(&*cur, value); + } + } + catch (...) + { + for (;first != cur; ++first) + mystl::destroy(&*first); + } +} + +template +void uninitialized_fill(ForwardIter first, ForwardIter last, const T& value) +{ + mystl::unchecked_uninit_fill(first, last, value, + std::is_trivially_copy_assignable< + typename iterator_traits:: + value_type>{}); +} + +/*****************************************************************************************/ +// uninitialized_fill_n +// 从 first 位置开始,填充 n 个元素值,返回填充结束的位置 +/*****************************************************************************************/ +template +ForwardIter +unchecked_uninit_fill_n(ForwardIter first, Size n, const T& value, std::true_type) +{ + return mystl::fill_n(first, n, value); +} + +template +ForwardIter +unchecked_uninit_fill_n(ForwardIter first, Size n, const T& value, std::false_type) +{ + auto cur = first; + try + { + for (; n > 0; --n, ++cur) + { + mystl::construct(&*cur, value); + } + } + catch (...) + { + for (; first != cur; ++first) + mystl::destroy(&*first); + } + return cur; +} + +template +ForwardIter uninitialized_fill_n(ForwardIter first, Size n, const T& value) +{ + return mystl::unchecked_uninit_fill_n(first, n, value, + std::is_trivially_copy_assignable< + typename iterator_traits:: + value_type>{}); +} + +/*****************************************************************************************/ +// uninitialized_move +// 把[first, last)上的内容移动到以 result 为起始处的空间,返回移动结束的位置 +/*****************************************************************************************/ +template +ForwardIter +unchecked_uninit_move(InputIter first, InputIter last, ForwardIter result, std::true_type) +{ + return mystl::move(first, last, result); +} + +template +ForwardIter +unchecked_uninit_move(InputIter first, InputIter last, ForwardIter result, std::false_type) +{ + ForwardIter cur = result; + try + { + for (; first != last; ++first, ++cur) + { + mystl::construct(&*cur, mystl::move(*first)); + } + } + catch (...) + { + mystl::destroy(result, cur); + } + return cur; +} + +template +ForwardIter uninitialized_move(InputIter first, InputIter last, ForwardIter result) +{ + return mystl::unchecked_uninit_move(first, last, result, + std::is_trivially_move_assignable< + typename iterator_traits:: + value_type>{}); +} + +/*****************************************************************************************/ +// uninitialized_move_n +// 把[first, first + n)上的内容移动到以 result 为起始处的空间,返回移动结束的位置 +/*****************************************************************************************/ +template +ForwardIter +unchecked_uninit_move_n(InputIter first, Size n, ForwardIter result, std::true_type) +{ + return mystl::move(first, first + n, result); +} + +template +ForwardIter +unchecked_uninit_move_n(InputIter first, Size n, ForwardIter result, std::false_type) +{ + auto cur = result; + try + { + for (; n > 0; --n, ++first, ++cur) + { + mystl::construct(&*cur, mystl::move(*first)); + } + } + catch (...) + { + for (; result != cur; ++result) + mystl::destroy(&*result); + throw; + } + return cur; +} + +template +ForwardIter uninitialized_move_n(InputIter first, Size n, ForwardIter result) +{ + return mystl::unchecked_uninit_move_n(first, n, result, + std::is_trivially_move_assignable< + typename iterator_traits:: + value_type>{}); +} + +} // namespace mystl +#endif // !MYTINYSTL_UNINITIALIZED_H_ + diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/unordered_map.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/unordered_map.h new file mode 100644 index 0000000..5838a21 --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/unordered_map.h @@ -0,0 +1,563 @@ +#ifndef MYTINYSTL_UNORDERED_MAP_H_ +#define MYTINYSTL_UNORDERED_MAP_H_ + +// 这个头文件包含两个模板类 unordered_map 和 unordered_multimap +// 功能与用法与 map 和 multimap 类似,不同的是使用 hashtable 作为底层实现机制,容器内的元素不会自动排序 + +// notes: +// +// 异常保证: +// mystl::unordered_map / mystl::unordered_multimap 满足基本异常保证,对以下等函数做强异常安全保证: +// * emplace +// * emplace_hint +// * insert + +#include "hashtable.h" + +namespace mystl +{ + +// 模板类 unordered_map,键值不允许重复 +// 参数一代表键值类型,参数二代表实值类型,参数三代表哈希函数,缺省使用 mystl::hash +// 参数四代表键值比较方式,缺省使用 mystl::equal_to +template , class KeyEqual = mystl::equal_to> +class unordered_map +{ +private: + // 使用 hashtable 作为底层机制 + typedef hashtable, Hash, KeyEqual> base_type; + base_type ht_; + +public: + // 使用 hashtable 的型别 + + typedef typename base_type::allocator_type allocator_type; + typedef typename base_type::key_type key_type; + typedef typename base_type::mapped_type mapped_type; + typedef typename base_type::value_type value_type; + typedef typename base_type::hasher hasher; + typedef typename base_type::key_equal key_equal; + + typedef typename base_type::size_type size_type; + typedef typename base_type::difference_type difference_type; + typedef typename base_type::pointer pointer; + typedef typename base_type::const_pointer const_pointer; + typedef typename base_type::reference reference; + typedef typename base_type::const_reference const_reference; + + typedef typename base_type::iterator iterator; + typedef typename base_type::const_iterator const_iterator; + typedef typename base_type::local_iterator local_iterator; + typedef typename base_type::const_local_iterator const_local_iterator; + + allocator_type get_allocator() const { return ht_.get_allocator(); } + +public: + // 构造、复制、移动、析构函数 + + unordered_map() + :ht_(100, Hash(), KeyEqual()) + { + } + + explicit unordered_map(size_type bucket_count, + const Hash& hash = Hash(), + const KeyEqual& equal = KeyEqual()) + :ht_(bucket_count, hash, equal) + { + } + + template + unordered_map(InputIterator first, InputIterator last, + const size_type bucket_count = 100, + const Hash& hash = Hash(), + const KeyEqual& equal = KeyEqual()) + : ht_(mystl::max(bucket_count, static_cast(mystl::distance(first, last))), hash, equal) + { + for (; first != last; ++first) + ht_.insert_unique_noresize(*first); + } + + unordered_map(std::initializer_list ilist, + const size_type bucket_count = 100, + const Hash& hash = Hash(), + const KeyEqual& equal = KeyEqual()) + :ht_(mystl::max(bucket_count, static_cast(ilist.size())), hash, equal) + { + for (auto first = ilist.begin(), last = ilist.end(); first != last; ++first) + ht_.insert_unique_noresize(*first); + } + + unordered_map(const unordered_map& rhs) + :ht_(rhs.ht_) + { + } + unordered_map(unordered_map&& rhs) noexcept + :ht_(mystl::move(rhs.ht_)) + { + } + + unordered_map& operator=(const unordered_map& rhs) + { + ht_ = rhs.ht_; + return *this; + } + unordered_map& operator=(unordered_map&& rhs) + { + ht_ = mystl::move(rhs.ht_); + return *this; + } + + unordered_map& operator=(std::initializer_list ilist) + { + ht_.clear(); + ht_.reserve(ilist.size()); + for (auto first = ilist.begin(), last = ilist.end(); first != last; ++first) + ht_.insert_unique_noresize(*first); + return *this; + } + + ~unordered_map() = default; + + // 迭代器相关 + + iterator begin() noexcept + { return ht_.begin(); } + const_iterator begin() const noexcept + { return ht_.begin(); } + iterator end() noexcept + { return ht_.end(); } + const_iterator end() const noexcept + { return ht_.end(); } + + const_iterator cbegin() const noexcept + { return ht_.cbegin(); } + const_iterator cend() const noexcept + { return ht_.cend(); } + + // 容量相关 + + bool empty() const noexcept { return ht_.empty(); } + size_type size() const noexcept { return ht_.size(); } + size_type max_size() const noexcept { return ht_.max_size(); } + + // 修改容器操作 + + // empalce / empalce_hint + + template + pair emplace(Args&& ...args) + { return ht_.emplace_unique(mystl::forward(args)...); } + + template + iterator emplace_hint(const_iterator hint, Args&& ...args) + { return ht_.emplace_unique_use_hint(hint, mystl::forward(args)...); } + + // insert + + pair insert(const value_type& value) + { return ht_.insert_unique(value); } + pair insert(value_type&& value) + { return ht_.emplace_unique(mystl::move(value)); } + + iterator insert(const_iterator hint, const value_type& value) + { return ht_.insert_unique_use_hint(hint, value); } + iterator insert(const_iterator hint, value_type&& value) + { return ht_.emplace_unique_use_hint(hint, mystl::move(value)); } + + template + void insert(InputIterator first, InputIterator last) + { ht_.insert_unique(first, last); } + + // erase / clear + + void erase(iterator it) + { ht_.erase(it); } + void erase(iterator first, iterator last) + { ht_.erase(first, last); } + + size_type erase(const key_type& key) + { return ht_.erase_unique(key); } + + void clear() + { ht_.clear(); } + + void swap(unordered_map& other) noexcept + { ht_.swap(other.ht_); } + + // 查找相关 + + mapped_type& at(const key_type& key) + { + iterator it = ht_.find(key); + THROW_OUT_OF_RANGE_IF(it.node == nullptr, "unordered_map no such element exists"); + return it->second; + } + const mapped_type& at(const key_type& key) const + { + iterator it = ht_.find(key); + THROW_OUT_OF_RANGE_IF(it.node == nullptr, "unordered_map no such element exists"); + return it->second; + } + + mapped_type& operator[](const key_type& key) + { + iterator it = ht_.find(key); + if (it.node == nullptr) + it = ht_.emplace_unique(key, T{}).first; + return it->second; + } + mapped_type& operator[](key_type&& key) + { + iterator it = ht_.find(key); + if (it.node == nullptr) + it = ht_.emplace_unique(mystl::move(key), T{}).first; + return it->second; + } + + size_type count(const key_type& key) const + { return ht_.count(key); } + + iterator find(const key_type& key) + { return ht_.find(key); } + const_iterator find(const key_type& key) const + { return ht_.find(key); } + + pair equal_range(const key_type& key) + { return ht_.equal_range_unique(key); } + pair equal_range(const key_type& key) const + { return ht_.equal_range_unique(key); } + + // bucket interface + + local_iterator begin(size_type n) noexcept + { return ht_.begin(n); } + const_local_iterator begin(size_type n) const noexcept + { return ht_.begin(n); } + const_local_iterator cbegin(size_type n) const noexcept + { return ht_.cbegin(n); } + + local_iterator end(size_type n) noexcept + { return ht_.end(n); } + const_local_iterator end(size_type n) const noexcept + { return ht_.end(n); } + const_local_iterator cend(size_type n) const noexcept + { return ht_.cend(n); } + + size_type bucket_count() const noexcept + { return ht_.bucket_count(); } + size_type max_bucket_count() const noexcept + { return ht_.max_bucket_count(); } + + size_type bucket_size(size_type n) const noexcept + { return ht_.bucket_size(n); } + size_type bucket(const key_type& key) const + { return ht_.bucket(key); } + + // hash policy + + float load_factor() const noexcept { return ht_.load_factor(); } + + float max_load_factor() const noexcept { return ht_.max_load_factor(); } + void max_load_factor(float ml) { ht_.max_load_factor(ml); } + + void rehash(size_type count) { ht_.rehash(count); } + void reserve(size_type count) { ht_.reserve(count); } + + hasher hash_fcn() const { return ht_.hash_fcn(); } + key_equal key_eq() const { return ht_.key_eq(); } + +public: + friend bool operator==(const unordered_map& lhs, const unordered_map& rhs) + { + return lhs.ht_.equal_range_unique(rhs.ht_); + } + friend bool operator!=(const unordered_map& lhs, const unordered_map& rhs) + { + return !lhs.ht_.equal_range_unique(rhs.ht_); + } +}; + +// 重载比较操作符 +template +bool operator==(const unordered_map& lhs, + const unordered_map& rhs) +{ + return lhs == rhs; +} + +template +bool operator!=(const unordered_map& lhs, + const unordered_map& rhs) +{ + return lhs != rhs; +} + +// 重载 mystl 的 swap +template +void swap(unordered_map& lhs, + unordered_map& rhs) +{ + lhs.swap(rhs); +} + +/*****************************************************************************************/ + +// 模板类 unordered_multimap,键值允许重复 +// 参数一代表键值类型,参数二代表实值类型,参数三代表哈希函数,缺省使用 mystl::hash +// 参数四代表键值比较方式,缺省使用 mystl::equal_to +template , class KeyEqual = mystl::equal_to> +class unordered_multimap +{ +private: + // 使用 hashtable 作为底层机制 + typedef hashtable, Hash, KeyEqual> base_type; + base_type ht_; + +public: + // 使用 hashtable 的型别 + typedef typename base_type::allocator_type allocator_type; + typedef typename base_type::key_type key_type; + typedef typename base_type::mapped_type mapped_type; + typedef typename base_type::value_type value_type; + typedef typename base_type::hasher hasher; + typedef typename base_type::key_equal key_equal; + + typedef typename base_type::size_type size_type; + typedef typename base_type::difference_type difference_type; + typedef typename base_type::pointer pointer; + typedef typename base_type::const_pointer const_pointer; + typedef typename base_type::reference reference; + typedef typename base_type::const_reference const_reference; + + typedef typename base_type::iterator iterator; + typedef typename base_type::const_iterator const_iterator; + typedef typename base_type::local_iterator local_iterator; + typedef typename base_type::const_local_iterator const_local_iterator; + + allocator_type get_allocator() const { return ht_.get_allocator(); } + +public: + // 构造、复制、移动函数 + + unordered_multimap() + :ht_(100, Hash(), KeyEqual()) + { + } + + explicit unordered_multimap(size_type bucket_count, + const Hash& hash = Hash(), + const KeyEqual& equal = KeyEqual()) + :ht_(bucket_count, hash, equal) + { + } + + template + unordered_multimap(InputIterator first, InputIterator last, + const size_type bucket_count = 100, + const Hash& hash = Hash(), + const KeyEqual& equal = KeyEqual()) + :ht_(mystl::max(bucket_count, static_cast(mystl::distance(first, last))), hash, equal) + { + for (; first != last; ++first) + ht_.insert_multi_noresize(*first); + } + + unordered_multimap(std::initializer_list ilist, + const size_type bucket_count = 100, + const Hash& hash = Hash(), + const KeyEqual& equal = KeyEqual()) + :ht_(mystl::max(bucket_count, static_cast(ilist.size())), hash, equal) + { + for (auto first = ilist.begin(), last = ilist.end(); first != last; ++first) + ht_.insert_multi_noresize(*first); + } + + unordered_multimap(const unordered_multimap& rhs) + :ht_(rhs.ht_) + { + } + unordered_multimap(unordered_multimap&& rhs) noexcept + :ht_(mystl::move(rhs.ht_)) + { + } + + unordered_multimap& operator=(const unordered_multimap& rhs) + { + ht_ = rhs.ht_; + return *this; + } + unordered_multimap& operator=(unordered_multimap&& rhs) + { + ht_ = mystl::move(rhs.ht_); + return *this; + } + + unordered_multimap& operator=(std::initializer_list ilist) + { + ht_.clear(); + ht_.reserve(ilist.size()); + for (auto first = ilist.begin(), last = ilist.end(); first != last; ++first) + ht_.insert_multi_noresize(*first); + return *this; + } + + ~unordered_multimap() = default; + + // 迭代器相关 + + iterator begin() noexcept + { return ht_.begin(); } + const_iterator begin() const noexcept + { return ht_.begin(); } + iterator end() noexcept + { return ht_.end(); } + const_iterator end() const noexcept + { return ht_.end(); } + + const_iterator cbegin() const noexcept + { return ht_.cbegin(); } + const_iterator cend() const noexcept + { return ht_.cend(); } + + // 容量相关 + + bool empty() const noexcept { return ht_.empty(); } + size_type size() const noexcept { return ht_.size(); } + size_type max_size() const noexcept { return ht_.max_size(); } + + // 修改容器相关 + + // emplace / emplace_hint + + template + iterator emplace(Args&& ...args) + { return ht_.emplace_multi(mystl::forward(args)...); } + + template + iterator emplace_hint(const_iterator hint, Args&& ...args) + { return ht_.emplace_multi_use_hint(hint, mystl::forward(args)...); } + + // insert + + iterator insert(const value_type& value) + { return ht_.insert_multi(value); } + iterator insert(value_type&& value) + { return ht_.emplace_multi(mystl::move(value)); } + + iterator insert(const_iterator hint, const value_type& value) + { return ht_.insert_multi_use_hint(hint, value); } + iterator insert(const_iterator hint, value_type&& value) + { return ht_.emplace_multi_use_hint(hint, mystl::move(value)); } + + template + void insert(InputIterator first, InputIterator last) + { ht_.insert_multi(first, last); } + + // erase / clear + + void erase(iterator it) + { ht_.erase(it); } + void erase(iterator first, iterator last) + { ht_.erase(first, last); } + + size_type erase(const key_type& key) + { return ht_.erase_multi(key); } + + void clear() + { ht_.clear(); } + + void swap(unordered_multimap& other) noexcept + { ht_.swap(other.ht_); } + + // 查找相关 + + size_type count(const key_type& key) const + { return ht_.count(key); } + + iterator find(const key_type& key) + { return ht_.find(key); } + const_iterator find(const key_type& key) const + { return ht_.find(key); } + + pair equal_range(const key_type& key) + { return ht_.equal_range_multi(key); } + pair equal_range(const key_type& key) const + { return ht_.equal_range_multi(key); } + + // bucket interface + + local_iterator begin(size_type n) noexcept + { return ht_.begin(n); } + const_local_iterator begin(size_type n) const noexcept + { return ht_.begin(n); } + const_local_iterator cbegin(size_type n) const noexcept + { return ht_.cbegin(n); } + + local_iterator end(size_type n) noexcept + { return ht_.end(n); } + const_local_iterator end(size_type n) const noexcept + { return ht_.end(n); } + const_local_iterator cend(size_type n) const noexcept + { return ht_.cend(n); } + + size_type bucket_count() const noexcept + { return ht_.bucket_count(); } + size_type max_bucket_count() const noexcept + { return ht_.max_bucket_count(); } + + size_type bucket_size(size_type n) const noexcept + { return ht_.bucket_size(n); } + size_type bucket(const key_type& key) const + { return ht_.bucket(key); } + + // hash policy + + float load_factor() const noexcept { return ht_.load_factor(); } + + float max_load_factor() const noexcept { return ht_.max_load_factor(); } + void max_load_factor(float ml) { ht_.max_load_factor(ml); } + + void rehash(size_type count) { ht_.rehash(count); } + void reserve(size_type count) { ht_.reserve(count); } + + hasher hash_fcn() const { return ht_.hash_fcn(); } + key_equal key_eq() const { return ht_.key_eq(); } + +public: + friend bool operator==(const unordered_multimap& lhs, const unordered_multimap& rhs) + { + return lhs.ht_.equal_range_multi(rhs.ht_); + } + friend bool operator!=(const unordered_multimap& lhs, const unordered_multimap& rhs) + { + return !lhs.ht_.equal_range_multi(rhs.ht_); + } +}; + +// 重载比较操作符 +template +bool operator==(const unordered_multimap& lhs, + const unordered_multimap& rhs) +{ + return lhs == rhs; +} + +template +bool operator!=(const unordered_multimap& lhs, + const unordered_multimap& rhs) +{ + return lhs != rhs; +} + +// 重载 mystl 的 swap +template +void swap(unordered_multimap& lhs, + unordered_multimap& rhs) +{ + lhs.swap(rhs); +} + +} // namespace mystl +#endif // !MYTINYSTL_UNORDERED_MAP_H_ + diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/unordered_set.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/unordered_set.h new file mode 100644 index 0000000..eb60589 --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/unordered_set.h @@ -0,0 +1,534 @@ +#ifndef MYTINYSTL_UNORDERED_SET_H_ +#define MYTINYSTL_UNORDERED_SET_H_ + +// 这个头文件包含两个模板类 unordered_set 和 unordered_multiset +// 功能与用法与 set 和 multiset 类似,不同的是使用 hashtable 作为底层实现机制,容器中的元素不会自动排序 + +// notes: +// +// 异常保证: +// mystl::unordered_set / mystl::unordered_multiset 满足基本异常保证,对以下等函数做强异常安全保证: +// * emplace +// * emplace_hint +// * insert + +#include "hashtable.h" + +namespace mystl +{ + +// 模板类 unordered_set,键值不允许重复 +// 参数一代表键值类型,参数二代表哈希函数,缺省使用 mystl::hash, +// 参数三代表键值比较方式,缺省使用 mystl::equal_to +template , class KeyEqual = mystl::equal_to> +class unordered_set +{ +private: + // 使用 hashtable 作为底层机制 + typedef hashtable base_type; + base_type ht_; + +public: + // 使用 hashtable 的型别 + typedef typename base_type::allocator_type allocator_type; + typedef typename base_type::key_type key_type; + typedef typename base_type::value_type value_type; + typedef typename base_type::hasher hasher; + typedef typename base_type::key_equal key_equal; + + typedef typename base_type::size_type size_type; + typedef typename base_type::difference_type difference_type; + typedef typename base_type::pointer pointer; + typedef typename base_type::const_pointer const_pointer; + typedef typename base_type::reference reference; + typedef typename base_type::const_reference const_reference; + + typedef typename base_type::const_iterator iterator; + typedef typename base_type::const_iterator const_iterator; + typedef typename base_type::const_local_iterator local_iterator; + typedef typename base_type::const_local_iterator const_local_iterator; + + allocator_type get_allocator() const { return ht_.get_allocator(); } + +public: + // 构造、复制、移动函数 + + unordered_set() + :ht_(100, Hash(), KeyEqual()) + { + } + + explicit unordered_set(size_type bucket_count, + const Hash& hash = Hash(), + const KeyEqual& equal = KeyEqual()) + :ht_(bucket_count, hash, equal) + { + } + + template + unordered_set(InputIterator first, InputIterator last, + const size_type bucket_count = 100, + const Hash& hash = Hash(), + const KeyEqual& equal = KeyEqual()) + : ht_(mystl::max(bucket_count, static_cast(mystl::distance(first, last))), hash, equal) + { + for (; first != last; ++first) + ht_.insert_unique_noresize(*first); + } + + unordered_set(std::initializer_list ilist, + const size_type bucket_count = 100, + const Hash& hash = Hash(), + const KeyEqual& equal = KeyEqual()) + :ht_(mystl::max(bucket_count, static_cast(ilist.size())), hash, equal) + { + for (auto first = ilist.begin(), last = ilist.end(); first != last; ++first) + ht_.insert_unique_noresize(*first); + } + + unordered_set(const unordered_set& rhs) + :ht_(rhs.ht_) + { + } + unordered_set(unordered_set&& rhs) noexcept + : ht_(mystl::move(rhs.ht_)) + { + } + + unordered_set& operator=(const unordered_set& rhs) + { + ht_ = rhs.ht_; + return *this; + } + unordered_set& operator=(unordered_set&& rhs) + { + ht_ = mystl::move(rhs.ht_); + return *this; + } + + unordered_set& operator=(std::initializer_list ilist) + { + ht_.clear(); + ht_.reserve(ilist.size()); + for (auto first = ilist.begin(), last = ilist.end(); first != last; ++first) + ht_.insert_unique_noresize(*first); + return *this; + } + + ~unordered_set() = default; + + // 迭代器相关 + + iterator begin() noexcept + { return ht_.begin(); } + const_iterator begin() const noexcept + { return ht_.begin(); } + iterator end() noexcept + { return ht_.end(); } + const_iterator end() const noexcept + { return ht_.end(); } + + const_iterator cbegin() const noexcept + { return ht_.cbegin(); } + const_iterator cend() const noexcept + { return ht_.cend(); } + + // 容量相关 + + bool empty() const noexcept { return ht_.empty(); } + size_type size() const noexcept { return ht_.size(); } + size_type max_size() const noexcept { return ht_.max_size(); } + + // 修改容器操作 + + // empalce / empalce_hint + + template + pair emplace(Args&& ...args) + { return ht_.emplace_unique(mystl::forward(args)...); } + + template + iterator emplace_hint(const_iterator hint, Args&& ...args) + { return ht_.emplace_unique_use_hint(hint, mystl::forward(args)...); } + + // insert + + pair insert(const value_type& value) + { return ht_.insert_unique(value); } + pair insert(value_type&& value) + { return ht_.emplace_unique(mystl::move(value)); } + + iterator insert(const_iterator hint, const value_type& value) + { return ht_.insert_unique_use_hint(hint, value); } + iterator insert(const_iterator hint, value_type&& value) + { return ht_.emplace_unique_use_hint(hint, mystl::move(value)); } + + template + void insert(InputIterator first, InputIterator last) + { ht_.insert_unique(first, last); } + + // erase / clear + + void erase(iterator it) + { ht_.erase(it); } + void erase(iterator first, iterator last) + { ht_.erase(first, last); } + + size_type erase(const key_type& key) + { return ht_.erase_unique(key); } + + void clear() + { ht_.clear(); } + + void swap(unordered_set& other) noexcept + { ht_.swap(other.ht_); } + + // 查找相关 + + size_type count(const key_type& key) const + { return ht_.count(key); } + + iterator find(const key_type& key) + { return ht_.find(key); } + const_iterator find(const key_type& key) const + { return ht_.find(key); } + + pair equal_range(const key_type& key) + { return ht_.equal_range_unique(key); } + pair equal_range(const key_type& key) const + { return ht_.equal_range_unique(key); } + + // bucket interface + + local_iterator begin(size_type n) noexcept + { return ht_.begin(n); } + const_local_iterator begin(size_type n) const noexcept + { return ht_.begin(n); } + const_local_iterator cbegin(size_type n) const noexcept + { return ht_.cbegin(n); } + + local_iterator end(size_type n) noexcept + { return ht_.end(n); } + const_local_iterator end(size_type n) const noexcept + { return ht_.end(n); } + const_local_iterator cend(size_type n) const noexcept + { return ht_.cend(n); } + + size_type bucket_count() const noexcept + { return ht_.bucket_count(); } + size_type max_bucket_count() const noexcept + { return ht_.max_bucket_count(); } + + size_type bucket_size(size_type n) const noexcept + { return ht_.bucket_size(n); } + size_type bucket(const key_type& key) const + { return ht_.bucket(key); } + + // hash policy + + float load_factor() const noexcept { return ht_.load_factor(); } + + float max_load_factor() const noexcept { return ht_.max_load_factor(); } + void max_load_factor(float ml) { ht_.max_load_factor(ml); } + + void rehash(size_type count) { ht_.rehash(count); } + void reserve(size_type count) { ht_.reserve(count); } + + hasher hash_fcn() const { return ht_.hash_fcn(); } + key_equal key_eq() const { return ht_.key_eq(); } + + +public: + friend bool operator==(const unordered_set& lhs, const unordered_set& rhs) + { + return lhs.ht_.equal_range_unique(rhs.ht_); + } + friend bool operator!=(const unordered_set& lhs, const unordered_set& rhs) + { + return !lhs.ht_.equal_range_unique(rhs.ht_); + } +}; + +// 重载比较操作符 +template +bool operator==(const unordered_set& lhs, + const unordered_set& rhs) +{ + return lhs == rhs; +} + +template +bool operator!=(const unordered_set& lhs, + const unordered_set& rhs) +{ + return lhs != rhs; +} + +// 重载 mystl 的 swap +template +void swap(unordered_set& lhs, + unordered_set& rhs) +{ + lhs.swap(rhs); +} + +/*****************************************************************************************/ + +// 模板类 unordered_multiset,键值允许重复 +// 参数一代表键值类型,参数二代表哈希函数,缺省使用 mystl::hash, +// 参数三代表键值比较方式,缺省使用 mystl::equal_to +template , class KeyEqual = mystl::equal_to> +class unordered_multiset +{ +private: + // 使用 hashtable 作为底层机制 + typedef hashtable base_type; + base_type ht_; + +public: + // 使用 hashtable 的型别 + typedef typename base_type::allocator_type allocator_type; + typedef typename base_type::key_type key_type; + typedef typename base_type::value_type value_type; + typedef typename base_type::hasher hasher; + typedef typename base_type::key_equal key_equal; + + typedef typename base_type::size_type size_type; + typedef typename base_type::difference_type difference_type; + typedef typename base_type::pointer pointer; + typedef typename base_type::const_pointer const_pointer; + typedef typename base_type::reference reference; + typedef typename base_type::const_reference const_reference; + + typedef typename base_type::const_iterator iterator; + typedef typename base_type::const_iterator const_iterator; + typedef typename base_type::const_local_iterator local_iterator; + typedef typename base_type::const_local_iterator const_local_iterator; + + allocator_type get_allocator() const { return ht_.get_allocator(); } + +public: + // 构造、复制、移动函数 + + unordered_multiset() + :ht_(100, Hash(), KeyEqual()) + { + } + + explicit unordered_multiset(size_type bucket_count, + const Hash& hash = Hash(), + const KeyEqual& equal = KeyEqual()) + :ht_(bucket_count, hash, equal) + { + } + + template + unordered_multiset(InputIterator first, InputIterator last, + const size_type bucket_count = 100, + const Hash& hash = Hash(), + const KeyEqual& equal = KeyEqual()) + : ht_(mystl::max(bucket_count, static_cast(mystl::distance(first, last))), hash, equal) + { + for (; first != last; ++first) + ht_.insert_multi_noresize(*first); + } + + unordered_multiset(std::initializer_list ilist, + const size_type bucket_count = 100, + const Hash& hash = Hash(), + const KeyEqual& equal = KeyEqual()) + :ht_(mystl::max(bucket_count, static_cast(ilist.size())), hash, equal) + { + for (auto first = ilist.begin(), last = ilist.end(); first != last; ++first) + ht_.insert_multi_noresize(*first); + } + + unordered_multiset(const unordered_multiset& rhs) + :ht_(rhs.ht_) + { + } + unordered_multiset(unordered_multiset&& rhs) noexcept + : ht_(mystl::move(rhs.ht_)) + { + } + + unordered_multiset& operator=(const unordered_multiset& rhs) + { + ht_ = rhs.ht_; + return *this; + } + unordered_multiset& operator=(unordered_multiset&& rhs) + { + ht_ = mystl::move(rhs.ht_); + return *this; + } + + unordered_multiset& operator=(std::initializer_list ilist) + { + ht_.clear(); + ht_.reserve(ilist.size()); + for (auto first = ilist.begin(), last = ilist.end(); first != last; ++first) + ht_.insert_multi_noresize(*first); + return *this; + } + + ~unordered_multiset() = default; + + + // 迭代器相关 + + iterator begin() noexcept + { return ht_.begin(); } + const_iterator begin() const noexcept + { return ht_.begin(); } + iterator end() noexcept + { return ht_.end(); } + const_iterator end() const noexcept + { return ht_.end(); } + + const_iterator cbegin() const noexcept + { return ht_.cbegin(); } + const_iterator cend() const noexcept + { return ht_.cend(); } + + // 容量相关 + + bool empty() const noexcept { return ht_.empty(); } + size_type size() const noexcept { return ht_.size(); } + size_type max_size() const noexcept { return ht_.max_size(); } + + // 修改容器相关 + + // emplace / emplace_hint + + template + iterator emplace(Args&& ...args) + { return ht_.emplace_multi(mystl::forward(args)...); } + + template + iterator emplace_hint(const_iterator hint, Args&& ...args) + { return ht_.emplace_multi_use_hint(hint, mystl::forward(args)...); } + + // insert + + iterator insert(const value_type& value) + { return ht_.insert_multi(value); } + iterator insert(value_type&& value) + { return ht_.emplace_multi(mystl::move(value)); } + + iterator insert(const_iterator hint, const value_type& value) + { return ht_.insert_multi_use_hint(hint, value); } + iterator insert(const_iterator hint, value_type&& value) + { return ht_.emplace_multi_use_hint(hint, mystl::move(value)); } + + template + void insert(InputIterator first, InputIterator last) + { ht_.insert_multi(first, last); } + + // erase / clear + + void erase(iterator it) + { ht_.erase(it); } + void erase(iterator first, iterator last) + { ht_.erase(first, last); } + + size_type erase(const key_type& key) + { return ht_.erase_multi(key); } + + void clear() + { ht_.clear(); } + + void swap(unordered_multiset& other) noexcept + { ht_.swap(other.ht_); } + + // 查找相关 + + size_type count(const key_type& key) const + { return ht_.count(key); } + + iterator find(const key_type& key) + { return ht_.find(key); } + const_iterator find(const key_type& key) const + { return ht_.find(key); } + + pair equal_range(const key_type& key) + { return ht_.equal_range_multi(key); } + pair equal_range(const key_type& key) const + { return ht_.equal_range_multi(key); } + + // bucket interface + + local_iterator begin(size_type n) noexcept + { return ht_.begin(n); } + const_local_iterator begin(size_type n) const noexcept + { return ht_.begin(n); } + const_local_iterator cbegin(size_type n) const noexcept + { return ht_.cbegin(n); } + + local_iterator end(size_type n) noexcept + { return ht_.end(n); } + const_local_iterator end(size_type n) const noexcept + { return ht_.end(n); } + const_local_iterator cend(size_type n) const noexcept + { return ht_.cend(n); } + + size_type bucket_count() const noexcept + { return ht_.bucket_count(); } + size_type max_bucket_count() const noexcept + { return ht_.max_bucket_count(); } + + size_type bucket_size(size_type n) const noexcept + { return ht_.bucket_size(n); } + size_type bucket(const key_type& key) const + { return ht_.bucket(key); } + + // hash policy + + float load_factor() const noexcept { return ht_.load_factor(); } + + float max_load_factor() const noexcept { return ht_.max_load_factor(); } + void max_load_factor(float ml) { ht_.max_load_factor(ml); } + + void rehash(size_type count) { ht_.rehash(count); } + void reserve(size_type count) { ht_.reserve(count); } + + hasher hash_fcn() const { return ht_.hash_fcn(); } + key_equal key_eq() const { return ht_.key_eq(); } + +public: + friend bool operator==(const unordered_multiset& lhs, const unordered_multiset& rhs) + { + return lhs.ht_.equal_range_multi(rhs.ht_); + } + friend bool operator!=(const unordered_multiset& lhs, const unordered_multiset& rhs) + { + return !lhs.ht_.equal_range_multi(rhs.ht_); + } +}; + +// 重载比较操作符 +template +bool operator==(const unordered_multiset& lhs, + const unordered_multiset& rhs) +{ + return lhs == rhs; +} + +template +bool operator!=(const unordered_multiset& lhs, + const unordered_multiset& rhs) +{ + return lhs != rhs; +} + +// 重载 mystl 的 swap +template +void swap(unordered_multiset& lhs, + unordered_multiset& rhs) +{ + lhs.swap(rhs); +} + +} // namespace mystl +#endif // !MYTINYSTL_UNORDERED_SET_H_ + diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/util.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/util.h new file mode 100644 index 0000000..df6d583 --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/util.h @@ -0,0 +1,297 @@ +#ifndef MYTINYSTL_UTIL_H_ +#define MYTINYSTL_UTIL_H_ + +// 这个文件包含一些通用工具,包括 move, forward, swap 等函数,以及 pair 等 + +#include + +#include "type_traits.h" + +namespace mystl +{ + +// move + +template +typename std::remove_reference::type&& move(T&& arg) noexcept +{ + return static_cast::type&&>(arg); +} + +// forward + +template +T&& forward(typename std::remove_reference::type& arg) noexcept +{ + return static_cast(arg); +} + +template +T&& forward(typename std::remove_reference::type&& arg) noexcept +{ + static_assert(!std::is_lvalue_reference::value, "bad forward"); + return static_cast(arg); +} + +// swap + +template +void swap(Tp& lhs, Tp& rhs) +{ + auto tmp(mystl::move(lhs)); + lhs = mystl::move(rhs); + rhs = mystl::move(tmp); +} + +template +ForwardIter2 swap_range(ForwardIter1 first1, ForwardIter1 last1, ForwardIter2 first2) +{ + for (; first1 != last1; ++first1, (void) ++first2) + mystl::swap(*first1, *first2); + return first2; +} + +template +void swap(Tp(&a)[N], Tp(&b)[N]) +{ + mystl::swap_range(a, a + N, b); +} + +// -------------------------------------------------------------------------------------- +// pair + +// 结构体模板 : pair +// 两个模板参数分别表示两个数据的类型 +// 用 first 和 second 来分别取出第一个数据和第二个数据 +template +struct pair +{ + typedef Ty1 first_type; + typedef Ty2 second_type; + + first_type first; // 保存第一个数据 + second_type second; // 保存第二个数据 + + // default constructiable + template ::value && + std::is_default_constructible::value, void>::type> + constexpr pair() + : first(), second() + { + } + + // implicit constructiable for this type + template ::value && + std::is_copy_constructible::value && + std::is_convertible::value && + std::is_convertible::value, int>::type = 0> + constexpr pair(const Ty1& a, const Ty2& b) + : first(a), second(b) + { + } + + // explicit constructible for this type + template ::value && + std::is_copy_constructible::value && + (!std::is_convertible::value || + !std::is_convertible::value), int>::type = 0> + explicit constexpr pair(const Ty1& a, const Ty2& b) + : first(a), second(b) + { + } + + pair(const pair& rhs) = default; + pair(pair&& rhs) = default; + + // implicit constructiable for other type + template ::value && + std::is_constructible::value && + std::is_convertible::value && + std::is_convertible::value, int>::type = 0> + constexpr pair(Other1&& a, Other2&& b) + : first(mystl::forward(a)), + second(mystl::forward(b)) + { + } + + // explicit constructiable for other type + template ::value && + std::is_constructible::value && + (!std::is_convertible::value || + !std::is_convertible::value), int>::type = 0> + explicit constexpr pair(Other1&& a, Other2&& b) + : first(mystl::forward(a)), + second(mystl::forward(b)) + { + } + + // implicit constructiable for other pair + template ::value && + std::is_constructible::value && + std::is_convertible::value && + std::is_convertible::value, int>::type = 0> + constexpr pair(const pair& other) + : first(other.first), + second(other.second) + { + } + + // explicit constructiable for other pair + template ::value && + std::is_constructible::value && + (!std::is_convertible::value || + !std::is_convertible::value), int>::type = 0> + explicit constexpr pair(const pair& other) + : first(other.first), + second(other.second) + { + } + + // implicit constructiable for other pair + template ::value && + std::is_constructible::value && + std::is_convertible::value && + std::is_convertible::value, int>::type = 0> + constexpr pair(pair&& other) + : first(mystl::forward(other.first)), + second(mystl::forward(other.second)) + { + } + + // explicit constructiable for other pair + template ::value && + std::is_constructible::value && + (!std::is_convertible::value || + !std::is_convertible::value), int>::type = 0> + explicit constexpr pair(pair&& other) + : first(mystl::forward(other.first)), + second(mystl::forward(other.second)) + { + } + + // copy assign for this pair + pair& operator=(const pair& rhs) + { + if (this != &rhs) + { + first = rhs.first; + second = rhs.second; + } + return *this; + } + + // move assign for this pair + pair& operator=(pair&& rhs) + { + if (this != &rhs) + { + first = mystl::move(rhs.first); + second = mystl::move(rhs.second); + } + return *this; + } + + // copy assign for other pair + template + pair& operator=(const pair& other) + { + first = other.first; + second = other.second; + return *this; + } + + // move assign for other pair + template + pair& operator=(pair&& other) + { + first = mystl::forward(other.first); + second = mystl::forward(other.second); + return *this; + } + + ~pair() = default; + + void swap(pair& other) + { + if (this != &other) + { + mystl::swap(first, other.first); + mystl::swap(second, other.second); + } + } + +}; + +// 重载比较操作符 +template +bool operator==(const pair& lhs, const pair& rhs) +{ + return lhs.first == rhs.first && lhs.second == rhs.second; +} + +template +bool operator<(const pair& lhs, const pair& rhs) +{ + return lhs.first < rhs.first || (lhs.first == rhs.first && lhs.second < rhs.second); +} + +template +bool operator!=(const pair& lhs, const pair& rhs) +{ + return !(lhs == rhs); +} + +template +bool operator>(const pair& lhs, const pair& rhs) +{ + return rhs < lhs; +} + +template +bool operator<=(const pair& lhs, const pair& rhs) +{ + return !(rhs < lhs); +} + +template +bool operator>=(const pair& lhs, const pair& rhs) +{ + return !(lhs < rhs); +} + +// 重载 mystl 的 swap +template +void swap(pair& lhs, pair& rhs) +{ + lhs.swap(rhs); +} + +// 全局函数,让两个数据成为一个 pair +template +pair make_pair(Ty1&& first, Ty2&& second) +{ + return pair(mystl::forward(first), mystl::forward(second)); +} + +} + +#endif // !MYTINYSTL_UTIL_H_ + diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/vector.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/vector.h new file mode 100644 index 0000000..5192761 --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/vector.h @@ -0,0 +1,936 @@ +#ifndef MYTINYSTL_VECTOR_H_ +#define MYTINYSTL_VECTOR_H_ + +// 这个头文件包含一个模板类 vector +// vector : 向量 + +// notes: +// +// 异常保证: +// mystl::vecotr 满足基本异常保证,部分函数无异常保证,并对以下函数做强异常安全保证: +// * emplace +// * emplace_back +// * push_back +// 当 std::is_nothrow_move_assignable::value == true 时,以下函数也满足强异常保证: +// * reserve +// * resize +// * insert + +#include + +#include "iterator.h" +#include "memory.h" +#include "util.h" +#include "exceptdef.h" +#include "algo.h" + +namespace mystl +{ + +#ifdef max +#pragma message("#undefing marco max") +#undef max +#endif // max + +#ifdef min +#pragma message("#undefing marco min") +#undef min +#endif // min + +// 模板类: vector +// 模板参数 T 代表类型 +template +class vector +{ + static_assert(!std::is_same::value, "vector is abandoned in mystl"); +public: + // vector 的嵌套型别定义 + typedef mystl::allocator allocator_type; + typedef mystl::allocator data_allocator; + + typedef typename allocator_type::value_type value_type; + typedef typename allocator_type::pointer pointer; + typedef typename allocator_type::const_pointer const_pointer; + typedef typename allocator_type::reference reference; + typedef typename allocator_type::const_reference const_reference; + typedef typename allocator_type::size_type size_type; + typedef typename allocator_type::difference_type difference_type; + + typedef value_type* iterator; + typedef const value_type* const_iterator; + typedef mystl::reverse_iterator reverse_iterator; + typedef mystl::reverse_iterator const_reverse_iterator; + + allocator_type get_allocator() { return data_allocator(); } + +private: + iterator begin_; // 表示目前使用空间的头部 + iterator end_; // 表示目前使用空间的尾部 + iterator cap_; // 表示目前储存空间的尾部 + +public: + // 构造、复制、移动、析构函数 + vector() noexcept + { try_init(); } + + explicit vector(size_type n) + { fill_init(n, value_type()); } + + vector(size_type n, const value_type& value) + { fill_init(n, value); } + + template ::value, int>::type = 0> + vector(Iter first, Iter last) + { + MYSTL_DEBUG(!(last < first)); + range_init(first, last); + } + + vector(const vector& rhs) + { + range_init(rhs.begin_, rhs.end_); + } + + vector(vector&& rhs) noexcept + :begin_(rhs.begin_), + end_(rhs.end_), + cap_(rhs.cap_) + { + rhs.begin_ = nullptr; + rhs.end_ = nullptr; + rhs.cap_ = nullptr; + } + + vector(std::initializer_list ilist) + { + range_init(ilist.begin(), ilist.end()); + } + + vector& operator=(const vector& rhs); + vector& operator=(vector&& rhs) noexcept; + + vector& operator=(std::initializer_list ilist) + { + vector tmp(ilist.begin(), ilist.end()); + swap(tmp); + return *this; + } + + ~vector() + { + destroy_and_recover(begin_, end_, cap_ - begin_); + begin_ = end_ = cap_ = nullptr; + } + +public: + + // 迭代器相关操作 + iterator begin() noexcept + { return begin_; } + const_iterator begin() const noexcept + { return begin_; } + iterator end() noexcept + { return end_; } + const_iterator end() const noexcept + { return end_; } + + reverse_iterator rbegin() noexcept + { return reverse_iterator(end()); } + const_reverse_iterator rbegin() const noexcept + { return const_reverse_iterator(end()); } + reverse_iterator rend() noexcept + { return reverse_iterator(begin()); } + const_reverse_iterator rend() const noexcept + { return const_reverse_iterator(begin()); } + + const_iterator cbegin() const noexcept + { return begin(); } + const_iterator cend() const noexcept + { return end(); } + const_reverse_iterator crbegin() const noexcept + { return rbegin(); } + const_reverse_iterator crend() const noexcept + { return rend(); } + + // 容量相关操作 + bool empty() const noexcept + { return begin_ == end_; } + size_type size() const noexcept + { return static_cast(end_ - begin_); } + size_type max_size() const noexcept + { return static_cast(-1) / sizeof(T); } + size_type capacity() const noexcept + { return static_cast(cap_ - begin_); } + void reserve(size_type n); + void shrink_to_fit(); + + // 访问元素相关操作 + reference operator[](size_type n) + { + MYSTL_DEBUG(n < size()); + return *(begin_ + n); + } + const_reference operator[](size_type n) const + { + MYSTL_DEBUG(n < size()); + return *(begin_ + n); + } + reference at(size_type n) + { + THROW_OUT_OF_RANGE_IF(!(n < size()), "vector::at() subscript out of range"); + return (*this)[n]; + } + const_reference at(size_type n) const + { + THROW_OUT_OF_RANGE_IF(!(n < size()), "vector::at() subscript out of range"); + return (*this)[n]; + } + + reference front() + { + MYSTL_DEBUG(!empty()); + return *begin_; + } + const_reference front() const + { + MYSTL_DEBUG(!empty()); + return *begin_; + } + reference back() + { + MYSTL_DEBUG(!empty()); + return *(end_ - 1); + } + const_reference back() const + { + MYSTL_DEBUG(!empty()); + return *(end_ - 1); + } + + pointer data() noexcept { return begin_; } + const_pointer data() const noexcept { return begin_; } + + // 修改容器相关操作 + + // assign + + void assign(size_type n, const value_type& value) + { fill_assign(n, value); } + + template ::value, int>::type = 0> + void assign(Iter first, Iter last) + { + MYSTL_DEBUG(!(last < first)); + copy_assign(first, last, iterator_category(first)); + } + + void assign(std::initializer_list il) + { copy_assign(il.begin(), il.end(), mystl::forward_iterator_tag{}); } + + // emplace / emplace_back + + template + iterator emplace(const_iterator pos, Args&& ...args); + + template + void emplace_back(Args&& ...args); + + // push_back / pop_back + + void push_back(const value_type& value); + void push_back(value_type&& value) + { emplace_back(mystl::move(value)); } + + void pop_back(); + + // insert + + iterator insert(const_iterator pos, const value_type& value); + iterator insert(const_iterator pos, value_type&& value) + { return emplace(pos, mystl::move(value)); } + + iterator insert(const_iterator pos, size_type n, const value_type& value) + { + MYSTL_DEBUG(pos >= begin() && pos <= end()); + return fill_insert(const_cast(pos), n, value); + } + + template ::value, int>::type = 0> + void insert(const_iterator pos, Iter first, Iter last) + { + MYSTL_DEBUG(pos >= begin() && pos <= end() && !(last < first)); + copy_insert(const_cast(pos), first, last); + } + + // erase / clear + iterator erase(const_iterator pos); + iterator erase(const_iterator first, const_iterator last); + void clear() { erase(begin(), end()); } + + // resize / reverse + void resize(size_type new_size) { return resize(new_size, value_type()); } + void resize(size_type new_size, const value_type& value); + + void reverse() { mystl::reverse(begin(), end()); } + + // swap + void swap(vector& rhs) noexcept; + +private: + // helper functions + + // initialize / destroy + void try_init() noexcept; + + void init_space(size_type size, size_type cap); + + void fill_init(size_type n, const value_type& value); + template + void range_init(Iter first, Iter last); + + void destroy_and_recover(iterator first, iterator last, size_type n); + + // calculate the growth size + size_type get_new_cap(size_type add_size); + + // assign + + void fill_assign(size_type n, const value_type& value); + + template + void copy_assign(IIter first, IIter last, input_iterator_tag); + + template + void copy_assign(FIter first, FIter last, forward_iterator_tag); + + // reallocate + + template + void reallocate_emplace(iterator pos, Args&& ...args); + void reallocate_insert(iterator pos, const value_type& value); + + // insert + + iterator fill_insert(iterator pos, size_type n, const value_type& value); + template + void copy_insert(iterator pos, IIter first, IIter last); + + // shrink_to_fit + + void reinsert(size_type size); +}; + +/*****************************************************************************************/ + +// 复制赋值操作符 +template +vector& vector::operator=(const vector& rhs) +{ + if (this != &rhs) + { + const auto len = rhs.size(); + if (len > capacity()) + { + vector tmp(rhs.begin(), rhs.end()); + swap(tmp); + } + else if (size() >= len) + { + auto i = mystl::copy(rhs.begin(), rhs.end(), begin()); + data_allocator::destroy(i, end_); + end_ = begin_ + len; + } + else + { + mystl::copy(rhs.begin(), rhs.begin() + size(), begin_); + mystl::uninitialized_copy(rhs.begin() + size(), rhs.end(), end_); + cap_ = end_ = begin_ + len; + } + } + return *this; +} + +// 移动赋值操作符 +template +vector& vector::operator=(vector&& rhs) noexcept +{ + destroy_and_recover(begin_, end_, cap_ - begin_); + begin_ = rhs.begin_; + end_ = rhs.end_; + cap_ = rhs.cap_; + rhs.begin_ = nullptr; + rhs.end_ = nullptr; + rhs.cap_ = nullptr; + return *this; +} + +// 预留空间大小,当原容量小于要求大小时,才会重新分配 +template +void vector::reserve(size_type n) +{ + if (capacity() < n) + { + THROW_LENGTH_ERROR_IF(n > max_size(), + "n can not larger than max_size() in vector::reserve(n)"); + const auto old_size = size(); + auto tmp = data_allocator::allocate(n); + mystl::uninitialized_move(begin_, end_, tmp); + data_allocator::deallocate(begin_, cap_ - begin_); + begin_ = tmp; + end_ = tmp + old_size; + cap_ = begin_ + n; + } +} + +// 放弃多余的容量 +template +void vector::shrink_to_fit() +{ + if (end_ < cap_) + { + reinsert(size()); + } +} + +// 在 pos 位置就地构造元素,避免额外的复制或移动开销 +template +template +typename vector::iterator +vector::emplace(const_iterator pos, Args&& ...args) +{ + MYSTL_DEBUG(pos >= begin() && pos <= end()); + iterator xpos = const_cast(pos); + const size_type n = xpos - begin_; + if (end_ != cap_ && xpos == end_) + { + data_allocator::construct(mystl::address_of(*end_), mystl::forward(args)...); + ++end_; + } + else if (end_ != cap_) + { + auto new_end = end_; + data_allocator::construct(mystl::address_of(*end_), *(end_ - 1)); + ++new_end; + mystl::copy_backward(xpos, end_ - 1, end_); + *xpos = value_type(mystl::forward(args)...); + end_ = new_end; + } + else + { + reallocate_emplace(xpos, mystl::forward(args)...); + } + return begin() + n; +} + +// 在尾部就地构造元素,避免额外的复制或移动开销 +template +template +void vector::emplace_back(Args&& ...args) +{ + if (end_ < cap_) + { + data_allocator::construct(mystl::address_of(*end_), mystl::forward(args)...); + ++end_; + } + else + { + reallocate_emplace(end_, mystl::forward(args)...); + } +} + +// 在尾部插入元素 +template +void vector::push_back(const value_type& value) +{ + if (end_ != cap_) + { + data_allocator::construct(mystl::address_of(*end_), value); + ++end_; + } + else + { + reallocate_insert(end_, value); + } +} + +// 弹出尾部元素 +template +void vector::pop_back() +{ + MYSTL_DEBUG(!empty()); + data_allocator::destroy(end_ - 1); + --end_; +} + +// 在 pos 处插入元素 +template +typename vector::iterator +vector::insert(const_iterator pos, const value_type& value) +{ + MYSTL_DEBUG(pos >= begin() && pos <= end()); + iterator xpos = const_cast(pos); + const size_type n = pos - begin_; + if (end_ != cap_ && xpos == end_) + { + data_allocator::construct(mystl::address_of(*end_), value); + ++end_; + } + else if (end_ != cap_) + { + auto new_end = end_; + data_allocator::construct(mystl::address_of(*end_), *(end_ - 1)); + ++new_end; + auto value_copy = value; // 避免元素因以下复制操作而被改变 + mystl::copy_backward(xpos, end_ - 1, end_); + *xpos = mystl::move(value_copy); + end_ = new_end; + } + else + { + reallocate_insert(xpos, value); + } + return begin_ + n; +} + +// 删除 pos 位置上的元素 +template +typename vector::iterator +vector::erase(const_iterator pos) +{ + MYSTL_DEBUG(pos >= begin() && pos < end()); + iterator xpos = begin_ + (pos - begin()); + mystl::move(xpos + 1, end_, xpos); + data_allocator::destroy(end_ - 1); + --end_; + return xpos; +} + +// 删除[first, last)上的元素 +template +typename vector::iterator +vector::erase(const_iterator first, const_iterator last) +{ + MYSTL_DEBUG(first >= begin() && last <= end() && !(last < first)); + const auto n = first - begin(); + iterator r = begin_ + (first - begin()); + data_allocator::destroy(mystl::move(r + (last - first), end_, r), end_); + end_ = end_ - (last - first); + return begin_ + n; +} + +// 重置容器大小 +template +void vector::resize(size_type new_size, const value_type& value) +{ + if (new_size < size()) + { + erase(begin() + new_size, end()); + } + else + { + insert(end(), new_size - size(), value); + } +} + +// 与另一个 vector 交换 +template +void vector::swap(vector& rhs) noexcept +{ + if (this != &rhs) + { + mystl::swap(begin_, rhs.begin_); + mystl::swap(end_, rhs.end_); + mystl::swap(cap_, rhs.cap_); + } +} + +/*****************************************************************************************/ +// helper function + +// try_init 函数,若分配失败则忽略,不抛出异常 +template +void vector::try_init() noexcept +{ + try + { + begin_ = data_allocator::allocate(16); + end_ = begin_; + cap_ = begin_ + 16; + } + catch (...) + { + begin_ = nullptr; + end_ = nullptr; + cap_ = nullptr; + } +} + +// init_space 函数 +template +void vector::init_space(size_type size, size_type cap) +{ + try + { + begin_ = data_allocator::allocate(cap); + end_ = begin_ + size; + cap_ = begin_ + cap; + } + catch (...) + { + begin_ = nullptr; + end_ = nullptr; + cap_ = nullptr; + throw; + } +} + +// fill_init 函数 +template +void vector:: +fill_init(size_type n, const value_type& value) +{ + const size_type init_size = mystl::max(static_cast(16), n); + init_space(n, init_size); + mystl::uninitialized_fill_n(begin_, n, value); +} + +// range_init 函数 +template +template +void vector:: +range_init(Iter first, Iter last) +{ + const size_type len = mystl::distance(first, last); + const size_type init_size = mystl::max(len, static_cast(16)); + init_space(len, init_size); + mystl::uninitialized_copy(first, last, begin_); +} + +// destroy_and_recover 函数 +template +void vector:: +destroy_and_recover(iterator first, iterator last, size_type n) +{ + data_allocator::destroy(first, last); + data_allocator::deallocate(first, n); +} + +// get_new_cap 函数 +template +typename vector::size_type +vector:: +get_new_cap(size_type add_size) +{ + const auto old_size = capacity(); + THROW_LENGTH_ERROR_IF(old_size > max_size() - add_size, + "vector's size too big"); + if (old_size > max_size() - old_size / 2) + { + return old_size + add_size > max_size() - 16 + ? old_size + add_size : old_size + add_size + 16; + } + const size_type new_size = old_size == 0 + ? mystl::max(add_size, static_cast(16)) + : mystl::max(old_size + old_size / 2, old_size + add_size); + return new_size; +} + +// fill_assign 函数 +template +void vector:: +fill_assign(size_type n, const value_type& value) +{ + if (n > capacity()) + { + vector tmp(n, value); + swap(tmp); + } + else if (n > size()) + { + mystl::fill(begin(), end(), value); + end_ = mystl::uninitialized_fill_n(end_, n - size(), value); + } + else + { + erase(mystl::fill_n(begin_, n, value), end_); + } +} + +// copy_assign 函数 +template +template +void vector:: +copy_assign(IIter first, IIter last, input_iterator_tag) +{ + auto cur = begin_; + for (; first != last && cur != end_; ++first, ++cur) + { + *cur = *first; + } + if (first == last) + { + erase(cur, end_); + } + else + { + insert(end_, first, last); + } +} + +// 用 [first, last) 为容器赋值 +template +template +void vector:: +copy_assign(FIter first, FIter last, forward_iterator_tag) +{ + const size_type len = mystl::distance(first, last); + if (len > capacity()) + { + vector tmp(first, last); + swap(tmp); + } + else if (size() >= len) + { + auto new_end = mystl::copy(first, last, begin_); + data_allocator::destroy(new_end, end_); + end_ = new_end; + } + else + { + auto mid = first; + mystl::advance(mid, size()); + mystl::copy(first, mid, begin_); + auto new_end = mystl::uninitialized_copy(mid, last, end_); + end_ = new_end; + } +} + +// 重新分配空间并在 pos 处就地构造元素 +template +template +void vector:: +reallocate_emplace(iterator pos, Args&& ...args) +{ + const auto new_size = get_new_cap(1); + auto new_begin = data_allocator::allocate(new_size); + auto new_end = new_begin; + try + { + new_end = mystl::uninitialized_move(begin_, pos, new_begin); + data_allocator::construct(mystl::address_of(*new_end), mystl::forward(args)...); + ++new_end; + new_end = mystl::uninitialized_move(pos, end_, new_end); + } + catch (...) + { + data_allocator::deallocate(new_begin, new_size); + throw; + } + destroy_and_recover(begin_, end_, cap_ - begin_); + begin_ = new_begin; + end_ = new_end; + cap_ = new_begin + new_size; +} + +// 重新分配空间并在 pos 处插入元素 +template +void vector::reallocate_insert(iterator pos, const value_type& value) +{ + const auto new_size = get_new_cap(1); + auto new_begin = data_allocator::allocate(new_size); + auto new_end = new_begin; + const value_type& value_copy = value; + try + { + new_end = mystl::uninitialized_move(begin_, pos, new_begin); + data_allocator::construct(mystl::address_of(*new_end), value_copy); + ++new_end; + new_end = mystl::uninitialized_move(pos, end_, new_end); + } + catch (...) + { + data_allocator::deallocate(new_begin, new_size); + throw; + } + destroy_and_recover(begin_, end_, cap_ - begin_); + begin_ = new_begin; + end_ = new_end; + cap_ = new_begin + new_size; +} + +// fill_insert 函数 +template +typename vector::iterator +vector:: +fill_insert(iterator pos, size_type n, const value_type& value) +{ + if (n == 0) + return pos; + const size_type xpos = pos - begin_; + const value_type value_copy = value; // 避免被覆盖 + if (static_cast(cap_ - end_) >= n) + { // 如果备用空间大于等于增加的空间 + const size_type after_elems = end_ - pos; + auto old_end = end_; + if (after_elems > n) + { + mystl::uninitialized_copy(end_ - n, end_, end_); + end_ += n; + mystl::move_backward(pos, old_end - n, old_end); + mystl::uninitialized_fill_n(pos, n, value_copy); + } + else + { + end_ = mystl::uninitialized_fill_n(end_, n - after_elems, value_copy); + end_ = mystl::uninitialized_move(pos, old_end, end_); + mystl::uninitialized_fill_n(pos, after_elems, value_copy); + } + } + else + { // 如果备用空间不足 + const auto new_size = get_new_cap(n); + auto new_begin = data_allocator::allocate(new_size); + auto new_end = new_begin; + try + { + new_end = mystl::uninitialized_move(begin_, pos, new_begin); + new_end = mystl::uninitialized_fill_n(new_end, n, value); + new_end = mystl::uninitialized_move(pos, end_, new_end); + } + catch (...) + { + destroy_and_recover(new_begin, new_end, new_size); + throw; + } + data_allocator::deallocate(begin_, cap_ - begin_); + begin_ = new_begin; + end_ = new_end; + cap_ = begin_ + new_size; + } + return begin_ + xpos; +} + +// copy_insert 函数 +template +template +void vector:: +copy_insert(iterator pos, IIter first, IIter last) +{ + if (first == last) + return; + const auto n = mystl::distance(first, last); + if ((cap_ - end_) >= n) + { // 如果备用空间大小足够 + const auto after_elems = end_ - pos; + auto old_end = end_; + if (after_elems > n) + { + end_ = mystl::uninitialized_copy(end_ - n, end_, end_); + mystl::move_backward(pos, old_end - n, old_end); + mystl::uninitialized_copy(first, last, pos); + } + else + { + auto mid = first; + mystl::advance(mid, after_elems); + end_ = mystl::uninitialized_copy(mid, last, end_); + end_ = mystl::uninitialized_move(pos, old_end, end_); + mystl::uninitialized_copy(first, mid, pos); + } + } + else + { // 备用空间不足 + const auto new_size = get_new_cap(n); + auto new_begin = data_allocator::allocate(new_size); + auto new_end = new_begin; + try + { + new_end = mystl::uninitialized_move(begin_, pos, new_begin); + new_end = mystl::uninitialized_copy(first, last, new_end); + new_end = mystl::uninitialized_move(pos, end_, new_end); + } + catch (...) + { + destroy_and_recover(new_begin, new_end, new_size); + throw; + } + data_allocator::deallocate(begin_, cap_ - begin_); + begin_ = new_begin; + end_ = new_end; + cap_ = begin_ + new_size; + } +} + +// reinsert 函数 +template +void vector::reinsert(size_type size) +{ + auto new_begin = data_allocator::allocate(size); + try + { + mystl::uninitialized_move(begin_, end_, new_begin); + } + catch (...) + { + data_allocator::deallocate(new_begin, size); + throw; + } + data_allocator::deallocate(begin_, cap_ - begin_); + begin_ = new_begin; + end_ = begin_ + size; + cap_ = begin_ + size; +} + +/*****************************************************************************************/ +// 重载比较操作符 + +template +bool operator==(const vector& lhs, const vector& rhs) +{ + return lhs.size() == rhs.size() && + mystl::equal(lhs.begin(), lhs.end(), rhs.begin()); +} + +template +bool operator<(const vector& lhs, const vector& rhs) +{ + return mystl::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); +} + +template +bool operator!=(const vector& lhs, const vector& rhs) +{ + return !(lhs == rhs); +} + +template +bool operator>(const vector& lhs, const vector& rhs) +{ + return rhs < lhs; +} + +template +bool operator<=(const vector& lhs, const vector& rhs) +{ + return !(rhs < lhs); +} + +template +bool operator>=(const vector& lhs, const vector& rhs) +{ + return !(lhs < rhs); +} + +// 重载 mystl 的 swap +template +void swap(vector& lhs, vector& rhs) +{ + lhs.swap(rhs); +} + +} // namespace mystl +#endif // !MYTINYSTL_VECTOR_H_ + diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/README.md b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/README.md new file mode 100644 index 0000000..333ec43 --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/README.md @@ -0,0 +1,101 @@ +MyTinySTL +===== +[![Build Status](https://travis-ci.org/Alinshans/MyTinySTL.svg?branch=master)](https://travis-ci.org/Alinshans/MyTinySTL) [![Build Status](https://ci.appveyor.com/api/projects/status/github/Alinshans/MyTinySTL?branch=master&svg=true)](https://ci.appveyor.com/project/Alinshans/mytinystl) [![Release](https://img.shields.io/github/release/Alinshans/MyTinySTL.svg)](https://github.com/Alinshans/MyTinySTL/releases) [![License](https://img.shields.io/badge/License-MIT%20License-blue.svg)](https://opensource.org/licenses/MIT) [![Chat](https://img.shields.io/badge/chat-on%20gitter-FF6EB4.svg)](https://gitter.im/alinshans/MyTinySTL) + +## 简介 + 基于 `C++11` 的 `tinySTL`,这是我的第一个项目,使用了中文文档与中文注释,有不规范或不当的地方还请海涵。刚开始是作为新手练习用途,直到现在已经发布了 `2.x.x` 版本。实现了大部分 STL 中的容器与函数,但仍存在许多不足与 bug 。从 `2.x.x` 版本开始,本项目会进入长期维护的阶段,即基本不会增加新的内容,只修复发现的 bug。如发现错误,还请在 [`Issues`](https://github.com/Alinshans/MyTinySTL/issues) 中指出,欢迎 `Fork` 和 [`Pull requests`](https://github.com/Alinshans/MyTinySTL/pulls) 改善代码,谢谢! + +## 支持 + +* 操作系统 + * linux + * windows + * osx +* 编译器 + * g++ 5.4 或以上 + * clang++ 3.5 或以上 + * msvc 14.0 或以上 + +## 需要 + * 使用 cmake 2.8 来构建项目(**可选**) + +## 运行 + +如果你想要运行测试,请先阅读 [这个](https://github.com/Alinshans/MyTinySTL/blob/master/Test/README.md) 。 + + * gcc/clang on linux/osx + 1. 克隆仓库 +```bash +$ git clone git@github.com:Alinshans/MyTinySTL.git +$ cd MyTinySTL +``` + 2. 构建并运行 +```bash +$ mkdir build && cd build +$ cmake .. +$ make +$ cd ../bin && ./stltest +``` + + * msvc on windows + 1. 克隆仓库或 [Download ZIP](https://github.com/Alinshans/MyTinySTL/archive/master.zip) + 2. 使用 `vs2015`(或 `vs2017`)打开 `MSVC/MyTinySTL_VS2015.sln`,配置成 `Release` 模式,(Ctrl + F5)开始执行。 + +## 文档 + 见 [Wiki](https://github.com/Alinshans/MyTinySTL/wiki)。 + +## 测试 + 见 [Test](https://github.com/Alinshans/MyTinySTL/tree/master/Test)。 + +--- + +## Introduction + +This is a `tinySTL` based on `C++11`, which is my first project for practice. I use the Chinese documents and annotations for convenience, maybe there will be an English version later, but now I have no time to do that yet. Now I have released version `2.0.0`. I have achieved the vast majority of the containers and functions of `STL`, and there may be some deficiencies and bugs. From the version `2.x.x`, the project will enter the stage of long-term maintenance, i.e., I probably will not add new content but only fix bugs found. If you find any bugs, please point out that in [`Issues`](https://github.com/Alinshans/MyTinySTL/issues), or make a [`Pull requests`](https://github.com/Alinshans/MyTinySTL/pulls) to improve it, thanks! + +## Supported + +* os + * linux + * windows + * osx +* complier + * g++ 5.4 or later + * clang++ 3.5 or later + * msvc 14.0 or later + +## Required + +* Use cmake 2.8 to build this project (**Optional**) + +## Run test + +If you want to run the test, please read [this](https://github.com/Alinshans/MyTinySTL/blob/master/Test/README.md) first. + +* gcc/clang on linux/osx + +1. git clone +```bash +$ git clone git@github.com:Alinshans/MyTinySTL.git +$ cd MyTinySTL +``` +2. build and run +```bash +$ mkdir build && cd build +$ cmake .. +$ make +$ cd ../bin && ./stltest +``` + +* msvc on windows + +1. git clone or [Download ZIP](https://github.com/Alinshans/MyTinySTL/archive/master.zip) +2. use `vs2015`(or `vs2017`) open the file `MSVC/MyTinySTL_VS2015.sln`, configured in `Release`, run this project(Ctrl + F5). + +## Documents + +See [Wiki](https://github.com/Alinshans/MyTinySTL/wiki). + +## Test + +See [Test](https://github.com/Alinshans/MyTinySTL/tree/master/Test). diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/CMakeLists.txt b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/CMakeLists.txt new file mode 100644 index 0000000..aa01d4e --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/CMakeLists.txt @@ -0,0 +1,4 @@ +include_directories(${PROJECT_SOURCE_DIR}/MyTinySTL) +set(APP_SRC test.cpp) +set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin) +add_executable(stltest ${APP_SRC}) \ No newline at end of file diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/Lib/redbud/io/color.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/Lib/redbud/io/color.h new file mode 100644 index 0000000..e414bf7 --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/Lib/redbud/io/color.h @@ -0,0 +1,351 @@ +// ============================================================================ +// Copyright (c) 2017 Alinshans. All rights reserved. +// Licensed under the MIT License. See LICENSE for details. +// +// Header File : redbud/io/color.h +// +// This file is used to control font format and color in the terminal, which +// refers to a project on github, see https://github.com/agauniyal/rang . +// ============================================================================ + +#ifndef ALINSHANS_REDBUD_IO_COLOR_H_ +#define ALINSHANS_REDBUD_IO_COLOR_H_ + +#include "../platform.h" + +#if defined(REDBUD_LINUX) || defined(REDBUD_OSX) + #include // getenv + #include // strstr +#elif defined(REDBUD_WIN) + #include + #include +#endif + +#include +#include +#include + +namespace redbud +{ +namespace io +{ + +// ============================================================================ +// Enumerates the ANSI escape code corresponding to the font attributes. +// See https://en.wikipedia.org/wiki/ANSI_escape_code for details. +// +// Example: +// using namespace redbud::io; +// std::cout << fg::red << "This text has a red foreground color\n"; +// std::cout << bg::green << "This text has a green background color\n" +// ============================================================================ + +// Sets the text format, some of them is not widely supported. +enum class format +{ + reset = 0, // All attributes off. + bold = 1, // Bold or increased intensity. + faint = 2, // Faint (decreased intensity). + italic = 3, // Italian font. + underline = 4, // Underline. + blinkslow = 5, // Blink slowly. + blinkrapid = 6, // Blink quickly. + inverse = 7, // Swap foreground and background. + conceal = 8, // Hide the text. + strikeline = 9 // Characters legible, but marked for deletion. +}; + +// Sets the foreground color. +enum class fg +{ + black = 30, + red = 31, + green = 32, + yellow = 33, + blue = 34, + purple = 35, + cyan = 36, + white = 37, + reserve = 38, + reset = 39 +}; + +// Sets the background color. +enum class bg +{ + black = 40, + red = 41, + green = 42, + yellow = 43, + blue = 44, + purple = 45, + cyan = 46, + white = 47, + reserve = 38, + reset = 39 +}; + +// Sets the highlight foreground color. +enum class hfg +{ + black = 90, + red = 91, + green = 92, + yellow = 93, + blue = 94, + purple = 95, + cyan = 96, + white = 97 +}; + +// Sets the highlight background color. +enum class hbg +{ + black = 100, + red = 101, + green = 102, + yellow = 103, + blue = 104, + purple = 105, + cyan = 106, + white = 107 +}; + +// Sets the control state. +enum class state +{ + automatic = 0, // Automatic control. + manual = 1 // Manual control. +}; + +// ---------------------------------------------------------------------------- +// Details +namespace details +{ + +// Manages associated stream buffer. +inline const std::streambuf*& get_coutbuf() +{ + static const std::streambuf* pout = std::cout.rdbuf(); + return pout; +} + +inline const std::streambuf*& get_cerrbuf() +{ + static const std::streambuf* perr = std::cerr.rdbuf(); + return perr; +} + +inline const std::streambuf*& get_clogbuf() +{ + static const std::streambuf* plog = std::clog.rdbuf(); + return plog; +} + +// Gets an unique integer to use as index to iword() +inline int get_iword() +{ + static int i = std::ios_base::xalloc(); + return i; +} + +// Determines whether the terminal color of this system can be modified. +inline bool is_modifiable() +{ +#if defined(REDBUD_LINUX) || defined(REDBUD_OSX) + static constexpr const char* terms[] = { + "ansi", "color", "console", "cygwin", "gnome", "konsole", "kterm", + "linux", "msys", "putty", "rxvt", "screen", "vt100", "xterm" + }; + const char *penv = std::getenv("TERM"); + if (penv == nullptr) + { + return false; + } + bool result = false; + for (const auto& t : terms) + { + if (std::strstr(penv, t) != nullptr) + { + result = true; + break; + } + } + +#elif defined(REDBUD_WIN) + static constexpr bool result = true; +#endif + return result; +} + +/// Determines whether the buffer stream reaches the end. +inline bool is_terminal(const std::streambuf* buf) +{ + if (buf == get_coutbuf()) + { +#if defined(REDBUD_LINUX) || defined(REDBUD_OSX) + return isatty(fileno(stdout)) ? true : false; +#elif defined(REDBUD_WIN) + return _isatty(_fileno(stdout)) ? true : false; +#endif + } + + if (buf == get_cerrbuf() || buf == get_clogbuf()) + { +#if defined(REDBUD_LINUX) || defined(REDBUD_OSX) + return isatty(fileno(stderr)) ? true : false; +#elif defined(REDBUD_WIN) + return _isatty(_fileno(stderr)) ? true : false; +#endif + } + return false; +} + +// For overloading standard output stream. +template +using color_return_t = typename std::enable_if< + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value || + std::is_same::value, + std::ostream&>::type; + +template +using state_return_t = typename std::enable_if< + std::is_same::value, + std::ostream&>::type; + +// Sets the format and color of the text. +#if defined(REDBUD_LINUX) || defined(REDBUD_OSX) +template +inline color_return_t set_color(std::ostream& os, const T& value) +{ + return os << "\033[" << static_cast(value) << "m"; +} + +#elif defined(REDBUD_WIN) + +static constexpr WORD default_state = (FOREGROUND_BLUE | + FOREGROUND_GREEN | + FOREGROUND_RED); + +// Gets the corresponding RGB value on Windows. +inline WORD get_rgb(WORD rgb) +{ + static constexpr WORD cor[8] = { 0, 4, 2, 6, 1, 5, 3, 7 }; + return cor[rgb]; +} + +// Sets font attributes on Windows. +inline void set_attributes(redbud::io::fg color, WORD& state) +{ + if (color == redbud::io::fg::reserve) + { + return; + } + state &= 0xFFF0; + if (color == redbud::io::fg::reset) + { + state |= default_state; + return; + } + state |= get_rgb(static_cast(color) - 30); +} + +inline void set_attributes(redbud::io::bg color, WORD& state) +{ + if (color == redbud::io::bg::reserve) + { + return; + } + state &= 0xFF0F; + if (color == redbud::io::bg::reset) + { + return; + } + state |= get_rgb(static_cast(color) - 40) << 4; +} + +inline void set_attributes(redbud::io::hfg color, WORD& state) +{ + state &= 0xFFF0; + state |= (static_cast(0x8) | + get_rgb(static_cast(color) - 90)); +} + +inline void set_attributes(redbud::io::hbg color, WORD& state) +{ + state &= 0xFF0F; + state |= (static_cast(0x80) | + get_rgb(static_cast(color) - 100) << 4); +} + +inline void set_attributes(redbud::io::format format, WORD& state) +{ + if (format == redbud::io::format::reset) + { + state = default_state; + } +} + +inline WORD& current_state() +{ + static WORD state = default_state; + return state; +} + +inline HANDLE get_console_handle() +{ + static HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE); + return h; +} + +template +inline color_return_t set_color(std::ostream& os, const T& value) +{ + HANDLE h = get_console_handle(); + if (h && is_terminal(os.rdbuf())) + { + set_attributes(value, current_state()); + SetConsoleTextAttribute(h, current_state()); + return os; + } + return os; +} +#endif + +} // namespace details + +// ---------------------------------------------------------------------------- +// Overloads standard output stream to control the color of text. + +template +inline details::color_return_t +operator<<(std::ostream& os, const T& value) +{ + return (os.iword(details::get_iword()) || + (details::is_modifiable() && + details::is_terminal(os.rdbuf()))) + ? details::set_color(os, value) + : os; +} + +template +inline details::state_return_t +operator<<(std::ostream& os, const T& value) +{ + if (value == redbud::io::state::automatic) + { + os.iword(details::get_iword()) = 0; + } + else if (value == redbud::io::state::manual) + { + os.iword(details::get_iword()) = 1; + } + return os; +} + +} // namespace io +} // namespace redbud +#endif // !ALINSHANS_REDBUD_IO_COLOR_H_ diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/Lib/redbud/platform.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/Lib/redbud/platform.h new file mode 100644 index 0000000..0a09b44 --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/Lib/redbud/platform.h @@ -0,0 +1,108 @@ +// ============================================================================ +// Copyright (c) 2017 Alinshans. All rights reserved. +// Licensed under the MIT License. See LICENSE for details. +// +// Header File : redbud/platform.h +// +// This file contains some preprocessing macros related to the platform. +// ============================================================================ + +#ifndef ALINSHANS_REDBUD_PLATFORM_H_ +#define ALINSHANS_REDBUD_PLATFORM_H_ + +// ---------------------------------------------------------------------------- +// os + +#if defined(WIN32) || defined(_WIN32) || defined(_WIN64) + #define REDBUD_WIN 1 +#elif defined(__unix__) || defined(__unix) || defined(__linux__) + #define REDBUD_LINUX 1 +#elif defined(__APPLE__) || defined(__MACH__) + #define REDBUD_OSX 1 +#else + #error "System that is not supported yet." +#endif + +// ---------------------------------------------------------------------------- +// complier + +#if defined(__clang__) + #define REDBUD_CLANG __clang__ +#elif defined(__GNUC__) + #define REDBUD_GNUC __GNUC__ +#elif defined(_MSC_VER) + #define REDBUD_MSVC _MSC_VER +#else + #error "Complier that is not supported yet." +#endif + +// ---------------------------------------------------------------------------- +// stringify + +#define REDBUD_TO_STRING(x) #x +#define REDBUD_STRING(x) REDBUD_TO_STRING(x) + +// ---------------------------------------------------------------------------- +// join + +#define REDBUD_DO_JOIN(x ,y) x##y +#define REDBUD_JOIN(x, y) REDBUD_DO_JOIN(x, y) + +// ---------------------------------------------------------------------------- +// version + +#define REDBUD_MAJOR 1 +#define REDBUD_MINOR 0 +#define REDBUD_PATCH 0 +#define REDBUD_VERSION \ + REDBUD_STRING(REDBUD_MAJOR.REDBUD_MINOR.REDBUD_PATCH) + +#define _VERSION_CODE(x,y,z) \ + (((x)*100000) + ((y)*100) + (z)) + +#define GNUC_VERSION \ + _VERSION_CODE(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) + +#define CLANG_VERSION \ + _VERSION_CODE(__clang_major__, __clang_minor__, __clang_patchlevel__) + +// ---------------------------------------------------------------------------- +// redbud API + +#ifndef _REDBUD_API + #define _REDBUD_API ::redbud:: +#endif + +// ---------------------------------------------------------------------------- +// C++11 required + +#ifndef REDBUD_HAS_CXX11 + #if defined(REDBUD_MSVC) && (REDBUD_MSVC >= 1900) + #define REDBUD_HAS_CXX11 1 + #elif defined(REDBUD_GNUC) && (GNUC_VERSION >= _VERSION_CODE(4,8,0)) && \ + defined(__GXX_EXPERIMENTAL_CXX0X__) + #define REDBUD_HAS_CXX11 1 + #elif defined(REDBUD_CLANG) && (CLANG_VERSION >= _VERSION_CODE(3,3,0)) + #define REDBUD_HAS_CXX11 1 + #else + #define REDBUD_HAS_CXX11 0 + #endif +#endif // !REDBUD_HAS_CXX11 + +#if REDBUD_HAS_CXX11 == 0 + #error "C++11 required." +#endif + +// ---------------------------------------------------------------------------- +// Undefines macro min and max in MSVC. + +namespace redbud +{ + +#if REDBUD_MSVC + #define NOMINMAX +#endif + +} + +#endif // !ALINSHANS_REDBUD_PLATFORM_H_ diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/README.md b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/README.md new file mode 100644 index 0000000..1c6a1b5 --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/README.md @@ -0,0 +1,51 @@ +单元测试 (Unit test) +===== +## 测试环境 (Test environment) + 测试直接在 `Travis CI` 和 `AppVeyor` 上构建并运行,已在以下环境中做过测试: + + Tests were built and run directly on `Tracis CI` and `AppVeyor` and had been tested in the following environments: + + * linux, ubuntu 14.04, gcc5/6/7 + * osx, xcode5/6/7/8 + * windows, VS2015/VS2017, [x64|x86], [Release|Debug] + +## 测试框架 (Test frame) + 在 [test.h](https://github.com/Alinshans/MyTinySTL/blob/master/Test/test.h) 中,用了两个类实现了一个简单的测试框架,并定义了大量宏来封装测试过程。
+ In this file [test.h](https://github.com/Alinshans/MyTinySTL/blob/master/Test/test.h), I used two class to implement a simple test framework, and defined a lot of macros to package testing process. + +## 测试内容 (Test content) + 在 [test.h](https://github.com/Alinshans/MyTinySTL/blob/master/Test/test.h) 中定义了两个宏,`PERFORMANCE_TEST_ON` 和 `LARGER_TEST_DATA_ON`。`PERFORMANCE_TEST_ON` 代表开启性能测试,默认定义为 `1`。`LARGER_TEST_DATA_ON` 代表增大测试数据,默认定义为 `0`。**如果你想把 `LARGER_TEST_DATA_ON` 设置为 `1`,建议电脑配置为:处理器 i5 或以上,内存 8G 以上。**
+ In this file [test.h](https://github.com/Alinshans/MyTinySTL/blob/master/Test/test.h), I defined two marcos: `PERFORMANCE_TEST_ON` and `LARGER_TEST_DATA_ON`. `PERFORMANCE_TEST_ON` means to run performance test, the default is defined as `1`. `LARGER_TEST_DATA_ON` means to increase the test data, the default is defined as `0`. **If you want to set `LARGER_TEST_DATA_ON` to `1`, the proposed computer configuration is: CPU i5 or above, memory 8G or more.** + + 测试案例如下:
+ The test cases are as follows: + + * [algorithm](https://github.com/Alinshans/MyTinySTL/blob/master/Test/algorithm_test.h) *(100%/100%)* + * [algorithm_performance](https://github.com/Alinshans/MyTinySTL/blob/master/Test/algorithm_performance_test.h) *(100%/100%)* + * [deque](https://github.com/Alinshans/MyTinySTL/blob/master/Test/deque_test.h) *(100%/100%)* + * [list](https://github.com/Alinshans/MyTinySTL/blob/master/Test/list_test.h) *(100%/100%)* + * [map](https://github.com/Alinshans/MyTinySTL/blob/master/Test/map_test.h) *(100%/100%)* + * map + * multimap + * [queue](https://github.com/Alinshans/MyTinySTL/blob/master/Test/queue_test.h) *(100%/100%)* + * queue + * priority_queue + * [set](https://github.com/Alinshans/MyTinySTL/blob/master/Test/set_test.h) *(100%/100%)* + * set + * multiset + * [stack](https://github.com/Alinshans/MyTinySTL/blob/master/Test/stack_test.h) *(100%/100%)* + * [string_test](https://github.com/Alinshans/MyTinySTL/blob/master/Test/string_test.h) *(100%/100%)* + * [unordered_map](https://github.com/Alinshans/MyTinySTL/blob/master/Test/unordered_map_test.h) *(100%/100%)* + * unordered_map + * unordered_multimap + * [unordered_set](https://github.com/Alinshans/MyTinySTL/blob/master/Test/unordered_set_test.h) *(100%/100%)* + * unordered_set + * unordered_multiset + * [vector](https://github.com/Alinshans/MyTinySTL/blob/master/Test/vector_test.h) *(100%/100%)* + + +## 测试结果 (Test result) + 见 [Travis CI](https://travis-ci.org/Alinshans/MyTinySTL) 和 [AppVeyor](https://ci.appveyor.com/project/Alinshans/mytinystl)。 + + See [Travis CI](https://travis-ci.org/Alinshans/MyTinySTL) and [AppVeyor](https://ci.appveyor.com/project/Alinshans/mytinystl). + diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/algorithm_performance_test.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/algorithm_performance_test.h new file mode 100644 index 0000000..675e5b2 --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/algorithm_performance_test.h @@ -0,0 +1,108 @@ +#ifndef MYTINYSTL_ALGORITHM_PERFORMANCE_TEST_H_ +#define MYTINYSTL_ALGORITHM_PERFORMANCE_TEST_H_ + +// 仅仅针对 sort, binary_search 做了性能测试 + +#include + +#include "../MyTinySTL/algorithm.h" +#include "test.h" + +namespace mystl +{ +namespace test +{ +namespace algorithm_performance_test +{ + +// 函数性能测试宏定义 +#define FUN_TEST1(mode, fun, count) do { \ + std::string fun_name = #fun; \ + srand((int)time(0)); \ + char buf[10]; \ + clock_t start, end; \ + int *arr = new int[count]; \ + for(size_t i = 0; i < count; ++i) *(arr + i) = rand(); \ + start = clock(); \ + mode::fun(arr, arr + count); \ + end = clock(); \ + int n = static_cast(static_cast(end - start) \ + / CLOCKS_PER_SEC * 1000); \ + std::snprintf(buf, sizeof(buf), "%d", n); \ + std::string t = buf; \ + t += "ms |"; \ + std::cout << std::setw(WIDE) << t; \ + delete []arr; \ +} while(0) + +#define FUN_TEST2(mode, fun, count) do { \ + std::string fun_name = #fun; \ + srand((int)time(0)); \ + char buf[10]; \ + clock_t start, end; \ + int *arr = new int[count]; \ + for(size_t i = 0; i < count; ++i) *(arr + i) = rand(); \ + start = clock(); \ + for(size_t i = 0; i < count; ++i) \ + mode::fun(arr, arr + count, rand()); \ + end = clock(); \ + int n = static_cast(static_cast(end - start) \ + / CLOCKS_PER_SEC * 1000); \ + std::snprintf(buf, sizeof(buf), "%d", n); \ + std::string t = buf; \ + t += "ms |"; \ + std::cout << std::setw(WIDE) << t; \ + delete []arr; \ +} while(0) + +void binary_search_test() +{ + std::cout << "[------------------- function : binary_search ------------------]" << std::endl; + std::cout << "| orders of magnitude |"; + TEST_LEN(LEN1, LEN2, LEN3, WIDE); + std::cout << "| std |"; + FUN_TEST2(std, binary_search, LEN1); + FUN_TEST2(std, binary_search, LEN2); + FUN_TEST2(std, binary_search, LEN3); + std::cout << std::endl << "| mystl |"; + FUN_TEST2(mystl, binary_search, LEN1); + FUN_TEST2(mystl, binary_search, LEN2); + FUN_TEST2(mystl, binary_search, LEN3); + std::cout << std::endl; +} + +void sort_test() +{ + std::cout << "[----------------------- function : sort -----------------------]" << std::endl; + std::cout << "| orders of magnitude |"; + TEST_LEN(LEN1, LEN2, LEN3, WIDE); + std::cout << "| std |"; + FUN_TEST1(std, sort, LEN1); + FUN_TEST1(std, sort, LEN2); + FUN_TEST1(std, sort, LEN3); + std::cout << std::endl << "| mystl |"; + FUN_TEST1(mystl, sort, LEN1); + FUN_TEST1(mystl, sort, LEN2); + FUN_TEST1(mystl, sort, LEN3); + std::cout << std::endl; +} + +void algorithm_performance_test() +{ + +#if PERFORMANCE_TEST_ON + std::cout << "[===============================================================]" << std::endl; + std::cout << "[--------------- Run algorithm performance test ----------------]" << std::endl; + sort_test(); + binary_search_test(); + std::cout << "[--------------- End algorithm performance test ----------------]" << std::endl; + std::cout << "[===============================================================]" << std::endl; +#endif // PERFORMANCE_TEST_ON + +} + +} // namespace algorithm_performance_test +} // namespace test +} // namespace mystl +#endif // !MYTINYSTL_ALGORITHM_PERFORMANCE_TEST_H_ + diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/algorithm_test.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/algorithm_test.h new file mode 100644 index 0000000..92eccdc --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/algorithm_test.h @@ -0,0 +1,1180 @@ +#ifndef MYTINYSTL_ALGORITHM_TEST_H_ +#define MYTINYSTL_ALGORITHM_TEST_H_ + +// 算法测试: 包含了 mystl 的 81 个算法测试 + +#include +#include +#include + +#include "../MyTinySTL/algorithm.h" +#include "../MyTinySTL/vector.h" +#include "test.h" + +namespace mystl +{ +namespace test +{ + +#ifdef max +#pragma message("#undefing marco max") +#undef max +#endif // max + +#ifdef min +#pragma message("#undefing marco min") +#undef min +#endif // min + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4389) +#endif // _MSC_VER + +namespace algorithm_test +{ + +// 一些可能会用到的辅助数据和函数 +int for_each_sum = 0; + +int gen() { return 5; } +int r(int i) { return (i * 5 + 1) % 9; } +bool is_odd(int i) { return i & 1; } +bool is_even(int i) { return !(i & 1); } +void arr_sum(int i) { for_each_sum += i; } +bool cmp(const int& a, const int& b) { return b < a; } +int unary_op(const int& x) { return x + 1; } +int binary_op(const int& x, const int& y) { return x + y; } + +// 以下为 80 个函数的简单测试 + +// algobase test: +TEST(copy_test) +{ + int arr1[] = { 1,2,3,4,5,6,7,8,9,10 }; + int exp[5], act[5]; + std::copy(arr1, arr1 + 5, exp); + mystl::copy(arr1, arr1 + 5, act); + EXPECT_CON_EQ(exp, act); + std::copy(arr1 + 5, arr1 + 10, exp); + mystl::copy(arr1 + 5, arr1 + 10, act); + EXPECT_CON_EQ(exp, act); +} + +TEST(copy_backward_test) +{ + int arr1[] = { 1,2,3,4,5 }; + std::vector exp{ 0,0,0,0,0,6,7,8,9,10 }; + int act[] = { 0,0,0,0,0,6,7,8,9,10 }; + std::copy_backward(arr1, arr1 + 5, exp.begin() + 5); + mystl::copy_backward(arr1, arr1 + 5, act + 5); + EXPECT_CON_EQ(exp, act); + std::copy_backward(exp.begin(), exp.begin() + 8, exp.begin() + 9); + mystl::copy_backward(act, act + 8, act + 9); + EXPECT_CON_EQ(exp, act); +} + +TEST(copy_if_test) +{ + int arr1[] = { 1,2,3,4,5,6,7,8,9,10 }; + int exp[5], act[5]; + std::copy_if(arr1, arr1 + 10, exp, is_odd); + mystl::copy_if(arr1, arr1 + 10, act, is_odd); + EXPECT_CON_EQ(exp, act); + std::copy_if(arr1, arr1 + 10, exp, is_even); + mystl::copy_if(arr1, arr1 + 10, act, is_even); + EXPECT_CON_EQ(exp, act); +} + +TEST(copy_n_test) +{ + int arr1[] = { 1,2,3,4,5,6,7,8,9,10 }; + int exp[10], act[10]; + std::copy_n(arr1, 10, exp); + mystl::copy_n(arr1, 10, act); + EXPECT_CON_EQ(exp, act); + std::copy_n(arr1 + 5, 5, exp); + mystl::copy_n(arr1 + 5, 5, act); + EXPECT_CON_EQ(exp, act); +} + +TEST(move_test) +{ + int arr1[] = { 1,2,3,4,5 }; + int arr2[] = { 1,2,3,4,5 }; + int exp[5], act[5]; + std::move(arr1, arr1 + 5, exp); + mystl::move(arr2, arr2 + 5, act); + EXPECT_CON_EQ(exp, act); + EXPECT_CON_EQ(arr1, arr2); +} + +TEST(move_backward_test) +{ + int arr1[] = { 1,2,3,4,5 }; + int arr2[] = { 1,2,3,4,5 }; + int exp[5], act[5]; + std::move_backward(arr1, arr1 + 5, exp + 5); + mystl::move_backward(arr2, arr2 + 5, act + 5); + EXPECT_CON_EQ(exp, act); + EXPECT_CON_EQ(arr1, arr2); +} + +TEST(equal_test) +{ + std::vector v1{ 1,2,3,4,5 }; + std::vector v2{ 1,2,3,4,5,6 }; + int arr1[] = { 1,2,3,4,5 }; + int arr2[] = { 1,2,3,4,6 }; + EXPECT_EQ(std::equal(v1.begin(), v1.end(), v2.begin()), + mystl::equal(v1.begin(), v1.end(), v2.begin())); + EXPECT_EQ(std::equal(arr1, arr1 + 5, arr2), + mystl::equal(arr1, arr1 + 5, arr2)); + EXPECT_EQ(std::equal(v1.begin(), v1.end(), arr1), + mystl::equal(v1.begin(), v1.end(), arr1)); + EXPECT_EQ(std::equal(v1.begin(), v1.end(), arr2, std::equal_to()), + mystl::equal(v1.begin(), v1.end(), arr2, std::equal_to())); +} + +TEST(fill_test) +{ + int exp[10], act[10]; + mystl::vector v1(10, 1); + mystl::vector v2(10, 2); + std::fill(exp, exp + 10, 1); + mystl::fill(act, act + 10, 1); + EXPECT_CON_EQ(exp, act); + std::fill(v1.begin(), v1.end(), 3); + mystl::fill(v2.begin(), v2.end(), 3); + EXPECT_CON_EQ(v1, v2); +} + +TEST(fill_n_test) +{ + int arr1[5]; + int arr2[5]; + std::fill_n(arr2, 5, 1); + mystl::fill_n(arr1, 5, 1); + EXPECT_CON_EQ(arr1, arr2); + std::fill_n(arr1 + 2, 3, 2); + mystl::fill_n(arr2 + 2, 3, 2); + EXPECT_CON_EQ(arr1, arr2); +} + +TEST(iter_swap_test) +{ + int a = 1; + int b = 2; + int *p1 = &a; + int *p2 = &b; + int *p3 = &a; + int *p4 = &b; + std::iter_swap(p1, p2); + mystl::iter_swap(p3, p4); + EXPECT_PTR_EQ(p1, p3); + EXPECT_PTR_EQ(p2, p4); + EXPECT_EQ(p1, p3); + EXPECT_EQ(p2, p4); +} + +TEST(lexicographical_compare_test) +{ + int arr1[] = { 1,2,3,4,5 }; + int arr2[] = { 0,2,4,6,8 }; + int arr3[] = { 1,2,3,4,5 }; + int arr4[] = { 1,2,3,4,5,6 }; + int arr5[] = { 2,3,4 }; + EXPECT_EQ(std::lexicographical_compare(arr1, arr1 + 5, arr2, arr2 + 5), + mystl::lexicographical_compare(arr1, arr1 + 5, arr2, arr2 + 5)); + EXPECT_EQ(std::lexicographical_compare(arr1, arr1 + 5, arr3, arr3 + 5), + mystl::lexicographical_compare(arr1, arr1 + 5, arr3, arr3 + 5)); + EXPECT_EQ(std::lexicographical_compare(arr1, arr1 + 5, arr4, arr4 + 6, std::less()), + mystl::lexicographical_compare(arr1, arr1 + 5, arr4, arr4 + 6, std::less())); + EXPECT_EQ(std::lexicographical_compare(arr1, arr1 + 5, arr5, arr5 + 3, std::less()), + mystl::lexicographical_compare(arr1, arr1 + 5, arr5, arr5 + 3, std::less())); +} + +TEST(max_test) +{ + int i1 = 1, i2 = 2; + double d1 = 1.1, d2 = 2.2; + char c1 = 'a', c2 = 'b'; + EXPECT_EQ(std::max(i1, i2), mystl::max(i1, i2)); + EXPECT_EQ(std::max(d1, d2), mystl::max(d1, d2)); + EXPECT_EQ(std::max(c1, c2), mystl::max(c1, c2)); +} + +TEST(min_test) +{ + int i1 = 1, i2 = 2; + double d1 = 1.1, d2 = 2.2; + char c1 = 'a', c2 = 'b'; + EXPECT_EQ(std::min(i1, i2), mystl::min(i1, i2)); + EXPECT_EQ(std::min(d1, d2), mystl::min(d1, d2)); + EXPECT_EQ(std::min(c1, c2), mystl::min(c1, c2)); +} + +TEST(mismatch_test) +{ + int arr1[] = { 1,1,2,2,3,4,5 }; + int arr2[] = { 1,1,2,2,3,3,3 }; + int arr3[] = { 0,1,2,2,3,4,5 }; + int arr4[] = { 1,1,2,2,3,4,5 }; + auto p1 = std::mismatch(arr1, arr1 + 7, arr2); + auto p2 = mystl::mismatch(arr1, arr1 + 7, arr2); + auto p3 = std::mismatch(arr1, arr1 + 7, arr3); + auto p4 = mystl::mismatch(arr1, arr1 + 7, arr3); + auto p5 = std::mismatch(arr1, arr1 + 7, arr4, std::equal_to()); + auto p6 = mystl::mismatch(arr1, arr1 + 7, arr4, std::equal_to()); + EXPECT_EQ(p1.first, p2.first); + EXPECT_EQ(p1.second, p2.second); + EXPECT_EQ(p3.first, p4.first); + EXPECT_EQ(p3.second, p4.second); + EXPECT_EQ(p5.first, p6.first); + EXPECT_EQ(p5.second, p6.second); +} + +// heap_algo test +TEST(make_heap_test) +{ + int arr1[] = { 1,2,3,4,5,6,7,8,9 }; + int arr2[] = { 1,2,3,4,5,6,7,8,9 }; + int arr3[] = { 2,1,6,5,4,9,8,7,6 }; + int arr4[] = { 2,1,6,5,4,9,8,7,6 }; + int arr5[] = { 1,1,2,2,3,3,4,4,5,5 }; + int arr6[] = { 1,1,2,2,3,3,4,4,5,5 }; + std::make_heap(arr1, arr1 + 9); + mystl::make_heap(arr2, arr2 + 9); + std::make_heap(arr3, arr3 + 9); + mystl::make_heap(arr4, arr4 + 9); + std::make_heap(arr5, arr5 + 10, std::greater()); + mystl::make_heap(arr6, arr6 + 10, std::greater()); + EXPECT_CON_EQ(arr1, arr2); + EXPECT_CON_EQ(arr3, arr4); + EXPECT_CON_EQ(arr5, arr6); +} + +TEST(pop_heap_test) +{ + int arr1[] = { 1,2,3,4,5,6,7,8,9 }; + int arr2[] = { 1,2,3,4,5,6,7,8,9 }; + std::make_heap(arr1, arr1 + 9); + std::make_heap(arr2, arr2 + 9); + for (int i = 9; i > 0; --i) + { + std::pop_heap(arr1, arr1 + i); + mystl::pop_heap(arr2, arr2 + i); + EXPECT_CON_EQ(arr1, arr2); + } + int arr3[] = { 1,2,3,4,5,6,7,8,9 }; + int arr4[] = { 1,2,3,4,5,6,7,8,9 }; + std::make_heap(arr3, arr3 + 9, std::greater()); + std::make_heap(arr4, arr4 + 9, std::greater()); + std::pop_heap(arr3, arr3 + 9, std::greater()); + mystl::pop_heap(arr4, arr4 + 9, std::greater()); + EXPECT_CON_EQ(arr3, arr4); +} + +TEST(push_heap_test) +{ + int arr1[] = { 1,2,3,4,5,6,7,8,9 }; + int arr2[] = { 1,2,3,4,5,6,7,8,9 }; + std::make_heap(arr1, arr1 + 4); + std::make_heap(arr2, arr2 + 4); + for (int i = 4; i <= 9; ++i) + { + std::push_heap(arr1, arr1 + i); + mystl::push_heap(arr2, arr2 + i); + EXPECT_CON_EQ(arr1, arr2); + } + int arr3[] = { 1,2,3,4,5,6,7,8,9 }; + int arr4[] = { 1,2,3,4,5,6,7,8,9 }; + std::make_heap(arr3, arr3 + 9, std::greater()); + std::make_heap(arr4, arr4 + 9, std::greater()); + std::push_heap(arr3, arr3 + 9, std::greater()); + mystl::push_heap(arr4, arr4 + 9, std::greater()); + EXPECT_CON_EQ(arr3, arr4); +} + +TEST(sort_heap_test) +{ + int arr1[] = { 1,2,3,4,5,6,7,8,9 }; + int arr2[] = { 1,2,3,4,5,6,7,8,9 }; + int arr3[] = { 1,2,3,4,5,6,7,8,9 }; + int arr4[] = { 1,2,3,4,5,6,7,8,9 }; + std::make_heap(arr1, arr1 + 9); + std::make_heap(arr2, arr2 + 9); + std::make_heap(arr3, arr3 + 9, std::greater()); + std::make_heap(arr4, arr4 + 9, std::greater()); + std::sort_heap(arr1, arr1 + 9); + mystl::sort_heap(arr2, arr2 + 9); + std::sort_heap(arr3, arr3 + 9, std::greater()); + mystl::sort_heap(arr4, arr4 + 9, std::greater()); + EXPECT_CON_EQ(arr1, arr2); + EXPECT_CON_EQ(arr3, arr4); +} + +// set_algo test +TEST(set_difference_test) +{ + int arr1[] = { 1,2,3,4,5,6,7,8,9 }; + int arr2[] = { 1,2,3,4,5,6 }; + int arr3[] = { 1,2,3 }; + int exp[6] = { 0 }, act[6] = { 0 }; + std::set_difference(arr1, arr1 + 9, arr2, arr2 + 6, exp); + mystl::set_difference(arr1, arr1 + 9, arr2, arr2 + 6, act); + EXPECT_CON_EQ(exp, act); + std::set_difference(arr2, arr2 + 6, arr3, arr3 + 3, exp); + mystl::set_difference(arr2, arr2 + 6, arr3, arr3 + 3, act); + EXPECT_CON_EQ(exp, act); + std::set_difference(arr1, arr1 + 9, arr3, arr3 + 3, exp, std::less()); + mystl::set_difference(arr1, arr1 + 9, arr3, arr3 + 3, act, std::less()); + EXPECT_CON_EQ(exp, act); +} + +TEST(set_intersection_test) +{ + int arr1[] = { 1,2,3,4,5,6,7,8,9 }; + int arr2[] = { 1,2,3,4,5,6 }; + int arr3[] = { 1,2,3 }; + int exp[9] = { 0 }, act[9] = { 0 }; + std::set_intersection(arr1, arr1 + 9, arr2, arr2 + 6, exp); + mystl::set_intersection(arr1, arr1 + 9, arr2, arr2 + 6, act); + EXPECT_CON_EQ(exp, act); + std::set_intersection(arr2, arr2 + 6, arr3, arr3 + 3, exp); + mystl::set_intersection(arr2, arr2 + 6, arr3, arr3 + 3, act); + EXPECT_CON_EQ(exp, act); + std::set_intersection(arr1, arr1 + 9, arr3, arr3 + 3, exp, std::less()); + mystl::set_intersection(arr1, arr1 + 9, arr3, arr3 + 3, act, std::less()); + EXPECT_CON_EQ(exp, act); +} + +TEST(set_symmetric_difference_test) +{ + int arr1[] = { 1,2,3,4,5 }; + int arr2[] = { 1,3,5,7,9 }; + int arr3[] = { 2,4,6,8,10 }; + int exp[10] = { 0 }, act[10] = { 0 }; + std::set_symmetric_difference(arr1, arr1 + 5, arr2, arr2 + 5, exp); + mystl::set_symmetric_difference(arr1, arr1 + 5, arr2, arr2 + 5, act); + EXPECT_CON_EQ(exp, act); + std::set_symmetric_difference(arr1, arr1 + 5, arr3, arr3 + 5, exp); + mystl::set_symmetric_difference(arr1, arr1 + 5, arr3, arr3 + 5, act); + EXPECT_CON_EQ(exp, act); + std::set_symmetric_difference(arr2, arr2 + 5, arr3, arr3 + 5, exp, std::less()); + mystl::set_symmetric_difference(arr2, arr2 + 5, arr3, arr3 + 5, act, std::less()); + EXPECT_CON_EQ(exp, act); +} + +TEST(set_union_test) +{ + int arr1[] = { 1,2,3,4,5 }; + int arr2[] = { 1,3,5,7,9 }; + int arr3[] = { 2,4,6,8,10 }; + int exp[10] = { 0 }, act[10] = { 0 }; + std::set_union(arr1, arr1 + 5, arr2, arr2 + 5, exp); + mystl::set_union(arr1, arr1 + 5, arr2, arr2 + 5, act); + EXPECT_CON_EQ(exp, act); + std::set_union(arr1, arr1 + 5, arr3, arr3 + 5, exp); + mystl::set_union(arr1, arr1 + 5, arr3, arr3 + 5, act); + EXPECT_CON_EQ(exp, act); + std::set_union(arr2, arr2 + 5, arr3, arr3 + 5, exp, std::less()); + mystl::set_union(arr2, arr2 + 5, arr3, arr3 + 5, act, std::less()); + EXPECT_CON_EQ(exp, act); +} + +// numeric test +TEST(accumulate_test) +{ + int arr1[] = { 1,2,3,4,5 }; + EXPECT_EQ(std::accumulate(arr1, arr1 + 5, 0), + mystl::accumulate(arr1, arr1 + 5, 0)); + EXPECT_EQ(std::accumulate(arr1, arr1 + 5, 5), + mystl::accumulate(arr1, arr1 + 5, 5)); + EXPECT_EQ(std::accumulate(arr1, arr1 + 5, 0, std::minus()), + mystl::accumulate(arr1, arr1 + 5, 0, std::minus())); +} + +TEST(adjacent_difference_test) +{ + int arr1[] = { 1,2,3,4,5 }; + int arr2[] = { 1,1,1,1,1 }; + int exp[5], act[5]; + std::adjacent_difference(arr1, arr1 + 5, exp); + mystl::adjacent_difference(arr1, arr1 + 5, act); + EXPECT_CON_EQ(exp, act); + std::adjacent_difference(arr2, arr2 + 5, exp, std::minus()); + mystl::adjacent_difference(arr2, arr2 + 5, act, std::minus()); + EXPECT_CON_EQ(exp, act); +} + +TEST(inner_product_test) +{ + int arr1[] = { 1,1,1,1,1 }; + int arr2[] = { 2,2,2,2,2 }; + int arr3[] = { 1,2,3,4,5 }; + EXPECT_EQ(std::inner_product(arr1, arr1 + 5, arr3, 0), + mystl::inner_product(arr1, arr1 + 5, arr3, 0)); + EXPECT_EQ(std::inner_product(arr2, arr2 + 5, arr3, 0, std::minus(), std::multiplies()), + mystl::inner_product(arr2, arr2 + 5, arr3, 0, std::minus(), std::multiplies())); +} + +TEST(iota_test) +{ + int arr1[10]; + int arr2[10]; + std::iota(arr1, arr1 + 10, 1); + mystl::iota(arr2, arr2 + 10, 1); + EXPECT_CON_EQ(arr1, arr2); + std::iota(arr1, arr1 + 10, -1); + mystl::iota(arr2, arr2 + 10, -1); + EXPECT_CON_EQ(arr1, arr2); +} + +TEST(partial_sum_test) +{ + int arr1[] = { 1,2,3,4,5,6,7,8,9 }; + int exp1[5], act1[5]; + int exp2[9], act2[9]; + std::partial_sum(arr1, arr1 + 5, exp1); + mystl::partial_sum(arr1, arr1 + 5, act1); + std::partial_sum(arr1, arr1 + 9, exp2); + mystl::partial_sum(arr1, arr1 + 9, act2); + EXPECT_CON_EQ(exp1, act1); + EXPECT_CON_EQ(exp2, act2); + std::partial_sum(arr1, arr1 + 9, exp2, std::multiplies()); + mystl::partial_sum(arr1, arr1 + 9, act2, std::multiplies()); + EXPECT_CON_EQ(exp2, act2); +} + +// algo test +TEST(adjacent_find_test) +{ + int arr1[] = { 1,2,3,3,4 }; + int arr2[] = { 1,2,3,4,5 }; + EXPECT_EQ(std::adjacent_find(arr1, arr1 + 5), + mystl::adjacent_find(arr1, arr1 + 5)); + EXPECT_EQ(std::adjacent_find(arr2, arr2 + 5), + mystl::adjacent_find(arr2, arr2 + 5)); + EXPECT_EQ(std::adjacent_find(arr1, arr1 + 5, std::greater()), + mystl::adjacent_find(arr1, arr1 + 5, std::greater())); +} + +TEST(all_of_test) +{ + int arr1[] = { 1,3,5,7,9 }; + int arr2[] = { 1,3,5,7,8 }; + EXPECT_EQ(std::all_of(arr1, arr1 + 5, is_odd), + mystl::all_of(arr1, arr1 + 5, is_odd)); + EXPECT_EQ(std::all_of(arr2, arr2 + 5, is_odd), + mystl::all_of(arr2, arr2 + 5, is_odd)); +} + +TEST(any_of_test) +{ + int arr1[] = { 1,2,4,6,8 }; + int arr2[] = { 2,4,6,8,10 }; + EXPECT_EQ(std::any_of(arr1, arr1 + 5, is_odd), + mystl::any_of(arr1, arr1 + 5, is_odd)); + EXPECT_EQ(std::any_of(arr2, arr2 + 5, is_odd), + mystl::any_of(arr2, arr2 + 5, is_odd)); +} + +TEST(binary_search_test) +{ + int arr1[] = { 1,2,3,4,5 }; + EXPECT_EQ(std::binary_search(arr1, arr1 + 5, 1), + mystl::binary_search(arr1, arr1 + 5, 1)); + EXPECT_EQ(std::binary_search(arr1, arr1 + 5, 6), + mystl::binary_search(arr1, arr1 + 5, 6)); +} + +TEST(count_test) +{ + int arr1[] = { 1,2,2,3,3,3,4,5,8 }; + EXPECT_EQ(std::count(arr1, arr1 + 9, 2), + mystl::count(arr1, arr1 + 9, 2)); + EXPECT_EQ(std::count(arr1, arr1 + 9, 3), + mystl::count(arr1, arr1 + 9, 3)); + EXPECT_EQ(std::count(arr1, arr1 + 9, 6), + mystl::count(arr1, arr1 + 9, 6)); +} + +TEST(count_if_test) +{ + int arr1[] = { 1,2,2,3,3,3,4,5,8 }; + EXPECT_EQ(std::count_if(arr1, arr1 + 9, is_odd), + mystl::count_if(arr1, arr1 + 9, is_odd)); + EXPECT_EQ(std::count_if(arr1, arr1 + 9, is_even), + mystl::count_if(arr1, arr1 + 9, is_even)); +} + +TEST(equal_range_test) +{ + int arr1[] = { 1,2,3,3,3,4,5 }; + auto p1 = mystl::equal_range(arr1, arr1 + 7, 3); + auto p2 = std::equal_range(arr1, arr1 + 7, 3); + auto p3 = mystl::equal_range(arr1, arr1 + 7, 6, std::equal_to()); + auto p4 = std::equal_range(arr1, arr1 + 7, 6, std::equal_to()); + EXPECT_EQ(p2.first, p1.first); + EXPECT_EQ(p2.second, p1.second); + EXPECT_EQ(p4.first, p3.first); + EXPECT_EQ(p4.second, p3.second); +} + +TEST(find_test) +{ + int arr1[] = { 1,2,3,4,5 }; + EXPECT_EQ(std::find(arr1, arr1 + 5, 3), mystl::find(arr1, arr1 + 5, 3)); + EXPECT_EQ(std::find(arr1, arr1 + 5, 6), mystl::find(arr1, arr1 + 5, 6)); +} + +TEST(find_end_test) +{ + int arr1[] = { 1,2,3,2,2,3,4,5 }; + int arr2[] = { 2,3 }; + int arr3[] = { 4,5,6 }; + EXPECT_EQ(std::find_end(arr1, arr1 + 8, arr2, arr2 + 1), + mystl::find_end(arr1, arr1 + 8, arr2, arr2 + 1)); + EXPECT_EQ(std::find_end(arr1, arr1 + 8, arr3, arr3 + 2), + mystl::find_end(arr1, arr1 + 8, arr3, arr3 + 2)); + EXPECT_EQ(std::find_end(arr1, arr1 + 8, arr3, arr3 + 2), + mystl::find_end(arr1, arr1 + 8, arr3, arr3 + 2)); + EXPECT_EQ(std::find_end(arr1, arr1 + 8, arr3, arr3, std::less()), + mystl::find_end(arr1, arr1 + 8, arr3, arr3, std::less())); +} + +TEST(find_first_of_test) +{ + int arr1[] = { 1,2,3,4,5 }; + int arr2[] = { 2,3,4 }; + int arr3[] = { 6,7,8 }; + EXPECT_EQ(std::find_first_of(arr1, arr1 + 5, arr2, arr2 + 3), + mystl::find_first_of(arr1, arr1 + 5, arr2, arr2 + 3)); + EXPECT_EQ(std::find_first_of(arr1, arr1 + 5, arr3, arr3 + 3, std::equal_to()), + mystl::find_first_of(arr1, arr1 + 5, arr3, arr3 + 3, std::equal_to())); +} + +TEST(find_if_test) +{ + int arr1[] = { 1,2,3,4,5 }; + EXPECT_EQ(std::find_if(arr1, arr1 + 5, is_odd), + mystl::find_if(arr1, arr1 + 5, is_odd)); + EXPECT_EQ(std::find_if(arr1, arr1 + 5, is_even), + mystl::find_if(arr1, arr1 + 5, is_even)); +} + +TEST(find_if_not_test) +{ + int arr1[] = { 1,2,3,4,5 }; + EXPECT_EQ(std::find_if_not(arr1, arr1 + 5, is_odd), + mystl::find_if_not(arr1, arr1 + 5, is_odd)); + EXPECT_EQ(std::find_if_not(arr1, arr1 + 5, is_even), + mystl::find_if_not(arr1, arr1 + 5, is_even)); +} + +TEST(for_each_test) +{ + std::vector v1{ 1,2,3,4,5 }; + std::for_each(v1.begin(), v1.end(), arr_sum); + EXPECT_EQ(15, for_each_sum); + mystl::for_each(v1.begin(), v1.end(), arr_sum); + EXPECT_EQ(30, for_each_sum); +} + +TEST(generate_test) +{ + int arr1[5]; + int arr2[5]; + std::generate(arr1, arr1 + 5, gen); + mystl::generate(arr2, arr2 + 5, gen); + EXPECT_CON_EQ(arr1, arr2); +} + +TEST(generate_n_test) +{ + int arr1[] = { 1,1,1,1,1,6,7,8,9,10 }; + int arr2[] = { 2,2,2,2,2,6,7,8,9,10 }; + std::generate_n(arr1, 5, gen); + mystl::generate_n(arr2, 5, gen); + EXPECT_CON_EQ(arr1, arr2); +} + +TEST(includes_test) +{ + std::vector v1{ 1,2,3,4,5,6,7,8,9 }; + std::vector v2{ 2,3,5,6,9 }; + std::vector v3{ 0,1,2,3,4 }; + std::vector v4{ 1,2,5,7,10 }; + std::vector v5; + EXPECT_EQ(std::includes(v1.begin(), v1.end(), v2.begin(), v2.end()), + mystl::includes(v1.begin(), v1.end(), v2.begin(), v2.end())); + EXPECT_EQ(std::includes(v1.begin(), v1.end(), v3.begin(), v3.end()), + mystl::includes(v1.begin(), v1.end(), v3.begin(), v3.end())); + EXPECT_EQ(std::includes(v1.begin(), v1.end(), v4.begin(), v4.end()), + mystl::includes(v1.begin(), v1.end(), v4.begin(), v4.end())); + EXPECT_EQ(std::includes(v1.begin(), v1.end(), v5.begin(), v5.end(), std::less()), + mystl::includes(v1.begin(), v1.end(), v5.begin(), v5.end(), std::less())); +} + +TEST(inplace_merge_test) +{ + int arr1[] = { 1,3,5,7,9,2,4,6,8,10 }; + int arr2[] = { 1,3,5,7,9,2,4,6,8,10 }; + int arr3[] = { 1,2,3,1,2,3,4,5 }; + int arr4[] = { 1,2,3,1,2,3,4,5 }; + std::inplace_merge(arr1, arr1 + 5, arr1 + 10); + mystl::inplace_merge(arr2, arr2 + 5, arr2 + 10); + std::inplace_merge(arr3, arr3 + 3, arr3 + 8, std::less()); + mystl::inplace_merge(arr4, arr4 + 3, arr4 + 8, std::less()); + EXPECT_CON_EQ(arr1, arr2); + EXPECT_CON_EQ(arr3, arr4); +} + +TEST(is_heap_test) +{ + int arr1[] = { 0,1,2,3,4,5,6,7,8,9 }; + int arr2[] = { 9,8,7,6,5,4,3,2,1,0 }; + int arr3[] = { 1,3,5,7,9,0,2,4,6,8 }; + int arr4[] = { 0,1,2,3,4,5,6,7,8,9 }; + std::make_heap(arr4, arr4 + 10); + EXPECT_EQ(std::is_heap(arr1, arr1 + 10), mystl::is_heap(arr1, arr1 + 10)); + EXPECT_EQ(std::is_heap(arr2, arr2 + 10, std::less()), + mystl::is_heap(arr2, arr2 + 10, std::less())); + EXPECT_EQ(std::is_heap(arr3, arr3 + 10), mystl::is_heap(arr3, arr3 + 10)); + EXPECT_EQ(std::is_heap(arr4, arr4 + 10), mystl::is_heap(arr4, arr4 + 10)); +} + +TEST(is_sorted_test) +{ + int arr1[] = { 1,2,3,4,5 }; + int arr2[] = { 1,2,3,5,4 }; + int arr3[] = { 5,4,3,2,1 }; + int arr4[] = { 1,2,5,4,3 }; + EXPECT_EQ(std::is_sorted(arr1, arr1 + 5), mystl::is_sorted(arr1, arr1 + 5)); + EXPECT_EQ(std::is_sorted(arr2, arr2 + 5), mystl::is_sorted(arr2, arr2 + 5)); + EXPECT_EQ(std::is_sorted(arr3, arr3 + 5, std::less()), + mystl::is_sorted(arr3, arr3 + 5, std::less())); + EXPECT_EQ(std::is_sorted(arr4, arr4 + 5, std::less()), + mystl::is_sorted(arr4, arr4 + 5, std::less())); +} + +TEST(lower_bound_test) +{ + int arr1[] = { 1,2,3,3,3,4,5 }; + EXPECT_EQ(std::lower_bound(arr1, arr1 + 7, 1), + mystl::lower_bound(arr1, arr1 + 7, 1)); + EXPECT_EQ(std::lower_bound(arr1, arr1 + 7, 2), + mystl::lower_bound(arr1, arr1 + 7, 2)); + EXPECT_EQ(std::lower_bound(arr1, arr1 + 7, 3), + mystl::lower_bound(arr1, arr1 + 7, 3)); + EXPECT_EQ(std::lower_bound(arr1, arr1 + 7, 5, std::less()), + mystl::lower_bound(arr1, arr1 + 7, 5, std::less())); +} + +TEST(max_elememt_test) +{ + int arr1[] = { 1,2,3,4,5,4,3,2,1 }; + double arr2[] = { 1.0,2.2,6.6,8.8,8.81,2.4 }; + EXPECT_PTR_EQ(std::max_element(arr1, arr1 + 9), + mystl::max_element(arr1, arr1 + 9)); + EXPECT_PTR_EQ(std::max_element(arr2, arr2 + 6, std::less()), + mystl::max_element(arr2, arr2 + 6, std::less())); +} + +TEST(median_test) +{ + int ia = 2, ib = 1, ic = 3; + double da = 3.1, db = 3.0, dc = 3.2; + EXPECT_EQ(2, mystl::median(ia, ib, ic)); + EXPECT_EQ(3.1, mystl::median(da, db, dc, std::greater())); +} + +TEST(merge_test) +{ + int arr1[] = { 1,2,5,9,10 }; + int arr2[] = { 3,7,8,8,9 }; + int arr3[] = { 1,2,5,9,10 }; + int arr4[] = { 3,7,8,8,9 }; + int exp[10], act[10]; + std::merge(arr1, arr1 + 5, arr2, arr2 + 5, exp); + mystl::merge(arr3, arr3 + 5, arr4, arr4 + 5, act); + EXPECT_CON_EQ(exp, act); + std::merge(arr1, arr1 + 5, arr2, arr2 + 5, exp, std::less()); + mystl::merge(arr3, arr3 + 5, arr4, arr4 + 5, act, std::less()); + EXPECT_CON_EQ(exp, act); +} + +TEST(min_elememt_test) +{ + int arr1[] = { 2,4,8,1,6,5,8,9,3 }; + double arr2[] = { 1.5,2.2,1.4,1.33,1.333,2.33 }; + EXPECT_PTR_EQ(std::max_element(arr1, arr1 + 9), + mystl::max_element(arr1, arr1 + 9)); + EXPECT_PTR_EQ(std::max_element(arr2, arr2 + 6, std::less()), + mystl::max_element(arr2, arr2 + 6, std::less())); +} + +TEST(is_permutation_test) +{ + int arr1[] = { 1,2,3,4,5 }; + int arr2[] = { 3,4,5,2,1 }; + int arr3[] = { 1,2,3,4,6 }; + // 因为提供的是 C++11 的支持,std::is_permutation 可能没有 C++14 的接口 + EXPECT_EQ(std::is_permutation(arr1, arr1 + 5, arr2), + mystl::is_permutation(arr1, arr1 + 5, arr2, arr2 + 5)); + EXPECT_EQ(std::is_permutation(arr1, arr1 + 5, arr3), + mystl::is_permutation(arr1, arr1 + 5, arr3, arr3 + 5)); + EXPECT_EQ(std::is_permutation(arr1, arr1 + 5, arr2, std::equal_to()), + mystl::is_permutation(arr1, arr1 + 5, arr2, arr2 + 5, std::equal_to())); + EXPECT_EQ(std::is_permutation(arr1, arr1 + 5, arr3, std::equal_to()), + mystl::is_permutation(arr1, arr1 + 5, arr3, arr3 + 5, std::equal_to())); +} + +TEST(next_permutation_test) +{ + int arr1[] = { 1,2,3,3 }; + int arr2[] = { 1,2,3,3 }; + int n1 = 0, n2 = 0; + while (std::next_permutation(arr1, arr1 + 4)) n1++; + while (mystl::next_permutation(arr1, arr1 + 4)) n2++; + EXPECT_EQ(n1, n2); + for (; n1 > 0; n1--) + { + std::next_permutation(arr1, arr1 + 4); + mystl::next_permutation(arr2, arr2 + 4); + EXPECT_CON_EQ(arr1, arr2); + } + std::next_permutation(arr1, arr1 + 4, std::greater()); + mystl::next_permutation(arr2, arr2 + 4, std::greater()); + EXPECT_CON_EQ(arr1, arr2); +} + +TEST(none_of_test) +{ + int arr1[] = { 1,3,5,7,9 }; + int arr2[] = { 1,3,5,7,8 }; + int arr3[] = { 2,4,6,8,10 }; + EXPECT_EQ(std::none_of(arr1, arr1 + 5, is_even), + mystl::none_of(arr1, arr1 + 5, is_even)); + EXPECT_EQ(std::none_of(arr2, arr2 + 5, is_even), + mystl::none_of(arr2, arr2 + 5, is_even)); + EXPECT_EQ(std::none_of(arr3, arr3 + 5, is_even), + mystl::none_of(arr3, arr3 + 5, is_even)); +} + +TEST(nth_element_test) +{ + int arr1[] = { 9,8,7,6,5,4,3,2,1 }; + int arr2[] = { 1,2,3,4,5,6,3,2,1 }; + int arr3[] = { 1,2,8,9,6,5,3,4,7 }; + int arr4[] = { 1,5,1,5,8,4,9,6,8,4,10,13,20,4,2,1 }; + mystl::nth_element(arr1, arr1 + 4, arr1 + 9); + mystl::nth_element(arr2, arr2 + 2, arr2 + 9); + mystl::nth_element(arr3, arr3 + 8, arr3 + 9, std::less()); + mystl::nth_element(arr4, arr4 + 3, arr4 + 16, std::less()); + bool arr1_left_less = true, arr1_right_greater = true; + bool arr2_left_less = true, arr2_right_greater = true; + bool arr3_left_less = true, arr3_right_greater = true; + bool arr4_left_less = true, arr4_right_greater = true; + for (int i = 0; i < 9; ++i) + { + if (i < 4 && arr1[i] > arr1[4]) arr1_left_less = false; + else if (i > 4 && arr1[i] < arr1[4]) arr1_right_greater = false; + } + for (int i = 0; i < 9; ++i) + { + if (i < 2 && arr2[i] > arr2[2]) arr2_left_less = false; + else if (i > 2 && arr2[i] < arr2[2]) arr2_right_greater = false; + } + for (int i = 0; i < 9; ++i) + { + if (i < 8 && arr3[i] > arr3[8]) arr3_left_less = false; + } + for (int i = 0; i < 16; ++i) + { + if (i < 3 && arr4[i] > arr4[3]) arr4_left_less = false; + else if (i > 3 && arr4[i] < arr4[3]) arr4_right_greater = false; + } + EXPECT_TRUE(arr1_left_less); + EXPECT_TRUE(arr1_right_greater); + EXPECT_TRUE(arr2_left_less); + EXPECT_TRUE(arr2_right_greater); + EXPECT_TRUE(arr3_left_less); + EXPECT_TRUE(arr3_right_greater); + EXPECT_TRUE(arr4_left_less); + EXPECT_TRUE(arr4_right_greater); +} + +TEST(partial_sort_test) +{ + int arr1[] = { 3,2,1,9,8,7,6,5,4 }; + int arr2[] = { 3,2,1,9,8,7,6,5,4 }; + int arr3[] = { 5,1,5,8,6,4,8,4,1,3,5,8,4 }; + int arr4[] = { 5,1,5,8,6,4,8,4,1,3,5,8,4 }; + std::partial_sort(arr1, arr1 + 2, arr1 + 9); + mystl::partial_sort(arr2, arr2 + 2, arr2 + 9); + std::partial_sort(arr3, arr3 + 5, arr3 + 13, std::greater()); + mystl::partial_sort(arr4, arr4 + 5, arr4 + 13, std::greater()); + EXPECT_CON_EQ(arr1, arr2); + EXPECT_CON_EQ(arr3, arr4); +} + +TEST(partial_sort_copy_test) +{ + int arr1[] = { 3,2,1,9,8,7,6,5,4 }; + int arr2[] = { 1,2,3,4,5,6,7,8,9 }; + int arr3[] = { 1,6,8,4,2,1,6,8,4,7,6,2,1,3,6 }; + int exp[5], act[5]; + std::partial_sort_copy(arr1, arr1 + 9, exp, exp + 5); + mystl::partial_sort_copy(arr1, arr1 + 9, act, act + 5); + EXPECT_CON_EQ(exp, act); + std::partial_sort_copy(arr2, arr2 + 9, exp, exp + 5); + mystl::partial_sort_copy(arr2, arr2 + 9, act, act + 5); + EXPECT_CON_EQ(exp, act); + std::partial_sort_copy(arr3, arr3 + 15, exp, exp + 5, std::greater()); + mystl::partial_sort_copy(arr3, arr3 + 15, act, act + 5, std::greater()); + EXPECT_CON_EQ(exp, act); +} + +TEST(partition_test) +{ + int arr1[] = { 1,2,3,4,5,6,7,8,9 }; + int arr2[] = { 1,2,3,4,5,6,7,8,9 }; + std::partition(arr1, arr1 + 9, is_odd); + mystl::partition(arr2, arr2 + 9, is_odd); + EXPECT_CON_EQ(arr1, arr2); + std::partition(arr1, arr1 + 9, is_even); + mystl::partition(arr2, arr2 + 9, is_even); + EXPECT_CON_EQ(arr1, arr2); +} + +TEST(partition_copy_test) +{ + int arr1[] = { 1,2,3,4,5,6,7,8,9,10 }; + int exp_true[5], exp_false[5]; + int act_true[5], act_false[5]; + std::partition_copy(arr1, arr1 + 10, exp_true, exp_false, is_odd); + mystl::partition_copy(arr1, arr1 + 10, act_true, act_false, is_odd); + EXPECT_CON_EQ(exp_true, act_true); + EXPECT_CON_EQ(exp_false, act_false); +} + +TEST(prev_permutation_test) +{ + int arr1[] = { 3,2,1,1 }; + int arr2[] = { 3,2,1,1 }; + int n1 = 0, n2 = 0; + while (std::prev_permutation(arr1, arr1 + 4)) n1++; + while (mystl::prev_permutation(arr1, arr1 + 4)) n2++; + EXPECT_EQ(n1, n2); + for (; n1 > 0; n1--) + { + std::prev_permutation(arr1, arr1 + 4); + mystl::prev_permutation(arr2, arr2 + 4); + EXPECT_CON_EQ(arr1, arr2); + } + std::prev_permutation(arr1, arr1 + 4, std::greater()); + mystl::prev_permutation(arr2, arr2 + 4, std::greater()); + EXPECT_CON_EQ(arr1, arr2); +} + +TEST(random_shuffle_test) +{ + int arr1[] = { 1,2,3,4,5,6,7,8,9 }; + int arr2[9]; + for (int i = 0; i < 9; ++i) + { + std::copy(arr1, arr1 + 9, arr2); + mystl::random_shuffle(arr1, arr1 + 9); + EXPECT_CON_NE(arr1, arr2); + } + std::copy(arr1, arr1 + 9, arr2); + mystl::random_shuffle(arr1, arr1 + 9, r); + EXPECT_CON_NE(arr1, arr2); +} + +TEST(remove_test) +{ + std::vector v1{ 1,2,3,4,5,6,6,6 }; + std::vector v2(v1); + std::remove(v1.begin(), v1.end(), 3); + mystl::remove(v2.begin(), v2.end(), 3); + EXPECT_CON_EQ(v1, v2); + std::remove(v1.begin(), v1.end(), 6); + mystl::remove(v2.begin(), v2.end(), 6); + EXPECT_CON_EQ(v1, v2); +} + +TEST(remove_copy_test) +{ + int arr1[] = { 1,2,3,4,5,6,6,6 }; + int arr2[] = { 1,2,3,4,5,6,6,6 }; + int exp[5], act[5]; + std::remove_copy(arr1, arr1 + 8, exp, 6); + mystl::remove_copy(arr2, arr2 + 8, act, 6); + EXPECT_CON_EQ(exp, act); + std::remove_copy(arr1, arr1 + 5, exp, 3); + mystl::remove_copy(arr2, arr2 + 5, act, 3); + EXPECT_CON_EQ(exp, act); +} + +TEST(remove_copy_if_test) +{ + int arr1[] = { 1,2,3,4,5,6,7,8,9,10 }; + int exp[5], act[5]; + std::remove_copy_if(arr1, arr1 + 10, exp, is_odd); + mystl::remove_copy_if(arr1, arr1 + 10, act, is_odd); + EXPECT_CON_EQ(exp, act); + std::remove_copy_if(arr1, arr1 + 10, exp, is_even); + mystl::remove_copy_if(arr1, arr1 + 10, act, is_even); + EXPECT_CON_EQ(exp, act); +} + +TEST(remove_if_test) +{ + std::vector v1{ 1,2,3,4,5,6,7,8,9,10 }; + std::vector v2(v1); + std::remove_if(v1.begin(), v1.end(), is_odd); + mystl::remove_if(v2.begin(), v2.end(), is_odd); + EXPECT_CON_EQ(v1, v2); +} + +TEST(replace_test) +{ + int arr1[] = { 1,1,1,2,2,2,3,3,3 }; + int arr2[] = { 1,1,1,2,2,2,3,3,3 }; + std::replace(arr1, arr1 + 9, 1, 4); + mystl::replace(arr2, arr2 + 9, 1, 4); + EXPECT_CON_EQ(arr1, arr2); + std::replace(arr1, arr1 + 9, 2, 5); + mystl::replace(arr2, arr2 + 9, 2, 5); + EXPECT_CON_EQ(arr1, arr2); + std::replace(arr1, arr1 + 9, 3, 6); + mystl::replace(arr2, arr2 + 9, 3, 6); + EXPECT_CON_EQ(arr1, arr2); +} + +TEST(replace_copy_test) +{ + int arr1[] = { 1,1,1,2,2,2,3,3,3 }; + int exp[9], act[9]; + std::replace_copy(arr1, arr1 + 9, exp, 1, 4); + mystl::replace_copy(arr1, arr1 + 9, act, 1, 4); + EXPECT_CON_EQ(exp, act); + std::replace_copy(arr1, arr1 + 9, exp, 2, 5); + mystl::replace_copy(arr1, arr1 + 9, act, 2, 5); + EXPECT_CON_EQ(exp, act); + std::replace_copy(arr1, arr1 + 9, exp, 3, 6); + mystl::replace_copy(arr1, arr1 + 9, act, 3, 6); + EXPECT_CON_EQ(exp, act); +} + +TEST(replace_copy_if_test) +{ + int arr1[] = { 1,2,3,4,5,6,7,8,9,10 }; + int exp[10] = { 0 }, act[10] = { 0 }; + std::replace_copy_if(arr1, arr1 + 10, exp, is_odd, 1); + mystl::replace_copy_if(arr1, arr1 + 10, act, is_odd, 1); + EXPECT_CON_EQ(exp, act); + std::replace_copy_if(arr1, arr1 + 10, exp, is_even, 2); + mystl::replace_copy_if(arr1, arr1 + 10, act, is_even, 2); + EXPECT_CON_EQ(exp, act); +} + +TEST(replace_if_test) +{ + std::vector v1{ 1,2,3,4,5,6,7,8,9,10 }; + std::vector v2(v1); + std::replace_if(v1.begin(), v1.end(), is_odd, 1); + mystl::replace_if(v2.begin(), v2.end(), is_odd, 1); + EXPECT_CON_EQ(v1, v2); + std::replace_if(v1.begin(), v1.end(), is_even, 2); + mystl::replace_if(v2.begin(), v2.end(), is_even, 2); + EXPECT_CON_EQ(v1, v2); +} + +TEST(reverse_test) +{ + int arr1[] = { 1,2,3,4,5,6,7,8,9 }; + int arr2[] = { 1,2,3,4,5,6,7,8,9 }; + std::reverse(arr1, arr1 + 9); + mystl::reverse(arr2, arr2 + 9); + EXPECT_CON_EQ(arr1, arr2); + std::reverse(arr1, arr1 + 5); + mystl::reverse(arr2, arr2 + 5); + EXPECT_CON_EQ(arr1, arr2); +} + +TEST(reverse_copy_test) +{ + int arr1[] = { 1,2,3,4,5,6,7,8,9 }; + int exp[5], act[5]; + std::reverse_copy(arr1, arr1 + 5, exp); + mystl::reverse_copy(arr1, arr1 + 5, act); + EXPECT_CON_EQ(exp, act); + std::reverse_copy(arr1 + 4, arr1 + 9, exp); + mystl::reverse_copy(arr1 + 4, arr1 + 9, act); + EXPECT_CON_EQ(exp, act); +} + +TEST(rotate_test) +{ + int arr1[] = { 1,2,3,4,5,6,7,8,9 }; + int arr2[] = { 1,2,3,4,5,6,7,8,9 }; + std::rotate(arr1, arr1 + 3, arr1 + 9); + mystl::rotate(arr2, arr2 + 3, arr2 + 9); + EXPECT_CON_EQ(arr1, arr2); + std::rotate(arr1 + 3, arr1 + 5, arr1 + 9); + mystl::rotate(arr2 + 3, arr2 + 5, arr2 + 9); + EXPECT_CON_EQ(arr1, arr2); + std::rotate(arr1, arr1 + 9, arr1 + 9); + mystl::rotate(arr2, arr2 + 9, arr2 + 9); + EXPECT_CON_EQ(arr1, arr2); +} + +TEST(rotate_copy_test) +{ + int arr1[] = { 1,2,3,4,5,6,7,8,9 }; + int exp[9], act[9]; + std::rotate_copy(arr1, arr1 + 5, arr1 + 9, exp); + mystl::rotate_copy(arr1, arr1 + 5, arr1 + 9, act); + EXPECT_CON_EQ(exp, act); + std::rotate_copy(arr1, arr1, arr1 + 9, exp); + mystl::rotate_copy(arr1, arr1, arr1 + 9, act); + EXPECT_CON_EQ(exp, act); + std::rotate_copy(arr1, arr1 + 9, arr1 + 9, exp); + mystl::rotate_copy(arr1, arr1 + 9, arr1 + 9, act); + EXPECT_CON_EQ(exp, act); +} + +TEST(search_test) +{ + int arr1[] = { 1,2,3,3,3,4,5,6,6, }; + int arr2[] = { 1 }; + int arr3[] = { 3,3 }; + int arr4[] = { 5,6,6,6 }; + EXPECT_EQ(std::search(arr1, arr1 + 9, arr2, arr2 + 1), + mystl::search(arr1, arr1 + 9, arr2, arr2 + 1)); + EXPECT_EQ(std::search(arr1, arr1 + 9, arr3, arr3 + 2), + mystl::search(arr1, arr1 + 9, arr3, arr3 + 2)); + EXPECT_EQ(std::search(arr1, arr1 + 9, arr4, arr4 + 3, std::less()), + mystl::search(arr1, arr1 + 9, arr4, arr4 + 3, std::less())); + EXPECT_EQ(std::search(arr1, arr1 + 9, arr4, arr4 + 4, std::less()), + mystl::search(arr1, arr1 + 9, arr4, arr4 + 4, std::less())); +} + +TEST(search_n_test) +{ + int arr1[] = { 1,2,2,3,3,3,6,6,9 }; + EXPECT_EQ(std::search_n(arr1, arr1 + 9, 1, 0), + mystl::search_n(arr1, arr1 + 9, 1, 0)); + EXPECT_EQ(std::search_n(arr1, arr1 + 9, 2, 2), + mystl::search_n(arr1, arr1 + 9, 2, 2)); + EXPECT_EQ(std::search_n(arr1, arr1 + 9, 1, 3), + mystl::search_n(arr1, arr1 + 9, 1, 3)); + EXPECT_EQ(std::search_n(arr1, arr1 + 9, 3, 6, std::less()), + mystl::search_n(arr1, arr1 + 9, 3, 6, std::less())); + EXPECT_EQ(std::search_n(arr1, arr1 + 9, 2, 10, std::less()), + mystl::search_n(arr1, arr1 + 9, 2, 10, std::less())); +} + +TEST(sort_test) +{ + int arr1[] = { 6,1,2,5,4,8,3,2,4,6,10,2,1,9 }; + int arr2[] = { 6,1,2,5,4,8,3,2,4,6,10,2,1,9 }; + int arr3[] = { 80,30,51,65,12,10,24,87,62,51,32,45,1,33,66,20,35,84,62,14 }; + int arr4[] = { 80,30,51,65,12,10,24,87,62,51,32,45,1,33,66,20,35,84,62,14 }; + int arr5[] = { 9,9,9,8,8,8,7,7,7 }; + int arr6[] = { 9,9,9,8,8,8,7,7,7 }; + std::sort(arr1, arr1 + 14); + mystl::sort(arr2, arr2 + 14); + std::sort(arr3, arr3 + 20); + mystl::sort(arr4, arr4 + 20); + std::sort(arr5, arr5 + 9, std::greater()); + mystl::sort(arr6, arr6 + 9, std::greater()); + EXPECT_CON_EQ(arr1, arr2); + EXPECT_CON_EQ(arr3, arr4); + EXPECT_CON_EQ(arr5, arr6); +} + +TEST(swap_ranges_test) +{ + int arr1[] = { 4,5,6,1,2,3 }; + int arr2[] = { 4,5,6,1,2,3 }; + int arr3[] = { 1,2,3,4,5,6 }; + int arr4[] = { 1,2,3,4,5,6 }; + int arr5[] = { 1,1,1 }; + int arr6[] = { 1,1,1 }; + std::swap_ranges(arr1, arr1 + 6, arr3); + mystl::swap_ranges(arr2, arr2 + 6, arr4); + std::swap_ranges(arr1, arr1 + 3, arr5); + mystl::swap_ranges(arr2, arr2 + 3, arr6); + EXPECT_CON_EQ(arr1, arr2); + EXPECT_CON_EQ(arr1, arr2); +} + +TEST(transform_test) +{ + int arr1[] = { 1,2,3,4,5,6,7,8,9 }; + int arr2[] = { 9,8,7,6,5,4,3,2,1 }; + int exp[9], act[9]; + std::transform(arr1, arr1 + 9, exp, unary_op); + mystl::transform(arr1, arr1 + 9, act, unary_op); + EXPECT_CON_EQ(exp, act); + std::transform(arr1, arr1 + 9, arr2, exp, binary_op); + mystl::transform(arr1, arr1 + 9, arr2, act, binary_op); + EXPECT_CON_EQ(exp, act); +} + +TEST(unique_test) +{ + int arr1[] = { 1,1,1,2,2,3,4,4,5,6 }; + int arr2[] = { 1,1,1,2,2,3,4,4,5,6 }; + int arr3[] = { 1,2,3,6,6,6,8,8,9 }; + int arr4[] = { 1,2,3,6,6,6,8,8,9 }; + std::unique(arr1, arr1 + 10); + mystl::unique(arr2, arr2 + 10); + std::unique(arr3, arr3 + 9, std::equal_to()); + mystl::unique(arr4, arr4 + 9, std::equal_to()); + EXPECT_CON_EQ(arr1, arr2); + EXPECT_CON_EQ(arr3, arr4); +} + +TEST(unique_copy_test) +{ + int arr1[] = { 1,1,1,2,2,3,4,4,5,6 }; + int arr2[] = { 1,2,3,6,6,6,8,8,9 }; + int exp[6], act[6]; + std::unique_copy(arr1, arr1 + 10, exp); + mystl::unique_copy(arr1, arr1 + 10, act); + EXPECT_CON_EQ(exp, act); + std::unique_copy(arr2, arr2 + 9, exp, std::equal_to()); + mystl::unique_copy(arr2, arr2 + 9, act, std::equal_to()); + EXPECT_CON_EQ(exp, act); +} + +TEST(upper_bound_test) +{ + int arr1[] = { 1,2,3,3,3,4,5,6,6 }; + EXPECT_EQ(std::upper_bound(arr1, arr1 + 9, 0), + mystl::upper_bound(arr1, arr1 + 9, 0)); + EXPECT_EQ(std::upper_bound(arr1, arr1 + 9, 1), + mystl::upper_bound(arr1, arr1 + 9, 1)); + EXPECT_EQ(std::upper_bound(arr1, arr1 + 9, 3), + mystl::upper_bound(arr1, arr1 + 9, 3)); + EXPECT_EQ(std::upper_bound(arr1, arr1 + 9, 6, std::less()), + mystl::upper_bound(arr1, arr1 + 9, 6, std::less())); + EXPECT_EQ(std::upper_bound(arr1, arr1 + 9, 7, std::less()), + mystl::upper_bound(arr1, arr1 + 9, 7, std::less())); +} + +} // namespace algorithm_test + +#ifdef _MSC_VER +#pragma warning(pop) +#endif // _MSC_VER + +} // namespace test +} // namespace mystl +#endif // !MYTINYSTL_ALGORITHM_TEST_H_ diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/deque_test.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/deque_test.h new file mode 100644 index 0000000..0793bf6 --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/deque_test.h @@ -0,0 +1,102 @@ +#ifndef MYTINYSTL_DEQUE_TEST_H_ +#define MYTINYSTL_DEQUE_TEST_H_ + +// deque test : 测试 deque 的接口和 push_front/push_back 的性能 + +#include + +#include "../MyTinySTL/deque.h" +#include "test.h" + +namespace mystl +{ +namespace test +{ +namespace deque_test +{ + +void deque_test() +{ + std::cout << "[===============================================================]" << std::endl; + std::cout << "[----------------- Run container test : deque ------------------]" << std::endl; + std::cout << "[-------------------------- API test ---------------------------]" << std::endl; + int a[] = { 1,2,3,4,5 }; + mystl::deque d1; + mystl::deque d2(5); + mystl::deque d3(5, 1); + mystl::deque d4(a, a + 5); + mystl::deque d5(d2); + mystl::deque d6(std::move(d2)); + mystl::deque d7; + d7 = d3; + mystl::deque d8; + d8 = std::move(d3); + mystl::deque d9{ 1,2,3,4,5,6,7,8,9 }; + mystl::deque d10; + d10 = { 1,2,3,4,5,6,7,8,9 }; + + FUN_AFTER(d1, d1.assign(5, 1)); + FUN_AFTER(d1, d1.assign(8, 8)); + FUN_AFTER(d1, d1.assign(a, a + 5)); + FUN_AFTER(d1, d1.assign({ 1,2,3,4,5 })); + FUN_AFTER(d1, d1.insert(d1.end(), 6)); + FUN_AFTER(d1, d1.insert(d1.end() - 1, 2, 7)); + FUN_AFTER(d1, d1.insert(d1.begin(), a, a + 5)); + FUN_AFTER(d1, d1.erase(d1.begin())); + FUN_AFTER(d1, d1.erase(d1.begin(), d1.begin() + 4)); + FUN_AFTER(d1, d1.emplace_back(8)); + FUN_AFTER(d1, d1.emplace_front(8)); + FUN_AFTER(d1, d1.emplace(d1.begin() + 1, 9)); + FUN_AFTER(d1, d1.push_front(1)); + FUN_AFTER(d1, d1.push_back(2)); + FUN_AFTER(d1, d1.pop_back()); + FUN_AFTER(d1, d1.pop_front()); + FUN_AFTER(d1, d1.shrink_to_fit()); + FUN_AFTER(d1, d1.resize(5)); + FUN_AFTER(d1, d1.resize(8, 8)); + FUN_AFTER(d1, d1.clear()); + FUN_AFTER(d1, d1.shrink_to_fit()); + FUN_AFTER(d1, d1.swap(d4)); + FUN_VALUE(*(d1.begin())); + FUN_VALUE(*(d1.end() - 1)); + FUN_VALUE(*(d1.rbegin())); + FUN_VALUE(*(d1.rend() - 1)); + FUN_VALUE(d1.front()); + FUN_VALUE(d1.back()); + FUN_VALUE(d1.at(1)); + FUN_VALUE(d1[2]); + std::cout << std::boolalpha; + FUN_VALUE(d1.empty()); + std::cout << std::noboolalpha; + FUN_VALUE(d1.size()); + FUN_VALUE(d1.max_size()); + PASSED; +#if PERFORMANCE_TEST_ON + std::cout << "[--------------------- Performance Testing ---------------------]" << std::endl; + std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl; + std::cout << "| push_front |"; +#if LARGER_TEST_DATA_ON + CON_TEST_P1(deque, push_front, rand(), SCALE_LL(LEN1), SCALE_LL(LEN2), SCALE_LL(LEN3)); +#else + CON_TEST_P1(deque, push_front, rand(), SCALE_L(LEN1), SCALE_L(LEN2), SCALE_L(LEN3)); +#endif + std::cout << std::endl; + std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl; + std::cout << "| push_back |"; +#if LARGER_TEST_DATA_ON + CON_TEST_P1(deque, push_back, rand(), SCALE_LL(LEN1), SCALE_LL(LEN2), SCALE_LL(LEN3)); +#else + CON_TEST_P1(deque, push_back, rand(), SCALE_L(LEN1), SCALE_L(LEN2), SCALE_L(LEN3)); +#endif + std::cout << std::endl; + std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl; + PASSED; +#endif + std::cout << "[----------------- End container test : deque ------------------]" << std::endl; +} + +} // namespace deque_test +} // namespace test +} // namespace mystl +#endif // !MYTINYSTL_DEQUE_TEST_H_ + diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/list_test.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/list_test.h new file mode 100644 index 0000000..83f90a6 --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/list_test.h @@ -0,0 +1,118 @@ +#ifndef MYTINYSTL_LIST_TEST_H_ +#define MYTINYSTL_LIST_TEST_H_ + +// list test : 测试 list 的接口与 insert, sort 的性能 + +#include + +#include "../MyTinySTL/list.h" +#include "test.h" + +namespace mystl +{ +namespace test +{ +namespace list_test +{ + +// 一个辅助测试函数 +bool is_odd(int x) { return x & 1; } + +void list_test() +{ + std::cout << "[===============================================================]" << std::endl; + std::cout << "[------------------ Run container test : list ------------------]" << std::endl; + std::cout << "[-------------------------- API test ---------------------------]" << std::endl; + int a[] = { 1,2,3,4,5 }; + mystl::list l1; + mystl::list l2(5); + mystl::list l3(5, 1); + mystl::list l4(a, a + 5); + mystl::list l5(l2); + mystl::list l6(std::move(l2)); + mystl::list l7{ 1,2,3,4,5,6,7,8,9 }; + mystl::list l8; + l8 = l3; + mystl::list l9; + l9 = std::move(l3); + mystl::list l10; + l10 = { 1, 2, 2, 3, 5, 6, 7, 8, 9 }; + + FUN_AFTER(l1, l1.assign(8, 8)); + FUN_AFTER(l1, l1.assign(a, a + 5)); + FUN_AFTER(l1, l1.assign({ 1,2,3,4,5,6 })); + FUN_AFTER(l1, l1.insert(l1.end(), 6)); + FUN_AFTER(l1, l1.insert(l1.end(), 2, 7)); + FUN_AFTER(l1, l1.insert(l1.begin(), a, a + 5)); + FUN_AFTER(l1, l1.push_back(2)); + FUN_AFTER(l1, l1.push_front(1)); + FUN_AFTER(l1, l1.emplace(l1.begin(),1)); + FUN_AFTER(l1, l1.emplace_front(0)); + FUN_AFTER(l1, l1.emplace_back(10)); + FUN_VALUE(l1.size()); + FUN_AFTER(l1, l1.pop_front()); + FUN_AFTER(l1, l1.pop_back()); + FUN_AFTER(l1, l1.erase(l1.begin())); + FUN_AFTER(l1, l1.erase(l1.begin(), l1.end())); + FUN_VALUE(l1.size()); + FUN_AFTER(l1, l1.resize(10)); + FUN_AFTER(l1, l1.resize(5, 1)); + FUN_AFTER(l1, l1.resize(8, 2)); + FUN_VALUE(l1.size()); + FUN_AFTER(l1, l1.splice(l1.end(), l4)); + FUN_AFTER(l1, l1.splice(l1.begin(), l5, l5.begin())); + FUN_AFTER(l1, l1.splice(l1.end(), l6, l6.begin(), ++l6.begin())); + FUN_VALUE(l1.size()); + FUN_AFTER(l1, l1.remove(0)); + FUN_AFTER(l1, l1.remove_if(is_odd)); + FUN_VALUE(l1.size()); + FUN_AFTER(l1, l1.assign({ 9,5,3,3,7,1,3,2,2,0,10 })); + FUN_VALUE(l1.size()); + FUN_AFTER(l1, l1.sort()); + FUN_AFTER(l1, l1.unique()); + FUN_AFTER(l1, l1.unique([&](int a, int b) {return b == a + 1; })); + FUN_AFTER(l1, l1.merge(l7)); + FUN_AFTER(l1, l1.sort(mystl::greater())); + FUN_AFTER(l1, l1.merge(l8, mystl::greater())); + FUN_AFTER(l1, l1.reverse()); + FUN_AFTER(l1, l1.clear()); + FUN_AFTER(l1, l1.swap(l9)); + FUN_VALUE(*l1.begin()); + FUN_VALUE(*l1.rbegin()); + FUN_VALUE(l1.front()); + FUN_VALUE(l1.back()); + std::cout << std::boolalpha; + FUN_VALUE(l1.empty()); + std::cout << std::noboolalpha; + FUN_VALUE(l1.size()); + FUN_VALUE(l1.max_size()); + PASSED; +#if PERFORMANCE_TEST_ON + std::cout << "[--------------------- Performance Testing ---------------------]" << std::endl; + std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl; + std::cout << "| insert |"; +#if LARGER_TEST_DATA_ON + CON_TEST_P2(list, insert, end, rand(), SCALE_L(LEN1), SCALE_L(LEN2), SCALE_L(LEN3)); +#else + CON_TEST_P2(list, insert, end, rand(), SCALE_M(LEN1), SCALE_M(LEN2), SCALE_M(LEN3)); +#endif + std::cout << std::endl; + std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl; + std::cout << "| sort |"; +#if LARGER_TEST_DATA_ON + LIST_SORT_TEST(SCALE_M(LEN1), SCALE_M(LEN2), SCALE_M(LEN3)); +#else + LIST_SORT_TEST(SCALE_S(LEN1), SCALE_S(LEN2), SCALE_S(LEN3)); +#endif + std::cout << std::endl; + std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl; + PASSED; +#endif + std::cout << "[------------------ End container test : list ------------------]" << std::endl; +} + +} // namespace list_test +} // namespace test +} // namespace mystl +#endif // !MYTINYSTL_LIST_TEST_H_ + diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/map_test.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/map_test.h new file mode 100644 index 0000000..78a0553 --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/map_test.h @@ -0,0 +1,202 @@ +#ifndef MYTINYSTL_MAP_TEST_H_ +#define MYTINYSTL_MAP_TEST_H_ + +// map test : 测试 map, multimap 的接口与它们 insert 的性能 + +#include + +#include "../MyTinySTL/map.h" +#include "../MyTinySTL/vector.h" +#include "test.h" + +namespace mystl +{ +namespace test +{ +namespace map_test +{ + +// pair 的宏定义 +#define PAIR mystl::pair + +// map 的遍历输出 +#define MAP_COUT(m) do { \ + std::string m_name = #m; \ + std::cout << " " << m_name << " :"; \ + for (auto it : m) std::cout << " <" << it.first << "," << it.second << ">"; \ + std::cout << std::endl; \ +} while(0) + +// map 的函数操作 +#define MAP_FUN_AFTER(con, fun) do { \ + std::string str = #fun; \ + std::cout << " After " << str << " :" << std::endl; \ + fun; \ + MAP_COUT(con); \ +} while(0) + +// map 的函数值 +#define MAP_VALUE(fun) do { \ + std::string str = #fun; \ + auto it = fun; \ + std::cout << " " << str << " : <" << it.first << "," << it.second << ">\n"; \ +} while(0) + +void map_test() +{ + std::cout << "[===============================================================]" << std::endl; + std::cout << "[------------------ Run container test : map -------------------]" << std::endl; + std::cout << "[-------------------------- API test ---------------------------]" << std::endl; + mystl::vector v; + for (int i = 0; i < 5; ++i) + v.push_back(PAIR(i, i)); + mystl::map m1; + mystl::map> m2; + mystl::map m3(v.begin(), v.end()); + mystl::map m4(v.begin(), v.end()); + mystl::map m5(m3); + mystl::map m6(std::move(m3)); + mystl::map m7; + m7 = m4; + mystl::map m8; + m8 = std::move(m4); + mystl::map m9{ PAIR(1,1),PAIR(3,2),PAIR(2,3) }; + mystl::map m10; + m10 = { PAIR(1,1),PAIR(3,2),PAIR(2,3) }; + + for (int i = 5; i > 0; --i) + { + MAP_FUN_AFTER(m1, m1.emplace(i, i)); + } + MAP_FUN_AFTER(m1, m1.emplace_hint(m1.begin(), 0, 0)); + MAP_FUN_AFTER(m1, m1.erase(m1.begin())); + MAP_FUN_AFTER(m1, m1.erase(0)); + MAP_FUN_AFTER(m1, m1.erase(1)); + MAP_FUN_AFTER(m1, m1.erase(m1.begin(), m1.end())); + for (int i = 0; i < 5; ++i) + { + MAP_FUN_AFTER(m1, m1.insert(PAIR(i, i))); + } + MAP_FUN_AFTER(m1, m1.insert(v.begin(), v.end())); + MAP_FUN_AFTER(m1, m1.insert(m1.end(), PAIR(5, 5))); + FUN_VALUE(m1.count(1)); + MAP_VALUE(*m1.find(3)); + MAP_VALUE(*m1.lower_bound(3)); + MAP_VALUE(*m1.upper_bound(2)); + auto first = *m1.equal_range(2).first; + auto second = *m1.equal_range(2).second; + std::cout << " m1.equal_range(2) : from <" << first.first << ", " << first.second + << "> to <" << second.first << ", " << second.second << ">" << std::endl; + MAP_FUN_AFTER(m1, m1.erase(m1.begin())); + MAP_FUN_AFTER(m1, m1.erase(1)); + MAP_FUN_AFTER(m1, m1.erase(m1.begin(), m1.find(3))); + MAP_FUN_AFTER(m1, m1.clear()); + MAP_FUN_AFTER(m1, m1.swap(m9)); + MAP_VALUE(*m1.begin()); + MAP_VALUE(*m1.rbegin()); + FUN_VALUE(m1[1]); + MAP_FUN_AFTER(m1, m1[1] = 3); + FUN_VALUE(m1.at(1)); + std::cout << std::boolalpha; + FUN_VALUE(m1.empty()); + std::cout << std::noboolalpha; + FUN_VALUE(m1.size()); + FUN_VALUE(m1.max_size()); + PASSED; +#if PERFORMANCE_TEST_ON + std::cout << "[--------------------- Performance Testing ---------------------]" << std::endl; + std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl; + std::cout << "| emplace |"; +#if LARGER_TEST_DATA_ON + MAP_EMPLACE_TEST(map, SCALE_L(LEN1), SCALE_L(LEN2), SCALE_L(LEN3)); +#else + MAP_EMPLACE_TEST(map, SCALE_M(LEN1), SCALE_M(LEN2), SCALE_M(LEN3)); +#endif + std::cout << std::endl; + std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl; + PASSED; +#endif + std::cout << "[------------------ End container test : map -------------------]" << std::endl; +} + +void multimap_test() +{ + std::cout << "[===============================================================]" << std::endl; + std::cout << "[---------------- Run container test : multimap ----------------]" << std::endl; + std::cout << "[-------------------------- API test ---------------------------]" << std::endl; + mystl::vector v; + for (int i = 0; i < 5; ++i) + v.push_back(PAIR(i, i)); + mystl::multimap m1; + mystl::multimap> m2; + mystl::multimap m3(v.begin(), v.end()); + mystl::multimap m4(v.begin(), v.end()); + mystl::multimap m5(m3); + mystl::multimap m6(std::move(m3)); + mystl::multimap m7; + m7 = m4; + mystl::multimap m8; + m8 = std::move(m4); + mystl::multimap m9{ PAIR(1,1),PAIR(3,2),PAIR(2,3) }; + mystl::multimap m10; + m10 = { PAIR(1,1),PAIR(3,2),PAIR(2,3) }; + + for (int i = 5; i > 0; --i) + { + MAP_FUN_AFTER(m1, m1.emplace(i, i)); + } + MAP_FUN_AFTER(m1, m1.emplace_hint(m1.begin(), 0, 0)); + MAP_FUN_AFTER(m1, m1.erase(m1.begin())); + MAP_FUN_AFTER(m1, m1.erase(0)); + MAP_FUN_AFTER(m1, m1.erase(1)); + MAP_FUN_AFTER(m1, m1.erase(m1.begin(), m1.end())); + for (int i = 0; i < 5; ++i) + { + MAP_FUN_AFTER(m1, m1.insert(mystl::make_pair(i, i))); + } + MAP_FUN_AFTER(m1, m1.insert(v.begin(), v.end())); + MAP_FUN_AFTER(m1, m1.insert(PAIR(5, 5))); + MAP_FUN_AFTER(m1, m1.insert(m1.end(), PAIR(5, 5))); + FUN_VALUE(m1.count(3)); + MAP_VALUE(*m1.find(3)); + MAP_VALUE(*m1.lower_bound(3)); + MAP_VALUE(*m1.upper_bound(2)); + auto first = *m1.equal_range(2).first; + auto second = *m1.equal_range(2).second; + std::cout << " m1.equal_range(2) : from <" << first.first << ", " << first.second + << "> to <" << second.first << ", " << second.second << ">" << std::endl; + MAP_FUN_AFTER(m1, m1.erase(m1.begin())); + MAP_FUN_AFTER(m1, m1.erase(1)); + MAP_FUN_AFTER(m1, m1.erase(m1.begin(), m1.find(3))); + MAP_FUN_AFTER(m1, m1.clear()); + MAP_FUN_AFTER(m1, m1.swap(m9)); + MAP_FUN_AFTER(m1, m1.insert(PAIR(3, 3))); + MAP_VALUE(*m1.begin()); + MAP_VALUE(*m1.rbegin()); + std::cout << std::boolalpha; + FUN_VALUE(m1.empty()); + std::cout << std::noboolalpha; + FUN_VALUE(m1.size()); + FUN_VALUE(m1.max_size()); + PASSED; +#if PERFORMANCE_TEST_ON + std::cout << "[--------------------- Performance Testing ---------------------]" << std::endl; + std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl; + std::cout << "| emplace |"; +#if LARGER_TEST_DATA_ON + MAP_EMPLACE_TEST(multimap, SCALE_M(LEN1), SCALE_M(LEN2), SCALE_M(LEN3)); +#else + MAP_EMPLACE_TEST(multimap, SCALE_S(LEN1), SCALE_S(LEN2), SCALE_S(LEN3)); +#endif + std::cout << std::endl; + std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl; + PASSED; +#endif + std::cout << "[---------------- End container test : multimap ----------------]" << std::endl; +} + +} // namespace map_test +} // namespace test +} // namespace mystl +#endif // !MYTINYSTL_MAP_TEST_H_ + diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/queue_test.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/queue_test.h new file mode 100644 index 0000000..2a11174 --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/queue_test.h @@ -0,0 +1,186 @@ +#ifndef MYTINYSTL_QUEUE_TEST_H_ +#define MYTINYSTL_QUEUE_TEST_H_ + +// queue test : 测试 queue, priority_queue 的接口和它们 push 的性能 + +#include + +#include "../MyTinySTL/queue.h" +#include "test.h" + +namespace mystl +{ +namespace test +{ +namespace queue_test +{ + +void queue_print(mystl::queue q) +{ + while (!q.empty()) + { + std::cout << " " << q.front(); + q.pop(); + } + std::cout << std::endl; +} + +void p_queue_print(mystl::priority_queue p) +{ + while (!p.empty()) + { + std::cout << " " << p.top(); + p.pop(); + } + std::cout << std::endl; +} + +// queue 的遍历输出 +#define QUEUE_COUT(q) do { \ + std::string q_name = #q; \ + std::cout << " " << q_name << " :"; \ + queue_print(q); \ +} while(0) + +// priority_queue 的遍历输出 +#define P_QUEUE_COUT(p) do { \ + std::string p_name = #p; \ + std::cout << " " << p_name << " :"; \ + p_queue_print(p); \ +} while(0) + +#define QUEUE_FUN_AFTER(con, fun) do { \ + std::string fun_name = #fun; \ + std::cout << " After " << fun_name << " :\n"; \ + fun; \ + QUEUE_COUT(con); \ +} while(0) + +#define P_QUEUE_FUN_AFTER(con, fun) do { \ + std::string fun_name = #fun; \ + std::cout << " After " << fun_name << " :\n"; \ + fun; \ + P_QUEUE_COUT(con); \ +} while(0) + +void queue_test() +{ + std::cout << "[===============================================================]" << std::endl; + std::cout << "[----------------- Run container test : queue ------------------]" << std::endl; + std::cout << "[-------------------------- API test ---------------------------]" << std::endl; + int a[] = { 1,2,3,4,5 }; + mystl::deque d1(5); + mystl::queue q1; + mystl::queue q2(5); + mystl::queue q3(5, 1); + mystl::queue q4(a, a + 5); + mystl::queue q5(d1); + mystl::queue q6(std::move(d1)); + mystl::queue q7(q2); + mystl::queue q8(std::move(q2)); + mystl::queue q9; + q9 = q3; + mystl::queue q10; + q10 = std::move(q3); + mystl::queue q11{ 1,2,3,4,5 }; + mystl::queue q12; + q12 = { 1,2,3,4,5 }; + + QUEUE_FUN_AFTER(q1, q1.push(1)); + QUEUE_FUN_AFTER(q1, q1.push(2)); + QUEUE_FUN_AFTER(q1, q1.push(3)); + QUEUE_FUN_AFTER(q1, q1.pop()); + QUEUE_FUN_AFTER(q1, q1.emplace(4)); + QUEUE_FUN_AFTER(q1, q1.emplace(5)); + std::cout << std::boolalpha; + FUN_VALUE(q1.empty()); + std::cout << std::noboolalpha; + FUN_VALUE(q1.size()); + FUN_VALUE(q1.front()); + FUN_VALUE(q1.back()); + while (!q1.empty()) + { + QUEUE_FUN_AFTER(q1, q1.pop()); + } + QUEUE_FUN_AFTER(q1, q1.swap(q4)); + QUEUE_FUN_AFTER(q1, q1.clear()); + PASSED; +#if PERFORMANCE_TEST_ON + std::cout << "[--------------------- Performance Testing ---------------------]" << std::endl; + std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl; + std::cout << "| push |"; +#if LARGER_TEST_DATA_ON + CON_TEST_P1(queue, push, rand(), SCALE_LL(LEN1), SCALE_LL(LEN2), SCALE_LL(LEN3)); +#else + CON_TEST_P1(queue, push, rand(), SCALE_L(LEN1), SCALE_L(LEN2), SCALE_L(LEN3)); +#endif + std::cout << std::endl; + std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl; + PASSED; +#endif + std::cout << "[----------------- End container test : queue ------------------]" << std::endl; +} + +void priority_test() +{ + std::cout << "[===============================================================]" << std::endl; + std::cout << "[------------- Run container test : priority_queue -------------]" << std::endl; + std::cout << "[-------------------------- API test ---------------------------]" << std::endl; + int a[] = { 1,2,3,4,5 }; + mystl::vector v1(5); + mystl::priority_queue p1; + mystl::priority_queue p2(5); + mystl::priority_queue p3(5, 1); + mystl::priority_queue p4(a, a + 5); + mystl::priority_queue p5(v1); + mystl::priority_queue p6(std::move(v1)); + mystl::priority_queue p7(p2); + mystl::priority_queue p8(std::move(p2)); + mystl::priority_queue p9; + p9 = p3; + mystl::priority_queue p10; + p10 = std::move(p3); + mystl::priority_queue p11{ 1,2,3,4,5 }; + mystl::priority_queue p12; + p12 = { 1,2,3,4,5 }; + + P_QUEUE_FUN_AFTER(p1, p1.push(1)); + P_QUEUE_FUN_AFTER(p1, p1.push(5)); + P_QUEUE_FUN_AFTER(p1, p1.push(3)); + P_QUEUE_FUN_AFTER(p1, p1.pop()); + P_QUEUE_FUN_AFTER(p1, p1.emplace(7)); + P_QUEUE_FUN_AFTER(p1, p1.emplace(2)); + P_QUEUE_FUN_AFTER(p1, p1.emplace(8)); + std::cout << std::boolalpha; + FUN_VALUE(p1.empty()); + std::cout << std::noboolalpha; + FUN_VALUE(p1.size()); + FUN_VALUE(p1.top()); + while (!p1.empty()) + { + P_QUEUE_FUN_AFTER(p1, p1.pop()); + } + P_QUEUE_FUN_AFTER(p1, p1.swap(p4)); + P_QUEUE_FUN_AFTER(p1, p1.clear()); + PASSED; +#if PERFORMANCE_TEST_ON + std::cout << "[--------------------- Performance Testing ---------------------]" << std::endl; + std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl; + std::cout << "| push |"; +#if LARGER_TEST_DATA_ON + CON_TEST_P1(priority_queue, push, rand(), SCALE_LL(LEN1), SCALE_LL(LEN2), SCALE_LL(LEN3)); +#else + CON_TEST_P1(priority_queue, push, rand(), SCALE_L(LEN1), SCALE_L(LEN2), SCALE_L(LEN3)); +#endif + std::cout << std::endl; + std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl; + PASSED; +#endif + std::cout << "[------------- End container test : priority_queue -------------]" << std::endl; +} + +} // namespace queue_test +} // namespace test +} // namespace mystl +#endif // !MYTINYSTL_QUEUE_TEST_H_ + diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/set_test.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/set_test.h new file mode 100644 index 0000000..8389e74 --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/set_test.h @@ -0,0 +1,166 @@ +#ifndef MYTINYSTL_SET_TEST_H_ +#define MYTINYSTL_SET_TEST_H_ + +// set test : 测试 set, multiset 的接口与它们 insert 的性能 + +#include + +#include "../MyTinySTL/set.h" +#include "test.h" + +namespace mystl +{ +namespace test +{ +namespace set_test +{ + +void set_test() +{ + std::cout << "[===============================================================]" << std::endl; + std::cout << "[------------------ Run container test : set -------------------]" << std::endl; + std::cout << "[-------------------------- API test ---------------------------]" << std::endl; + int a[] = { 5,4,3,2,1 }; + mystl::set s1; + mystl::set> s2; + mystl::set s3(a, a + 5); + mystl::set s4(a, a + 5); + mystl::set s5(s3); + mystl::set s6(std::move(s3)); + mystl::set s7; + s7 = s4; + mystl::set s8; + s8 = std::move(s4); + mystl::set s9{ 1,2,3,4,5 }; + mystl::set s10; + s10 = { 1,2,3,4,5 }; + + for (int i = 5; i > 0; --i) + { + FUN_AFTER(s1, s1.emplace(i)); + } + FUN_AFTER(s1, s1.emplace_hint(s1.begin(), 0)); + FUN_AFTER(s1, s1.erase(s1.begin())); + FUN_AFTER(s1, s1.erase(0)); + FUN_AFTER(s1, s1.erase(1)); + FUN_AFTER(s1, s1.erase(s1.begin(), s1.end())); + for (int i = 0; i < 5; ++i) + { + FUN_AFTER(s1, s1.insert(i)); + } + FUN_AFTER(s1, s1.insert(a, a + 5)); + FUN_AFTER(s1, s1.insert(5)); + FUN_AFTER(s1, s1.insert(s1.end(), 5)); + FUN_VALUE(s1.count(5)); + FUN_VALUE(*s1.find(3)); + FUN_VALUE(*s1.lower_bound(3)); + FUN_VALUE(*s1.upper_bound(3)); + auto first = *s1.equal_range(3).first; + auto second = *s1.equal_range(3).second; + std::cout << " s1.equal_range(3) : from " << first << " to " << second << std::endl; + FUN_AFTER(s1, s1.erase(s1.begin())); + FUN_AFTER(s1, s1.erase(1)); + FUN_AFTER(s1, s1.erase(s1.begin(), s1.find(3))); + FUN_AFTER(s1, s1.clear()); + FUN_AFTER(s1, s1.swap(s5)); + FUN_VALUE(*s1.begin()); + FUN_VALUE(*s1.rbegin()); + std::cout << std::boolalpha; + FUN_VALUE(s1.empty()); + std::cout << std::noboolalpha; + FUN_VALUE(s1.size()); + FUN_VALUE(s1.max_size()); + PASSED; +#if PERFORMANCE_TEST_ON + std::cout << "[--------------------- Performance Testing ---------------------]" << std::endl; + std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl; + std::cout << "| emplace |"; +#if LARGER_TEST_DATA_ON + CON_TEST_P1(set, emplace, rand(), SCALE_L(LEN1), SCALE_L(LEN2), SCALE_L(LEN3)); +#else + CON_TEST_P1(set, emplace, rand(), SCALE_M(LEN1), SCALE_M(LEN2), SCALE_M(LEN3)); +#endif + std::cout << std::endl; + std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl; + PASSED; +#endif + std::cout << "[------------------ End container test : set -------------------]" << std::endl; +} + +void multiset_test() +{ + std::cout << "[===============================================================]" << std::endl; + std::cout << "[---------------- Run container test : multiset ----------------]" << std::endl; + std::cout << "[-------------------------- API test ---------------------------]" << std::endl; + int a[] = { 5,4,3,2,1 }; + mystl::multiset s1; + mystl::multiset> s2; + mystl::multiset s3(a, a + 5); + mystl::multiset s4(a, a + 5); + mystl::multiset s5(s3); + mystl::multiset s6(std::move(s3)); + mystl::multiset s7; + s7 = s4; + mystl::multiset s8; + s8 = std::move(s4); + mystl::multiset s9{ 1,2,3,4,5 }; + mystl::multiset s10; + s10 = { 1,2,3,4,5 }; + + for (int i = 5; i > 0; --i) + { + FUN_AFTER(s1, s1.emplace(i)); + } + FUN_AFTER(s1, s1.emplace_hint(s1.begin(), 0)); + FUN_AFTER(s1, s1.erase(s1.begin())); + FUN_AFTER(s1, s1.erase(0)); + FUN_AFTER(s1, s1.erase(1)); + FUN_AFTER(s1, s1.erase(s1.begin(), s1.end())); + for (int i = 0; i < 5; ++i) + { + FUN_AFTER(s1, s1.insert(i)); + } + FUN_AFTER(s1, s1.insert(a, a + 5)); + FUN_AFTER(s1, s1.insert(5)); + FUN_AFTER(s1, s1.insert(s1.end(), 5)); + FUN_VALUE(s1.count(5)); + FUN_VALUE(*s1.find(3)); + FUN_VALUE(*s1.lower_bound(3)); + FUN_VALUE(*s1.upper_bound(3)); + auto first = *s1.equal_range(3).first; + auto second = *s1.equal_range(3).second; + std::cout << " s1.equal_range(3) : from " << first << " to " << second << std::endl; + FUN_AFTER(s1, s1.erase(s1.begin())); + FUN_AFTER(s1, s1.erase(1)); + FUN_AFTER(s1, s1.erase(s1.begin(), s1.find(3))); + FUN_AFTER(s1, s1.clear()); + FUN_AFTER(s1, s1.swap(s5)); + FUN_VALUE(*s1.begin()); + FUN_VALUE(*s1.rbegin()); + std::cout << std::boolalpha; + FUN_VALUE(s1.empty()); + std::cout << std::noboolalpha; + FUN_VALUE(s1.size()); + FUN_VALUE(s1.max_size()); + PASSED; +#if PERFORMANCE_TEST_ON + std::cout << "[--------------------- Performance Testing ---------------------]" << std::endl; + std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl; + std::cout << "| emplace |"; +#if LARGER_TEST_DATA_ON + CON_TEST_P1(multiset, emplace, rand(), SCALE_M(LEN1), SCALE_M(LEN2), SCALE_M(LEN3)); +#else + CON_TEST_P1(multiset, emplace, rand(), SCALE_S(LEN1), SCALE_S(LEN2), SCALE_S(LEN3)); +#endif + std::cout << std::endl; + std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl; + PASSED; +#endif + std::cout << "[---------------- End container test : multiset ----------------]" << std::endl; +} + +} // namespace set_test +} // namespace test +} // namespace mystl +#endif // !MYTINYSTL_SET_TEST_H_ + diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/stack_test.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/stack_test.h new file mode 100644 index 0000000..4eebdbc --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/stack_test.h @@ -0,0 +1,103 @@ +#ifndef MYTINYSTL_STACK_TEST_H_ +#define MYTINYSTL_STACK_TEST_H_ + +// stack test : 测试 stack 的接口 和 push 的性能 + +#include + +#include "../MyTinySTL/stack.h" +#include "test.h" + +namespace mystl +{ +namespace test +{ +namespace stack_test +{ + +void stack_print(mystl::stack s) +{ + while (!s.empty()) + { + std::cout << " " << s.top(); + s.pop(); + } + std::cout << std::endl; +} + +// stack 的遍历输出 +#define STACK_COUT(s) do { \ + std::string s_name = #s; \ + std::cout << " " << s_name << " :"; \ + stack_print(s); \ +} while(0) + +#define STACK_FUN_AFTER(con, fun) do { \ + std::string fun_name = #fun; \ + std::cout << " After " << fun_name << " :\n"; \ + fun; \ + STACK_COUT(con); \ +} while(0) + +void stack_test() +{ + std::cout << "[===============================================================]" << std::endl; + std::cout << "[----------------- Run container test : stack ------------------]" << std::endl; + std::cout << "[-------------------------- API test ---------------------------]" << std::endl; + int a[] = { 1,2,3,4,5 }; + mystl::deque d1(5); + mystl::stack s1; + mystl::stack s2(5); + mystl::stack s3(5, 1); + mystl::stack s4(a, a + 5); + mystl::stack s5(d1); + mystl::stack s6(std::move(d1)); + mystl::stack s7(s2); + mystl::stack s8(std::move(s2)); + mystl::stack s9; + s9 = s3; + mystl::stack s10; + s10 = std::move(s3); + mystl::stack s11{ 1,2,3,4,5 }; + mystl::stack s12; + s12 = { 1,2,3,4,5 }; + + STACK_FUN_AFTER(s1, s1.push(1)); + STACK_FUN_AFTER(s1, s1.push(2)); + STACK_FUN_AFTER(s1, s1.push(3)); + STACK_FUN_AFTER(s1, s1.pop()); + STACK_FUN_AFTER(s1, s1.emplace(4)); + STACK_FUN_AFTER(s1, s1.emplace(5)); + std::cout << std::boolalpha; + FUN_VALUE(s1.empty()); + std::cout << std::noboolalpha; + FUN_VALUE(s1.size()); + FUN_VALUE(s1.top()); + while (!s1.empty()) + { + STACK_FUN_AFTER(s1, s1.pop()); + } + STACK_FUN_AFTER(s1, s1.swap(s4)); + STACK_FUN_AFTER(s1, s1.clear()); + PASSED; +#if PERFORMANCE_TEST_ON + std::cout << "[--------------------- Performance Testing ---------------------]" << std::endl; + std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl; + std::cout << "| push |"; +#if LARGER_TEST_DATA_ON + CON_TEST_P1(stack, push, rand(), SCALE_LL(LEN1), SCALE_LL(LEN2), SCALE_LL(LEN3)); +#else + CON_TEST_P1(stack, push, rand(), SCALE_L(LEN1), SCALE_L(LEN2), SCALE_L(LEN3)); +#endif + std::cout << std::endl; + std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl; + PASSED; +#endif + std::cout << "[----------------- End container test : stack ------------------]" << std::endl; +} + +} // namespace stack_test +} // namespace test +} // namespace mystl +#endif // !MYTINYSTL_STACK_TEST_H_ + diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/string_test.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/string_test.h new file mode 100644 index 0000000..7af3811 --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/string_test.h @@ -0,0 +1,207 @@ +#ifndef MYTINYSTL_STRING_TEST_H_ +#define MYTINYSTL_STRING_TEST_H_ + +// string test : 测试 string 的接口和 insert 的性能 + +#include + +#include "../MyTinySTL/astring.h" +#include "test.h" + +namespace mystl +{ +namespace test +{ +namespace string_test +{ + +void string_test() +{ + std::cout << "[===============================================================]" << std::endl; + std::cout << "[----------------- Run container test : string -----------------]" << std::endl; + std::cout << "[-------------------------- API test ---------------------------]" << std::endl; + const char* s = "abcdefg"; + mystl::string str; + mystl::string str1(5, 'a'); + mystl::string str2(str1, 3); + mystl::string str3(str1, 0, 3); + mystl::string str4("abc"); + mystl::string str5("abcde",3); + mystl::string str6(s, s + 5); + mystl::string str7(str1); + mystl::string str8(std::move(str1)); + mystl::string str9; + str9 = str2; + mystl::string str10; + str10 = std::move(str2); + mystl::string str11; + str11 = "123"; + mystl::string str12; + str12 = 'A'; + + STR_FUN_AFTER(str, str = 'a'); + STR_FUN_AFTER(str, str = "string"); + FUN_VALUE(*str.begin()); + FUN_VALUE(*str.rbegin()); + FUN_VALUE(*(str.end() - 1)); + FUN_VALUE(*(str.rend() - 1)); + FUN_VALUE(str.front()); + FUN_VALUE(str.back()); + FUN_VALUE(str[1]); + FUN_VALUE(str.at(2)); + STR_COUT(str.data()); + STR_COUT(str.c_str()); + std::cout << std::boolalpha; + FUN_VALUE(str.empty()); + std::cout << std::noboolalpha; + FUN_VALUE(str.size()); + FUN_VALUE(str.length()); + FUN_VALUE(str.capacity()); + FUN_VALUE(str.max_size()); + STR_FUN_AFTER(str, str.shrink_to_fit()); + FUN_VALUE(str.capacity()); + + STR_FUN_AFTER(str, str.insert(str.begin(), 'a')); + STR_FUN_AFTER(str, str.insert(str.end(), 3, 'x')); + STR_FUN_AFTER(str, str.insert(str.end(), s, s + 3)); + STR_FUN_AFTER(str, str.erase(str.begin())); + STR_FUN_AFTER(str, str.erase(str.begin(), str.begin() + 3)); + STR_FUN_AFTER(str, str.clear()); + STR_FUN_AFTER(str, str.push_back('s')); + STR_FUN_AFTER(str, str.push_back('t')); + STR_FUN_AFTER(str, str.pop_back()); + STR_FUN_AFTER(str, str.append(1, 't')); + STR_FUN_AFTER(str, str.append(str4)); + STR_FUN_AFTER(str, str.append(str4, 1)); + STR_FUN_AFTER(str, str.append(str4, 2, 1)); + STR_FUN_AFTER(str, str.append("str")); + STR_FUN_AFTER(str, str.append("inging", 3)); + STR_FUN_AFTER(str, str.append(s, s + 3)); + STR_FUN_AFTER(str, str.resize(10)); + FUN_VALUE(str.size()); + STR_FUN_AFTER(str, str.resize(20, 'x')); + FUN_VALUE(str.size()); + STR_FUN_AFTER(str, str.clear()); + + STR_FUN_AFTER(str, str = "string"); + STR_FUN_AFTER(str3, str3 = "astrings"); + FUN_VALUE(str.compare(str3)); + FUN_VALUE(str.compare(0, 6, str3)); + FUN_VALUE(str.compare(0, 6, str3, 1, 6)); + FUN_VALUE(str.compare("atringgg")); + FUN_VALUE(str.compare("zzz")); + FUN_VALUE(str.compare(0, 3, "str")); + FUN_VALUE(str.compare(0, 3, "stri", 4)); + FUN_VALUE(str.compare(0, 3, "s", 2)); + FUN_VALUE(str.compare(0, 9, "stringabc", 9)); + FUN_VALUE(str.substr(0)); + FUN_VALUE(str.substr(3)); + FUN_VALUE(str.substr(0, 3)); + FUN_VALUE(str.substr(0, 10)); + STR_FUN_AFTER(str, str.replace(0, 6, str3)); + STR_FUN_AFTER(str, str.replace(str.end() - 1, str.end(), str3)); + STR_FUN_AFTER(str, str.replace(0, 1, "my ")); + STR_FUN_AFTER(str, str.replace(str.end() - 8, str.end(), " test")); + STR_FUN_AFTER(str, str.replace(10, 4, "replace")); + STR_FUN_AFTER(str, str.replace(str.end(), str.end(), " test")); + STR_FUN_AFTER(str, str.replace(0, 2, 3, '6')); + STR_FUN_AFTER(str, str.replace(str.begin(), str.begin() + 3, 6, '6')); + STR_FUN_AFTER(str, str.replace(0, 3, str3, 1, 3)); + STR_FUN_AFTER(str, str.replace(str.begin(), str.begin() + 6, s, s + 3)); + STR_FUN_AFTER(str, str.reverse()); + STR_FUN_AFTER(str, str.reverse()); + + STR_FUN_AFTER(str, str = "abcabc stringgg"); + STR_FUN_AFTER(str3, str3 = "abc"); + FUN_VALUE(str.find('a')); + FUN_VALUE(str.find('a', 3)); + FUN_VALUE(str.find('a', 4)); + FUN_VALUE(str.find("abc")); + FUN_VALUE(str.find("abc", 1)); + FUN_VALUE(str.find("abc", 1, 1)); + FUN_VALUE(str.find(str3)); + FUN_VALUE(str.find(str3, 1)); + FUN_VALUE(str.rfind('g')); + FUN_VALUE(str.rfind('g', 3)); + FUN_VALUE(str.rfind("gg")); + FUN_VALUE(str.rfind("bc", 10)); + FUN_VALUE(str.rfind(str3)); + FUN_VALUE(str.rfind(str3, 3)); + FUN_VALUE(str.find_first_of('g')); + FUN_VALUE(str.find_first_of('k')); + FUN_VALUE(str.find_first_of("bca")); + FUN_VALUE(str.find_first_of("defg", 10)); + FUN_VALUE(str.find_first_of("gnirts")); + FUN_VALUE(str.find_first_of("abc", 6)); + FUN_VALUE(str.find_first_of("abcdf", 2, 3)); + FUN_VALUE(str.find_first_of(str3, 1)); + FUN_VALUE(str.find_first_of(str3, 10)); + FUN_VALUE(str.find_first_not_of('a')); + FUN_VALUE(str.find_first_not_of('d')); + FUN_VALUE(str.find_first_not_of('g', 14)); + FUN_VALUE(str.find_first_not_of("abc")); + FUN_VALUE(str.find_first_not_of("ggggg", 14, 4)); + FUN_VALUE(str.find_first_not_of(str3)); + FUN_VALUE(str.find_first_not_of(str3, 3)); + FUN_VALUE(str.find_last_of('a')); + FUN_VALUE(str.find_last_of('a', 4)); + FUN_VALUE(str.find_last_of('g')); + FUN_VALUE(str.find_last_of("gg")); + FUN_VALUE(str.find_last_of("gg", 14)); + FUN_VALUE(str.find_last_of("ggg", 14, 1)); + FUN_VALUE(str.find_last_of(str3)); + FUN_VALUE(str.find_last_of(str3, 3)); + FUN_VALUE(str.find_last_not_of('g')); + FUN_VALUE(str.find_last_not_of('a')); + FUN_VALUE(str.find_last_not_of('a', 1)); + FUN_VALUE(str.find_last_not_of("ggg")); + FUN_VALUE(str.find_last_not_of("ggg", 14)); + FUN_VALUE(str.find_last_not_of("abc", 3, 1)); + FUN_VALUE(str.find_last_not_of(str3)); + FUN_VALUE(str.find_last_not_of(str3, 2)); + FUN_VALUE(str.count('a')); + FUN_VALUE(str.count('a', 2)); + FUN_VALUE(str.count('d', 10)); + + STR_FUN_AFTER(str, str.swap(str3)); + FUN_VALUE(str.size()); + FUN_VALUE(str.length()); + FUN_VALUE(str.capacity()); + STR_FUN_AFTER(str, str += str); + STR_FUN_AFTER(str, str += 'a'); + STR_FUN_AFTER(str, str += "bc"); + FUN_VALUE(str.size()); + FUN_VALUE(str.length()); + FUN_VALUE(str.capacity()); + STR_FUN_AFTER(str, str.shrink_to_fit()); + FUN_VALUE(str.capacity()); + STR_FUN_AFTER(str, str.reserve(50)); + FUN_VALUE(str.capacity()); + STR_FUN_AFTER(str3, str3 = "test"); + STR_FUN_AFTER(str4, str4 = " ok!"); + std::cout << " str3 + '!' : " << str3 + '!' << std::endl; + std::cout << " '#' + str3 : " << '#' + str3 << std::endl; + std::cout << " str3 + \" success\" : " << str3 + " success" << std::endl; + std::cout << " \"My \" + str3 : " << "My " + str3 << std::endl; + std::cout << " str3 + str4 : " << str3 + str4 << std::endl; + PASSED; +#if PERFORMANCE_TEST_ON + std::cout << "[--------------------- Performance Testing ---------------------]" << std::endl; + std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl; + std::cout << "| append |"; +#if LARGER_TEST_DATA_ON + CON_TEST_P1(string, append, "s", SCALE_LL(LEN1), SCALE_LL(LEN2), SCALE_LL(LEN3)); +#else + CON_TEST_P1(string, append, "s", SCALE_L(LEN1), SCALE_L(LEN2), SCALE_L(LEN3)); +#endif + std::cout << std::endl; + std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl; + PASSED; +#endif + std::cout << "[----------------- End container test : string -----------------]" << std::endl; +} + +} // namespace string_test +} // namespace test +} // namespace mystl +#endif // !MYTINYSTL_STRING_TEST_H_ diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/test.cpp b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/test.cpp new file mode 100644 index 0000000..67c795f --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/test.cpp @@ -0,0 +1,52 @@ +#ifdef _MSC_VER +#define _SCL_SECURE_NO_WARNINGS +#endif + +#if defined(_MSC_VER) && defined(_DEBUG) +#define _CRTDBG_MAP_ALLOC +#include +#include +#endif // check memory leaks + +#include "algorithm_performance_test.h" +#include "algorithm_test.h" +#include "vector_test.h" +#include "list_test.h" +#include "deque_test.h" +#include "queue_test.h" +#include "stack_test.h" +#include "map_test.h" +#include "set_test.h" +#include "unordered_map_test.h" +#include "unordered_set_test.h" +#include "string_test.h" + +int main() +{ + using namespace mystl::test; + + std::cout.sync_with_stdio(false); + + RUN_ALL_TESTS(); + algorithm_performance_test::algorithm_performance_test(); + vector_test::vector_test(); + list_test::list_test(); + deque_test::deque_test(); + queue_test::queue_test(); + queue_test::priority_test(); + stack_test::stack_test(); + map_test::map_test(); + map_test::multimap_test(); + set_test::set_test(); + set_test::multiset_test(); + unordered_map_test::unordered_map_test(); + unordered_map_test::unordered_multimap_test(); + unordered_set_test::unordered_set_test(); + unordered_set_test::unordered_multiset_test(); + string_test::string_test(); + +#if defined(_MSC_VER) && defined(_DEBUG) + _CrtDumpMemoryLeaks(); +#endif // check memory leaks + +} diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/test.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/test.h new file mode 100644 index 0000000..56e9cba --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/test.h @@ -0,0 +1,717 @@ +#ifndef MYTINYSTL_TEST_H_ +#define MYTINYSTL_TEST_H_ + +// 一个简单的单元测试框架,定义了两个类 TestCase 和 UnitTest,以及一系列用于测试的宏 + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Lib/redbud/io/color.h" + +namespace mystl +{ +namespace test +{ + +#define green redbud::io::state::manual << redbud::io::hfg::green +#define red redbud::io::state::manual << redbud::io::hfg::red + +#if defined(_MSC_VER) +#pragma warning(disable : 4244) +#pragma warning(disable : 4996) +#endif + +} // namespace test + +namespace test +{ + +// TestCase 类 +// 封装单个测试案例 +class TestCase +{ +public: + // 构造函数,接受一个字符串代表案例名称 + TestCase(const char* case_name) : testcase_name(case_name) {} + + // 一个纯虚函数,用于测试案例 + virtual void Run() = 0; + +public: + const char* testcase_name; // 测试案例的名称 + int nTestResult; // 测试案例的执行结果 + double nFailed; // 测试失败的案例数 + double nPassed; // 测试通过的案例数 +}; + +// UnitTest 类 +// 单元测试,把所有测试案例加入到 vector 中,依次执行测试案例 +class UnitTest +{ +public: + // 获取一个案例 + static UnitTest* GetInstance(); + + // 将案例依次加入 vector + TestCase* RegisterTestCase(TestCase* testcase); + + void Run(); + +public: + TestCase* CurrentTestCase; // 当前执行的测试案例 + double nPassed; // 通过案例数 + double nFailed; // 失败案例数 + +protected: + std::vector testcases_; // 保存案例集合 +}; + +UnitTest* UnitTest::GetInstance() +{ + static UnitTest instance; + return &instance; +} + +TestCase* UnitTest::RegisterTestCase(TestCase* testcase) +{ + testcases_.push_back(testcase); + return testcase; +} + +void UnitTest::Run() +{ + for (auto it : testcases_) + { + TestCase* testcase = it; + CurrentTestCase = testcase; + testcase->nTestResult = 1; + testcase->nFailed = 0; + testcase->nPassed = 0; + std::cout << green << "============================================\n"; + std::cout << green << " Run TestCase:" << testcase->testcase_name << "\n"; + testcase->Run(); + if (testcase->nFailed == 0) + std::cout << green; + else + std::cout << red; + std::cout << " " << testcase->nPassed << " / " << testcase->nFailed + testcase->nPassed + << " Cases passed. ( " << testcase->nPassed / + (testcase->nFailed + testcase->nPassed) * 100 << "% )\n"; + std::cout << green << " End TestCase:" << testcase->testcase_name << "\n"; + if (testcase->nTestResult) + ++nPassed; + else + ++nFailed; + } + std::cout << green << "============================================\n"; + std::cout << green << " Total TestCase : " << nPassed + nFailed << "\n"; + std::cout << green << " Total Passed : " << nPassed << "\n"; + std::cout << red << " Total Failed : " << nFailed << "\n"; + std::cout << green << " " << nPassed << " / " << nFailed + nPassed + << " TestCases passed. ( " << nPassed / (nFailed + nPassed) * 100 << "% )\n"; +} + +/*****************************************************************************************/ + +// 测试案例的类名,替换为 test_cast_TEST +#define TESTCASE_NAME(testcase_name) \ + testcase_name##_TEST + +// 使用宏定义掩盖复杂的测试样例封装过程,把 TEXT 中的测试案例放到单元测试中 +#define MYTINYSTL_TEST_(testcase_name) \ +class TESTCASE_NAME(testcase_name) : public TestCase { \ +public: \ + TESTCASE_NAME(testcase_name)(const char* case_name) \ + : TestCase(case_name) {}; \ + virtual void Run(); \ +private: \ + static TestCase* const testcase_; \ +}; \ + \ +TestCase* const TESTCASE_NAME(testcase_name) \ + ::testcase_ = UnitTest::GetInstance()->RegisterTestCase( \ + new TESTCASE_NAME(testcase_name)(#testcase_name)); \ +void TESTCASE_NAME(testcase_name)::Run() + +/* +Run()后边没有写实现,是为了用宏定义将测试用例放入到 Run 的实现里,例如: +TEST(AddTestDemo) +{ +EXPECT_EQ(3, Add(1, 2)); +EXPECT_EQ(2, Add(1, 1)); +} +上述代码将 { EXPECT_EQ(3, Add(1, 2)); EXPECT_EQ(2, Add(1, 1)); } 接到 Run() 的后面 +*/ + + +/*****************************************************************************************/ + +// 简单测试的宏定义 +// 断言 : 宏定义形式为 EXPECT_* ,符合验证条件的,案例测试通过,否则失败 +// 使用一系列的宏来封装验证条件,分为以下几大类 : + +/* +真假断言 +EXPECT_TRUE 验证条件: Condition 为 true +EXPECT_FALSE 验证条件: Condition 为 false + +Example: +bool isPrime(int n); 一个判断素数的函数 +EXPECT_TRUE(isPrime(2)); 通过 +EXPECT_FALSE(isPrime(4)); 通过 +EXPECT_TRUE(isPrime(6)); 失败 +EXPECT_FALSE(isPrime(3)); 失败 +*/ +#define EXPECT_TRUE(Condition) do { \ + if (Condition) { \ + UnitTest::GetInstance()->CurrentTestCase->nPassed++; \ + std::cout << green << " EXPECT_TRUE succeeded!\n"; \ + } \ + else { \ + UnitTest::GetInstance()->CurrentTestCase->nTestResult = 0; \ + UnitTest::GetInstance()->CurrentTestCase->nFailed++; \ + std::cout << red << " EXPECT_TRUE failed!\n"; \ +}} while(0) + +#define EXPECT_FALSE(Condition) do { \ + if (!Condition) { \ + UnitTest::GetInstance()->CurrentTestCase->nPassed++; \ + std::cout << green << " EXPECT_FALSE succeeded!\n"; \ + } \ + else { \ + UnitTest::GetInstance()->CurrentTestCase->nTestResult = 0; \ + UnitTest::GetInstance()->CurrentTestCase->nFailed++; \ + std::cout << red << " EXPECT_FALSE failed!\n"; \ +}} while(0) + +/* +比较断言 +EXPECT_EQ(v1, v2) 验证条件: v1 == v2 +EXPECT_NE(v1, v2) 验证条件: v1 != v2 +EXPECT_LT(v1, v2) 验证条件: v1 < v2 +EXPECT_LE(v1, v2) 验证条件: v1 <= v2 +EXPECT_GT(v1, v2) 验证条件: v1 > v2 +EXPECT_GE(v1, v2) 验证条件: v1 >= v2 + +Note: +1. 参数应满足 EXPECT_*(Expect, Actual)的格式,左边是期望值,右边是实际值 +2. 在断言失败时,会将期望值与实际值打印出来 +3. 参数值必须是可通过断言的比较操作符进行比较的,参数值还必须支持 << 操作符来 +将值输入到 ostream 中 +4. 这些断言可以用于用户自定义型别,但必须重载相应的比较操作符(如 == 、< 等) +5. EXPECT_EQ 对指针进行的是地址比较。即比较的是它们是否指向相同的内存地址, +而不是它们指向的内容是否相等。如果想比较两个 C 字符串(const char*)的值, +请使用 EXPECT_STREQ 。特别一提的是,要验证一个 C 字符串是否为空(NULL), +请使用 EXPECT_STREQ(NULL, c_str)。但是要比较两个 string 对象时, +应该使用 EXPECT_EQ + +Example: +EXPECT_EQ(3, foo()); +EXPECT_NE(NULL, pointer); +EXPECT_LT(len, v.size()); +*/ +#define EXPECT_EQ(v1, v2) do { \ + if (v1 == v2) { \ + UnitTest::GetInstance()->CurrentTestCase->nPassed++; \ + std::cout << green << " EXPECT_EQ succeeded!\n"; \ + } \ + else { \ + UnitTest::GetInstance()->CurrentTestCase->nTestResult = 0; \ + UnitTest::GetInstance()->CurrentTestCase->nFailed++; \ + std::cout << red << " EXPECT_EQ failed!\n"; \ + std::cout << red << " Expect:" << v1 << "\n"; \ + std::cout << red << " Actual:" << v2 << "\n"; \ +}} while(0) + +#define EXPECT_NE(v1, v2) do { \ + if (v1 != v2) { \ + UnitTest::GetInstance()->CurrentTestCase->nPassed++; \ + std::cout << green << " EXPECT_NE succeeded!\n"; \ + } \ + else { \ + UnitTest::GetInstance()->CurrentTestCase->nTestResult = 0; \ + UnitTest::GetInstance()->CurrentTestCase->nFailed++; \ + std::cout << red << " EXPECT_NE failed!\n"; \ + std::cout << red << " Expect:" << v1 << "\n"; \ + std::cout << red << " Actual:" << v2 << "\n"; \ +}} while(0) + +#define EXPECT_LT(v1, v2) do { \ + if (v1 < v2) { \ + UnitTest::GetInstance()->CurrentTestCase->nPassed++; \ + std::cout << green << " EXPECT_LT succeeded!\n"; \ + } \ + else { \ + UnitTest::GetInstance()->CurrentTestCase->nTestResult = 0; \ + UnitTest::GetInstance()->CurrentTestCase->nFailed++; \ + std::cout << red << " EXPECT_LT failed!\n"; \ + std::cout << red << " Expect:" << v1 << "\n"; \ + std::cout << red << " Actual:" << v2 << "\n"; \ +}} while(0) + +#define EXPECT_LE(v1, v2) do { \ + if (v1 <= v2) { \ + UnitTest::GetInstance()->CurrentTestCase->nPassed++; \ + std::cout << green << " EXPECT_LE succeeded!\n"; \ + } \ + else { \ + UnitTest::GetInstance()->CurrentTestCase->nTestResult = 0; \ + UnitTest::GetInstance()->CurrentTestCase->nFailed++; \ + std::cout << red << " EXPECT_LE failed!\n"; \ + std::cout << red << " Expect:" << v1 << "\n"; \ + std::cout << red << " Actual:" << v2 << "\n"; \ +}} while(0) + +#define EXPECT_GT(v1, v2) do { \ + if (v1 > v2) { \ + UnitTest::GetInstance()->CurrentTestCase->nPassed++; \ + std::cout << green << " EXPECT_GT succeeded!\n"; \ + } \ + else { \ + UnitTest::GetInstance()->CurrentTestCase->nTestResult = 0; \ + UnitTest::GetInstance()->CurrentTestCase->nFailed++; \ + std::cout << red << " EXPECT_GT failed!\n"; \ + std::cout << red << " Expect:" << v1 << "\n"; \ + std::cout << red << " Actual:" << v2 << "\n"; \ +}} while(0) + +#define EXPECT_GE(v1, v2) do { \ + if (v1 >= v2) { \ + UnitTest::GetInstance()->CurrentTestCase->nPassed++; \ + std::cout << green << " EXPECT_GE succeeded!\n"; \ + } \ + else { \ + UnitTest::GetInstance()->CurrentTestCase->nTestResult = 0; \ + UnitTest::GetInstance()->CurrentTestCase->nFailed++; \ + std::cout << red << " EXPECT_GE failed!\n"; \ + std::cout << red << " Expect:" << v1 << "\n"; \ + std::cout << red << " Actual:" << v2 << "\n"; \ +}} while(0) + +/* +字符串比较 +EXPECT_STREQ(s1, s2) 验证条件: 两个 C 字符串有相同的值 +EXPECT_STRNE(s1, s2) 验证条件: 两个 C 字符串有不同的值 + +Note: +1. 参数应满足 EXPECT_STR*(Expect, Actual)的格式,左边是期望值,右边是实际值 +2. 该组断言用于比较两个 C 字符串。如果你想要比较两个 string 对象,相应地使用 +EXPECT_EQ、EXPECT_NE 等断言 +3. EXPECT_STREQ 和 EXPECT_STRNE 不接受宽字符串(wchar_t*) +4. 一个 NULL 指针和一个空字符串会不是一样的 + +Example: +char* s1 = "", char* s2 = "abc", char* s3 = NULL; +EXPECT_STREQ("abc", s2); 通过 +EXPECT_STREQ(s1, s3); 失败 +EXPECT_STREQ(NULL, s3); 通过 +EXPECT_STRNE(" ", s1); 通过 +*/ + +#define EXPECT_STREQ(s1, s2) do { \ + if (s1 == NULL || s2 == NULL) { \ + if (s1 == NULL && s2 == NULL) { \ + UnitTest::GetInstance()->CurrentTestCase->nPassed++; \ + std::cout << green << " EXPECT_STRED succeeded!\n"; \ + } \ + else { \ + UnitTest::GetInstance()->CurrentTestCase->nTestResult = 0; \ + UnitTest::GetInstance()->CurrentTestCase->nFailed++; \ + std::cout << red << " EXPECT_STRED failed!\n"; \ + if(s1 == NULL) std::cout << " Expect: NULL\n"; \ + else std::cout << " Expect:\"" << s1 << "\"\n"; \ + if(s2 == NULL) std::cout << " Actual: NULL\n"; \ + else std::cout << " Actual:\"" << s2 << "\"\n"; \ + } \ + } \ + else if (strcmp(s1, s2) == 0) { \ + UnitTest::GetInstance()->CurrentTestCase->nPassed++; \ + std::cout << green << " EXPECT_STRED succeeded!\n"; \ + } \ + else { \ + UnitTest::GetInstance()->CurrentTestCase->nTestResult = 0; \ + UnitTest::GetInstance()->CurrentTestCase->nFailed++; \ + std::cout << red << " EXPECT_STRED failed!\n"; \ + std::cout << red << " Expect:\"" << s1 << "\"\n"; \ + std::cout << red << " Actual:\"" << s2 << "\"\n"; \ +}} while(0) + +#define EXPECT_STRNE(s1, s2) do { \ + if (s1 == NULL || s2 == NULL) { \ + if (s1 != NULL || s2 != NULL) { \ + UnitTest::GetInstance()->CurrentTestCase->nPassed++; \ + std::cout << green << " EXPECT_STRNE succeeded!\n"; \ + } \ + else { \ + UnitTest::GetInstance()->CurrentTestCase->nTestResult = 0; \ + UnitTest::GetInstance()->CurrentTestCase->nFailed++; \ + std::cout << red << " EXPECT_STRNE failed!\n"; \ + if(s1 == NULL) std::cout << " Expect: NULL\n"; \ + else std::cout << " Expect:\"" << s1 << "\"\n"; \ + if(s2 == NULL) std::cout << " Actual: NULL\n"; \ + else std::cout << " Actual:\"" << s2 << "\"\n"; \ + } \ + } \ + else if (strcmp(s1, s2) != 0) { \ + UnitTest::GetInstance()->CurrentTestCase->nPassed++; \ + std::cout << green << " EXPECT_STRNE succeeded!\n"; \ + } \ + else { \ + UnitTest::GetInstance()->CurrentTestCase->nTestResult = 0; \ + UnitTest::GetInstance()->CurrentTestCase->nFailed++; \ + std::cout << red << " EXPECT_STRNE failed!\n"; \ + std::cout << red << " Expect:\"" << s1 << "\"\n"; \ + std::cout << red << " Actual:\"" << s2 << "\"\n"; \ +}} while(0) + +/* +指针比较 +EXPECT_PTR_EQ(p1, p2) 验证条件: *p1 == *p2 +EXPECT_PTR_NE(p1, p2) 验证条件: *p1 != *p2 +EXPECT_PTR_RANGE_EQ(p1, p2, len) 验证条件: 任意 i (*p1 + i) == (*p2 + i) i∈[0,len) +EXPECT_PTR_RANGE_NE(p1, p2, len) 验证条件: 存在 i (*p1 + i) != (*p2 + i) i∈[0,len) + +Note: +1. 参数应满足 EXPECT_PTR_*(Expect, Actual)、 +EXPECT_PTR_RANGE_*(Expect, Actual, len)的格式, +即参数表中期望值在实际值左边 +2. EXPECT_PTR_EQ 比较的是指针所指元素的值,如果要比较 +指针指向的地址是否相等,请用 EXPECT_EQ +3. EXPECT_PTR_RANGE_* 比较的是从 p1,p2 开始, +长度为 len 的区间,请确保区间长度有效 + +Example: +int a[] = {1,2,3,4,5}; +int b[] = {1,2,3,4,6}; +int *p1 = a, *p2 = b; +EXPECT_PTR_EQ(p1, p2); 通过 +p1 = a + 4, p2 = b + 4; +EXPECT_PTR_EQ(p1, p2); 失败 +EXPECT_PTR_EQ(p1, std::find(a, a + 5, 5)); 通过 +EXPECT_PTR_RANGE_EQ(a, b, 5); 失败 +EXPECT_PTR_RANGE_EQ(a, b, 4); 通过 +*/ +#define EXPECT_PTR_EQ(p1, p2) do { \ + if (*p1 == *p2) { \ + UnitTest::GetInstance()->CurrentTestCase->nPassed++; \ + std::cout << green << " EXPECT_PTR_EQ succeeded!\n"; \ + } \ + else { \ + UnitTest::GetInstance()->CurrentTestCase->nTestResult = 0; \ + UnitTest::GetInstance()->CurrentTestCase->nFailed++; \ + std::cout << red << " EXPECT_PTR_EQ failed!\n"; \ + std::cout << red << " Expect:" << *p1 << "\n"; \ + std::cout << red << " Actual:" << *p2 << "\n"; \ +}} while(0) + +#define EXPECT_PTR_NE(p1, p2) do { \ + if (*p1 != *p2) { \ + UnitTest::GetInstance()->CurrentTestCase->nPassed++; \ + std::cout << green << " EXPECT_PTR_NE succeeded!\n"; \ + } \ + else { \ + UnitTest::GetInstance()->CurrentTestCase->nTestResult = 0; \ + UnitTest::GetInstance()->CurrentTestCase->nFailed++; \ + std::cout << red << " EXPECT_PTR_NE failed!\n"; \ + std::cout << red << " Expect:" << *p1 << "\n"; \ + std::cout << red << " Actual:" << *p2 << "\n"; \ +}} while(0) + +#define EXPECT_PTR_RANGE_EQ(p1, p2, len) do { \ + if (std::equal(p1, p1 + len, p2)) { \ + UnitTest::GetInstance()->CurrentTestCase->nPassed++; \ + std::cout << green << " EXPECT_PTR_RANGE_EQ succeeded!\n"; \ + } \ + else { \ + UnitTest::GetInstance()->CurrentTestCase->nTestResult = 0; \ + UnitTest::GetInstance()->CurrentTestCase->nFailed++; \ + std::cout << red << " EXPECT_PTR_RANGE_EQ failed!\n"; \ +}} while(0) + +#define EXPECT_PTR_RANGE_NE(p1, p2, len) do { \ + if (!std::equal(p1, p1 + len, p2)) { \ + UnitTest::GetInstance()->CurrentTestCase->nPassed++; \ + std::cout << green << " EXPECT_PTR_RANGE_NE succeeded!\n"; \ + } \ + else { \ + UnitTest::GetInstance()->CurrentTestCase->nTestResult = 0; \ + UnitTest::GetInstance()->CurrentTestCase->nFailed++; \ + std::cout << red << " EXPECT_PTR_RANGE_NE failed!\n"; \ +}} while(0) + +/* +容器比较 +EXPECT_CON_EQ(c1, c2) 验证条件: c1 == c2 +EXPECT_CON_NE(c1, c2) 验证条件: c1 != c2 + +Note: +1. 容器可以是 STL 容器,自定义的容器,或者数组,但不可以是指针 +2. 容器的数据类型要能够进行比较,类型一致或可以发生隐式转换 +3. EXPECT_CON_EQ 测试失败时,会打印首次不相等的两个值 + +Example: +int arr[] = {1,2,3}; +std::vector v1{1, 2, 3}; +std::vector v2{2, 3, 4}; +mystl::vector v3(arr, arr + 3); +EXPECT_CON_NE(v1, v2) ok +EXPECT_CON_EQ(arr, v1) ok +EXPECT_CON_EQ(v1, v3) ok +*/ +#define EXPECT_CON_EQ(c1, c2) do { \ + auto first1 = std::begin(c1), last1 = std::end(c1); \ + auto first2 = std::begin(c2), last2 = std::end(c2); \ + for (; first1 != last1 && first2 != last2; ++first1, ++first2) { \ + if (*first1 != *first2) break; \ + } \ + if (first1 == last1 && first2 == last2) { \ + UnitTest::GetInstance()->CurrentTestCase->nPassed++; \ + std::cout << green << " EXPECT_CON_EQ succeeded!\n"; \ + } \ + else { \ + UnitTest::GetInstance()->CurrentTestCase->nTestResult = 0; \ + UnitTest::GetInstance()->CurrentTestCase->nFailed++; \ + std::cout << red << " EXPECT_CON_EQ failed!\n"; \ + std::cout << red << " Expect:" << *first1 << "\n"; \ + std::cout << red << " Actual:" << *first2 << "\n"; \ +}} while(0) + +#define EXPECT_CON_NE(c1, c2) do { \ + auto first1 = std::begin(c1), last1 = std::end(c1); \ + auto first2 = std::begin(c2), last2 = std::end(c2); \ + for (; first1 != last1 && first2 != last2; ++first1, ++first2) { \ + if (*first1 != *first2) break; \ + } \ + if (first1 != last1 || first2 != last2) { \ + UnitTest::GetInstance()->CurrentTestCase->nPassed++; \ + std::cout << green << " EXPECT_CON_NE succeeded!\n"; \ + } \ + else { \ + UnitTest::GetInstance()->CurrentTestCase->nTestResult = 0; \ + UnitTest::GetInstance()->CurrentTestCase->nFailed++; \ + std::cout << red << " EXPECT_CON_NE failed!\n"; \ +}} while(0) + +/*****************************************************************************************/ +// 常用的宏定义 + +// 不同情况的测试数量级 +#if defined(_DEBUG) || defined(DEBUG) +#define LEN1 10000 +#define LEN2 100000 +#define LEN3 1000000 +#else +#define LEN1 100000 +#define LEN2 1000000 +#define LEN3 10000000 +#endif + +#define SCALE_LLL(N) (N * 20) +#define SCALE_LL(N) (N * 10) +#define SCALE_L(N) (N * 5) +#define SCALE_M(N) (N) +#define SCALE_S(N) (N / 5) +#define SCALE_SS(N) (N / 10) +#define SCALE_SSS(N) (N / 20) + +#define WIDE 14 + +// 输出通过提示 +#define PASSED std::cout << "[ PASSED ]\n" + +// 遍历输出容器 +#define COUT(container) do { \ + std::string con_name = #container; \ + std::cout << " " << con_name << " :"; \ + for (auto it : container) \ + std::cout << " " << it; \ + std::cout << "\n"; \ +} while(0) + +#define STR_COUT(str) do { \ + std::string str_name = #str; \ + std::cout << " " << str_name << " : " << str << "\n"; \ +} while(0) + +// 输出容器调用函数后的结果 +#define FUN_AFTER(con, fun) do { \ + std::string fun_name = #fun; \ + std::cout << " After " << fun_name << " :\n"; \ + fun; \ + COUT(con); \ +} while(0) + +#define STR_FUN_AFTER(str, fun) do { \ + std::string fun_name = #fun; \ + std::cout << " After " << fun_name << " :\n"; \ + fun; \ + STR_COUT(str); \ +} while(0) + +// 输出容器调用函数的值 +#define FUN_VALUE(fun) do { \ + std::string fun_name = #fun; \ + std::cout << " " << fun_name << " : " << fun << "\n"; \ +} while(0) + +// 输出测试数量级 +void test_len(size_t len1, size_t len2, size_t len3, size_t wide) +{ + std::string str1, str2, str3; + std::stringstream ss; + ss << len1 << " " << len2 << " " << len3; + ss >> str1 >> str2 >> str3; + str1 += " |"; + std::cout << std::setw(wide) << str1; + str2 += " |"; + std::cout << std::setw(wide) << str2; + str3 += " |"; + std::cout << std::setw(wide) << str3 << "\n"; +} + +#define TEST_LEN(len1, len2, len3, wide) \ + test_len(len1, len2, len3, wide) + +// 常用测试性能的宏 +#define FUN_TEST_FORMAT1(mode, fun, arg, count) do { \ + srand((int)time(0)); \ + clock_t start, end; \ + mode c; \ + char buf[10]; \ + start = clock(); \ + for (size_t i = 0; i < count; ++i) \ + c.fun(arg); \ + end = clock(); \ + int n = static_cast(static_cast(end - start) \ + / CLOCKS_PER_SEC * 1000); \ + std::snprintf(buf, sizeof(buf), "%d", n); \ + std::string t = buf; \ + t += "ms |"; \ + std::cout << std::setw(WIDE) << t; \ +} while(0) + +#define FUN_TEST_FORMAT2(mode, fun, arg1, arg2, count) do { \ + srand((int)time(0)); \ + clock_t start, end; \ + mode c; \ + char buf[10]; \ + start = clock(); \ + for (size_t i = 0; i < count; ++i) \ + c.fun(c.arg1(), arg2); \ + end = clock(); \ + int n = static_cast(static_cast(end - start) \ + / CLOCKS_PER_SEC * 1000); \ + std::snprintf(buf, sizeof(buf), "%d", n); \ + std::string t = buf; \ + t += "ms |"; \ + std::cout << std::setw(WIDE) << t; \ +} while(0) + +#define LIST_SORT_DO_TEST(mode, count) do { \ + srand((int)time(0)); \ + clock_t start, end; \ + mode::list l; \ + char buf[10]; \ + for (size_t i = 0; i < count; ++i) \ + l.insert(l.end(), rand()); \ + start = clock(); \ + l.sort(); \ + end = clock(); \ + int n = static_cast(static_cast(end - start) \ + / CLOCKS_PER_SEC * 1000); \ + std::snprintf(buf, sizeof(buf), "%d", n); \ + std::string t = buf; \ + t += "ms |"; \ + std::cout << std::setw(WIDE) << t; \ +} while(0) + +#define MAP_EMPLACE_DO_TEST(mode, con, count) do { \ + srand((int)time(0)); \ + clock_t start, end; \ + mode::con c; \ + char buf[10]; \ + start = clock(); \ + for (size_t i = 0; i < count; ++i) \ + c.emplace(mode::make_pair(rand(), rand())); \ + end = clock(); \ + int n = static_cast(static_cast(end - start) \ + / CLOCKS_PER_SEC * 1000); \ + std::snprintf(buf, sizeof(buf), "%d", n); \ + std::string t = buf; \ + t += "ms |"; \ + std::cout << std::setw(WIDE) << t; \ +} while(0) + +// 重构重复代码 +#define CON_TEST_P1(con, fun, arg, len1, len2, len3) \ + TEST_LEN(len1, len2, len3, WIDE); \ + std::cout << "| std |"; \ + FUN_TEST_FORMAT1(std::con, fun, arg, len1); \ + FUN_TEST_FORMAT1(std::con, fun, arg, len2); \ + FUN_TEST_FORMAT1(std::con, fun, arg, len3); \ + std::cout << "\n| mystl |"; \ + FUN_TEST_FORMAT1(mystl::con, fun, arg, len1); \ + FUN_TEST_FORMAT1(mystl::con, fun, arg, len2); \ + FUN_TEST_FORMAT1(mystl::con, fun, arg, len3); + +#define CON_TEST_P2(con, fun, arg1, arg2, len1, len2, len3) \ + TEST_LEN(len1, len2, len3, WIDE); \ + std::cout << "| std |"; \ + FUN_TEST_FORMAT2(std::con, fun, arg1, arg2, len1); \ + FUN_TEST_FORMAT2(std::con, fun, arg1, arg2, len2); \ + FUN_TEST_FORMAT2(std::con, fun, arg1, arg2, len3); \ + std::cout << "\n| mystl |"; \ + FUN_TEST_FORMAT2(mystl::con, fun, arg1, arg2, len1); \ + FUN_TEST_FORMAT2(mystl::con, fun, arg1, arg2, len2); \ + FUN_TEST_FORMAT2(mystl::con, fun, arg1, arg2, len3); + +#define MAP_EMPLACE_TEST(con, len1, len2, len3) \ + TEST_LEN(len1, len2, len3, WIDE); \ + std::cout << "| std |"; \ + MAP_EMPLACE_DO_TEST(std, con, len1); \ + MAP_EMPLACE_DO_TEST(std, con, len2); \ + MAP_EMPLACE_DO_TEST(std, con, len3); \ + std::cout << "\n| mystl |"; \ + MAP_EMPLACE_DO_TEST(mystl, con, len1); \ + MAP_EMPLACE_DO_TEST(mystl, con, len2); \ + MAP_EMPLACE_DO_TEST(mystl, con, len3); + +#define LIST_SORT_TEST(len1, len2, len3) \ + TEST_LEN(len1, len2, len3, WIDE); \ + std::cout << "| std |"; \ + LIST_SORT_DO_TEST(std, len1); \ + LIST_SORT_DO_TEST(std, len2); \ + LIST_SORT_DO_TEST(std, len3); \ + std::cout << "\n| mystl |"; \ + LIST_SORT_DO_TEST(mystl, len1); \ + LIST_SORT_DO_TEST(mystl, len2); \ + LIST_SORT_DO_TEST(mystl, len3); + +// 简单测试的宏定义 +#define TEST(testcase_name) \ + MYTINYSTL_TEST_(testcase_name) + +// 运行所有测试案例 +#define RUN_ALL_TESTS() \ + mystl::test::UnitTest::GetInstance()->Run() + +// 是否开启性能测试 +#ifndef PERFORMANCE_TEST_ON +#define PERFORMANCE_TEST_ON 1 +#endif // !PERFORMANCE_TEST_ON + +// 是否开启大数据量测试 +#ifndef LARGER_TEST_DATA_ON +#define LARGER_TEST_DATA_ON 0 +#endif // !LARGER_TEST_DATA_ON + +} // namespace test +} // namespace mystl +#endif // !MYTINYSTL_TEST_H_ + diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/unordered_map_test.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/unordered_map_test.h new file mode 100644 index 0000000..68dc96d --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/unordered_map_test.h @@ -0,0 +1,203 @@ +#ifndef MYTINYSTL_UNORDERED_MAP_TEST_H_ +#define MYTINYSTL_UNORDERED_MAP_TEST_H_ + +// unordered_map test : 测试 unordered_map, unordered_multimap 的接口与它们 insert 的性能 + +#include + +#include "../MyTinySTL/unordered_map.h" +#include "map_test.h" +#include "test.h" + +namespace mystl +{ +namespace test +{ +namespace unordered_map_test +{ + +void unordered_map_test() +{ + std::cout << "[===============================================================]" << std::endl; + std::cout << "[-------------- Run container test : unordered_map -------------]" << std::endl; + std::cout << "[-------------------------- API test ---------------------------]" << std::endl; + mystl::vector v; + for (int i = 0; i < 5; ++i) + v.push_back(PAIR(5 - i, 5 - i)); + mystl::unordered_map um1; + mystl::unordered_map um2(520); + mystl::unordered_map um3(520, mystl::hash()); + mystl::unordered_map um4(520, mystl::hash(), mystl::equal_to()); + mystl::unordered_map um5(v.begin(), v.end()); + mystl::unordered_map um6(v.begin(), v.end(), 100); + mystl::unordered_map um7(v.begin(), v.end(), 100, mystl::hash()); + mystl::unordered_map um8(v.begin(), v.end(), 100, mystl::hash(), mystl::equal_to()); + mystl::unordered_map um9(um5); + mystl::unordered_map um10(std::move(um5)); + mystl::unordered_map um11; + um11 = um6; + mystl::unordered_map um12; + um12 = std::move(um6); + mystl::unordered_map um13{ PAIR(1,1),PAIR(2,3),PAIR(3,3) }; + mystl::unordered_map um14; + um14 = { PAIR(1,1),PAIR(2,3),PAIR(3,3) }; + + MAP_FUN_AFTER(um1, um1.emplace(1, 1)); + MAP_FUN_AFTER(um1, um1.emplace_hint(um1.begin(), 1, 2)); + MAP_FUN_AFTER(um1, um1.insert(PAIR(2, 2))); + MAP_FUN_AFTER(um1, um1.insert(um1.end(), PAIR(3, 3))); + MAP_FUN_AFTER(um1, um1.insert(v.begin(), v.end())); + MAP_FUN_AFTER(um1, um1.erase(um1.begin())); + MAP_FUN_AFTER(um1, um1.erase(um1.begin(), um1.find(3))); + MAP_FUN_AFTER(um1, um1.erase(1)); + std::cout << std::boolalpha; + FUN_VALUE(um1.empty()); + std::cout << std::noboolalpha; + FUN_VALUE(um1.size()); + FUN_VALUE(um1.bucket_count()); + FUN_VALUE(um1.max_bucket_count()); + FUN_VALUE(um1.bucket(1)); + FUN_VALUE(um1.bucket_size(um1.bucket(5))); + MAP_FUN_AFTER(um1, um1.clear()); + MAP_FUN_AFTER(um1, um1.swap(um7)); + MAP_VALUE(*um1.begin()); + FUN_VALUE(um1.at(1)); + FUN_VALUE(um1[1]); + std::cout << std::boolalpha; + FUN_VALUE(um1.empty()); + std::cout << std::noboolalpha; + FUN_VALUE(um1.size()); + FUN_VALUE(um1.max_size()); + FUN_VALUE(um1.bucket_count()); + FUN_VALUE(um1.max_bucket_count()); + FUN_VALUE(um1.bucket(1)); + FUN_VALUE(um1.bucket_size(um1.bucket(1))); + MAP_FUN_AFTER(um1, um1.reserve(1000)); + FUN_VALUE(um1.size()); + FUN_VALUE(um1.bucket_count()); + FUN_VALUE(um1.bucket_size(1)); + FUN_VALUE(um1.bucket_size(2)); + FUN_VALUE(um1.bucket_size(3)); + MAP_FUN_AFTER(um1, um1.rehash(150)); + FUN_VALUE(um1.bucket_count()); + FUN_VALUE(um1.count(1)); + MAP_VALUE(*um1.find(3)); + auto first = *um1.equal_range(3).first; + auto second = *um1.equal_range(3).second; + std::cout << " um1.equal_range(3) : from <" << first.first << ", " << first.second + << "> to <" << second.first << ", " << second.second << ">" << std::endl; + FUN_VALUE(um1.load_factor()); + FUN_VALUE(um1.max_load_factor()); + MAP_FUN_AFTER(um1, um1.max_load_factor(1.5f)); + FUN_VALUE(um1.max_load_factor()); + PASSED; +#if PERFORMANCE_TEST_ON + std::cout << "[--------------------- Performance Testing ---------------------]" << std::endl; + std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl; + std::cout << "| emplace |"; +#if LARGER_TEST_DATA_ON + MAP_EMPLACE_TEST(unordered_map, SCALE_M(LEN1), SCALE_M(LEN2), SCALE_M(LEN3)); +#else + MAP_EMPLACE_TEST(unordered_map, SCALE_S(LEN1), SCALE_S(LEN2), SCALE_S(LEN3)); +#endif + std::cout << std::endl; + std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl; + PASSED; +#endif + std::cout << "[-------------- End container test : unordered_map -------------]" << std::endl; +} + +void unordered_multimap_test() +{ + std::cout << "[===============================================================]" << std::endl; + std::cout << "[----------- Run container test : unordered_multimap -----------]" << std::endl; + std::cout << "[-------------------------- API test ---------------------------]" << std::endl; + mystl::vector v; + for (int i = 0; i < 5; ++i) + v.push_back(PAIR(5 - i, 5 - i)); + mystl::unordered_multimap um1; + mystl::unordered_multimap um2(520); + mystl::unordered_multimap um3(520, mystl::hash()); + mystl::unordered_multimap um4(520, mystl::hash(), mystl::equal_to()); + mystl::unordered_multimap um5(v.begin(), v.end()); + mystl::unordered_multimap um6(v.begin(), v.end(), 100); + mystl::unordered_multimap um7(v.begin(), v.end(), 100, mystl::hash()); + mystl::unordered_multimap um8(v.begin(), v.end(), 100, mystl::hash(), mystl::equal_to()); + mystl::unordered_multimap um9(um5); + mystl::unordered_multimap um10(std::move(um5)); + mystl::unordered_multimap um11; + um11 = um6; + mystl::unordered_multimap um12; + um12 = std::move(um6); + mystl::unordered_multimap um13{ PAIR(1,1),PAIR(2,3),PAIR(3,3) }; + mystl::unordered_multimap um14; + um14 = { PAIR(1,1),PAIR(2,3),PAIR(3,3) }; + + MAP_FUN_AFTER(um1, um1.emplace(1, 1)); + MAP_FUN_AFTER(um1, um1.emplace_hint(um1.begin(), 1, 2)); + MAP_FUN_AFTER(um1, um1.insert(PAIR(2, 2))); + MAP_FUN_AFTER(um1, um1.insert(um1.end(), PAIR(3, 3))); + MAP_FUN_AFTER(um1, um1.insert(v.begin(), v.end())); + MAP_FUN_AFTER(um1, um1.erase(um1.begin())); + MAP_FUN_AFTER(um1, um1.erase(um1.begin(), um1.find(3))); + MAP_FUN_AFTER(um1, um1.erase(1)); + std::cout << std::boolalpha; + FUN_VALUE(um1.empty()); + std::cout << std::noboolalpha; + FUN_VALUE(um1.size()); + FUN_VALUE(um1.bucket_count()); + FUN_VALUE(um1.max_bucket_count()); + FUN_VALUE(um1.bucket(1)); + FUN_VALUE(um1.bucket_size(um1.bucket(5))); + MAP_FUN_AFTER(um1, um1.clear()); + MAP_FUN_AFTER(um1, um1.swap(um7)); + MAP_VALUE(*um1.begin()); + std::cout << std::boolalpha; + FUN_VALUE(um1.empty()); + std::cout << std::noboolalpha; + FUN_VALUE(um1.size()); + FUN_VALUE(um1.max_size()); + FUN_VALUE(um1.bucket_count()); + FUN_VALUE(um1.max_bucket_count()); + FUN_VALUE(um1.bucket(1)); + FUN_VALUE(um1.bucket_size(um1.bucket(1))); + MAP_FUN_AFTER(um1, um1.reserve(1000)); + FUN_VALUE(um1.size()); + FUN_VALUE(um1.bucket_count()); + FUN_VALUE(um1.bucket_size(1)); + FUN_VALUE(um1.bucket_size(2)); + FUN_VALUE(um1.bucket_size(3)); + MAP_FUN_AFTER(um1, um1.rehash(150)); + FUN_VALUE(um1.bucket_count()); + FUN_VALUE(um1.count(1)); + MAP_VALUE(*um1.find(3)); + auto first = *um1.equal_range(3).first; + auto second = *um1.equal_range(3).second; + std::cout << " um1.equal_range(3) : from <" << first.first << ", " << first.second + << "> to <" << second.first << ", " << second.second << ">" << std::endl; + FUN_VALUE(um1.load_factor()); + FUN_VALUE(um1.max_load_factor()); + MAP_FUN_AFTER(um1, um1.max_load_factor(1.5f)); + FUN_VALUE(um1.max_load_factor()); + PASSED; +#if PERFORMANCE_TEST_ON + std::cout << "[--------------------- Performance Testing ---------------------]" << std::endl; + std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl; + std::cout << "| emplace |"; +#if LARGER_TEST_DATA_ON + MAP_EMPLACE_TEST(unordered_multimap, SCALE_M(LEN1), SCALE_M(LEN2), SCALE_M(LEN3)); +#else + MAP_EMPLACE_TEST(unordered_multimap, SCALE_S(LEN1), SCALE_S(LEN2), SCALE_S(LEN3)); +#endif + std::cout << std::endl; + std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl; + PASSED; +#endif + std::cout << "[----------- End container test : unordered_multimap -----------]" << std::endl; +} + +} // namespace unordered_map_test +} // namespace test +} // namespace mystl +#endif // !MYTINYSTL_UNORDERED_MAP_TEST_H_ + diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/unordered_set_test.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/unordered_set_test.h new file mode 100644 index 0000000..82b99a2 --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/unordered_set_test.h @@ -0,0 +1,191 @@ +#ifndef MYTINYSTL_UNORDERED_SET_TEST_H_ +#define MYTINYSTL_UNORDERED_SET_TEST_H_ + +// unordered_set test : 测试 unordered_set, unordered_multiset 的接口与它们 insert 的性能 + +#include + +#include "../MyTinySTL/unordered_set.h" +#include "set_test.h" +#include "test.h" + +namespace mystl +{ +namespace test +{ +namespace unordered_set_test +{ + +void unordered_set_test() +{ + std::cout << "[===============================================================]" << std::endl; + std::cout << "[-------------- Run container test : unordered_set -------------]" << std::endl; + std::cout << "[-------------------------- API test ---------------------------]" << std::endl; + int a[] = { 5,4,3,2,1 }; + mystl::unordered_set us1; + mystl::unordered_set us2(520); + mystl::unordered_set us3(520, mystl::hash()); + mystl::unordered_set us4(520, mystl::hash(), mystl::equal_to()); + mystl::unordered_set us5(a, a + 5); + mystl::unordered_set us6(a, a + 5, 100); + mystl::unordered_set us7(a, a + 5, 100, mystl::hash()); + mystl::unordered_set us8(a, a + 5, 100, mystl::hash(), mystl::equal_to()); + mystl::unordered_set us9(us5); + mystl::unordered_set us10(std::move(us5)); + mystl::unordered_set us11; + us11 = us6; + mystl::unordered_set us12; + us12 = std::move(us6); + mystl::unordered_set us13{ 1,2,3,4,5 }; + mystl::unordered_set us14; + us13 = { 1,2,3,4,5 }; + + FUN_AFTER(us1, us1.emplace(1)); + FUN_AFTER(us1, us1.emplace_hint(us1.end(), 2)); + FUN_AFTER(us1, us1.insert(5)); + FUN_AFTER(us1, us1.insert(us1.begin(), 5)); + FUN_AFTER(us1, us1.insert(a, a + 5)); + FUN_AFTER(us1, us1.erase(us1.begin())); + FUN_AFTER(us1, us1.erase(us1.begin(), us1.find(3))); + FUN_AFTER(us1, us1.erase(1)); + std::cout << std::boolalpha; + FUN_VALUE(us1.empty()); + std::cout << std::noboolalpha; + FUN_VALUE(us1.size()); + FUN_VALUE(us1.bucket_count()); + FUN_VALUE(us1.max_bucket_count()); + FUN_VALUE(us1.bucket(1)); + FUN_VALUE(us1.bucket_size(us1.bucket(5))); + FUN_AFTER(us1, us1.clear()); + FUN_AFTER(us1, us1.swap(us7)); + FUN_VALUE(*us1.begin()); + std::cout << std::boolalpha; + FUN_VALUE(us1.empty()); + std::cout << std::noboolalpha; + FUN_VALUE(us1.size()); + FUN_VALUE(us1.max_size()); + FUN_VALUE(us1.bucket_count()); + FUN_AFTER(us1, us1.reserve(1000)); + FUN_VALUE(*us1.begin(us1.bucket(1))); + FUN_VALUE(us1.size()); + FUN_VALUE(us1.bucket_count()); + FUN_VALUE(us1.bucket_size(1)); + FUN_VALUE(us1.bucket_size(2)); + FUN_VALUE(us1.bucket_size(3)); + FUN_AFTER(us1, us1.rehash(150)); + FUN_VALUE(us1.bucket_count()); + FUN_VALUE(us1.count(1)); + FUN_VALUE(*us1.find(3)); + auto first = *us1.equal_range(3).first; + auto second = *us1.equal_range(3).second; + std::cout << " us1.equal_range(3) : from " << first << " to " << second << std::endl; + FUN_VALUE(us1.load_factor()); + FUN_VALUE(us1.max_load_factor()); + FUN_AFTER(us1, us1.max_load_factor(1.5f)); + FUN_VALUE(us1.max_load_factor()); + PASSED; +#if PERFORMANCE_TEST_ON + std::cout << "[--------------------- Performance Testing ---------------------]" << std::endl; + std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl; + std::cout << "| emplace |"; +#if LARGER_TEST_DATA_ON + CON_TEST_P1(unordered_set, emplace, rand(), SCALE_L(LEN1), SCALE_L(LEN2), SCALE_L(LEN3)); +#else + CON_TEST_P1(unordered_set, emplace, rand(), SCALE_M(LEN1), SCALE_M(LEN2), SCALE_M(LEN3)); +#endif + std::cout << std::endl; + std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl; + PASSED; +#endif + std::cout << "[-------------- End container test : unordered_set -------------]" << std::endl; +} + +void unordered_multiset_test() +{ + std::cout << "[===============================================================]" << std::endl; + std::cout << "[------------ Run container test : unordered_multiset ----------]" << std::endl; + std::cout << "[-------------------------- API test ---------------------------]" << std::endl; + int a[] = { 5,4,3,2,1 }; + mystl::unordered_multiset us1; + mystl::unordered_multiset us2(520); + mystl::unordered_multiset us3(520, mystl::hash()); + mystl::unordered_multiset us4(520, mystl::hash(), mystl::equal_to()); + mystl::unordered_multiset us5(a, a + 5); + mystl::unordered_multiset us6(a, a + 5, 100); + mystl::unordered_multiset us7(a, a + 5, 100, mystl::hash()); + mystl::unordered_multiset us8(a, a + 5, 100, mystl::hash(), mystl::equal_to()); + mystl::unordered_multiset us9(us5); + mystl::unordered_multiset us10(std::move(us5)); + mystl::unordered_multiset us11; + us11 = us6; + mystl::unordered_multiset us12; + us12 = std::move(us6); + mystl::unordered_multiset us13{ 1,2,3,4,5 }; + mystl::unordered_multiset us14; + us14 = { 1,2,3,4,5 }; + + FUN_AFTER(us1, us1.emplace(1)); + FUN_AFTER(us1, us1.emplace_hint(us1.end(), 2)); + FUN_AFTER(us1, us1.insert(5)); + FUN_AFTER(us1, us1.insert(us1.begin(), 5)); + FUN_AFTER(us1, us1.insert(a, a + 5)); + FUN_AFTER(us1, us1.erase(us1.begin())); + FUN_AFTER(us1, us1.erase(us1.begin(), us1.find(3))); + FUN_AFTER(us1, us1.erase(1)); + std::cout << std::boolalpha; + FUN_VALUE(us1.empty()); + std::cout << std::noboolalpha; + FUN_VALUE(us1.size()); + FUN_VALUE(us1.bucket_count()); + FUN_VALUE(us1.max_bucket_count()); + FUN_VALUE(us1.bucket(1)); + FUN_VALUE(us1.bucket_size(us1.bucket(5))); + FUN_AFTER(us1, us1.clear()); + FUN_AFTER(us1, us1.swap(us7)); + FUN_VALUE(*us1.begin()); + std::cout << std::boolalpha; + FUN_VALUE(us1.empty()); + std::cout << std::noboolalpha; + FUN_VALUE(us1.size()); + FUN_VALUE(us1.max_size()); + FUN_VALUE(us1.bucket_count()); + FUN_AFTER(us1, us1.reserve(1000)); + FUN_VALUE(*us1.begin(us1.bucket(1))); + FUN_VALUE(us1.size()); + FUN_VALUE(us1.bucket_count()); + FUN_VALUE(us1.bucket_size(1)); + FUN_VALUE(us1.bucket_size(2)); + FUN_VALUE(us1.bucket_size(3)); + FUN_AFTER(us1, us1.rehash(150)); + FUN_VALUE(us1.bucket_count()); + FUN_VALUE(us1.count(1)); + FUN_VALUE(*us1.find(3)); + auto first = *us1.equal_range(3).first; + auto second = *us1.equal_range(3).second; + std::cout << " us1.equal_range(3) : from " << first << " to " << second << std::endl; + FUN_VALUE(us1.load_factor()); + FUN_VALUE(us1.max_load_factor()); + FUN_AFTER(us1, us1.max_load_factor(1.5f)); + FUN_VALUE(us1.max_load_factor()); + PASSED; +#if PERFORMANCE_TEST_ON + std::cout << "[--------------------- Performance Testing ---------------------]" << std::endl; + std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl; + std::cout << "| emplace |"; +#if LARGER_TEST_DATA_ON + CON_TEST_P1(unordered_multiset, emplace, rand(), SCALE_M(LEN1), SCALE_M(LEN2), SCALE_M(LEN3)); +#else + CON_TEST_P1(unordered_multiset, emplace, rand(), SCALE_S(LEN1), SCALE_S(LEN2), SCALE_S(LEN3)); +#endif + std::cout << std::endl; + std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl; + PASSED; +#endif + std::cout << "[------------ End container test : unordered_multiset ----------]" << std::endl; +} + +} // namespace unordered_set_test +} // namespace test +} // namespace mystl +#endif // !MYTINYSTL_UNORDERED_SET_TEST_H_ + diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/vector_test.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/vector_test.h new file mode 100644 index 0000000..8b79ef6 --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/vector_test.h @@ -0,0 +1,114 @@ +#ifndef MYTINYSTL_VECTOR_TEST_H_ +#define MYTINYSTL_VECTOR_TEST_H_ + +// vector test : 测试 vector 的接口与 push_back 的性能 + +#include + +#include "../MyTinySTL/vector.h" +#include "test.h" + +namespace mystl +{ +namespace test +{ +namespace vector_test +{ + +void vector_test() +{ + std::cout << "[===============================================================]\n"; + std::cout << "[----------------- Run container test : vector -----------------]\n"; + std::cout << "[-------------------------- API test ---------------------------]\n"; + int a[] = { 1,2,3,4,5 }; + mystl::vector v1; + mystl::vector v2(10); + mystl::vector v3(10, 1); + mystl::vector v4(a, a + 5); + mystl::vector v5(v2); + mystl::vector v6(std::move(v2)); + mystl::vector v7{ 1,2,3,4,5,6,7,8,9 }; + mystl::vector v8, v9, v10; + v8 = v3; + v9 = std::move(v3); + v10 = { 1,2,3,4,5,6,7,8,9 }; + + FUN_AFTER(v1, v1.assign(8, 8)); + FUN_AFTER(v1, v1.assign(a, a + 5)); + FUN_AFTER(v1, v1.emplace(v1.begin(), 0)); + FUN_AFTER(v1, v1.emplace_back(6)); + FUN_AFTER(v1, v1.push_back(6)); + FUN_AFTER(v1, v1.insert(v1.end(), 7)); + FUN_AFTER(v1, v1.insert(v1.begin() + 3, 2, 3)); + FUN_AFTER(v1, v1.insert(v1.begin(), a, a + 5)); + FUN_AFTER(v1, v1.pop_back()); + FUN_AFTER(v1, v1.erase(v1.begin())); + FUN_AFTER(v1, v1.erase(v1.begin(), v1.begin() + 2)); + FUN_AFTER(v1, v1.reverse()); + FUN_AFTER(v1, v1.swap(v4)); + FUN_VALUE(*v1.begin()); + FUN_VALUE(*(v1.end() - 1)); + FUN_VALUE(*v1.rbegin()); + FUN_VALUE(*(v1.rend() - 1)); + FUN_VALUE(v1.front()); + FUN_VALUE(v1.back()); + FUN_VALUE(v1[0]); + FUN_VALUE(v1.at(1)); + int* p = v1.data(); + *p = 10; + *++p = 20; + p[1] = 30; + std::cout << " After change v1.data() :" << "\n"; + COUT(v1); + std::cout << std::boolalpha; + FUN_VALUE(v1.empty()); + std::cout << std::noboolalpha; + FUN_VALUE(v1.size()); + FUN_VALUE(v1.max_size()); + FUN_VALUE(v1.capacity()); + FUN_AFTER(v1, v1.resize(10)); + FUN_VALUE(v1.size()); + FUN_VALUE(v1.capacity()); + FUN_AFTER(v1, v1.shrink_to_fit()); + FUN_VALUE(v1.size()); + FUN_VALUE(v1.capacity()); + FUN_AFTER(v1, v1.resize(6, 6)); + FUN_VALUE(v1.size()); + FUN_VALUE(v1.capacity()); + FUN_AFTER(v1, v1.shrink_to_fit()); + FUN_VALUE(v1.size()); + FUN_VALUE(v1.capacity()); + FUN_AFTER(v1, v1.clear()); + FUN_VALUE(v1.size()); + FUN_VALUE(v1.capacity()); + FUN_AFTER(v1, v1.reserve(5)); + FUN_VALUE(v1.size()); + FUN_VALUE(v1.capacity()); + FUN_AFTER(v1, v1.reserve(20)); + FUN_VALUE(v1.size()); + FUN_VALUE(v1.capacity()); + FUN_AFTER(v1, v1.shrink_to_fit()); + FUN_VALUE(v1.size()); + FUN_VALUE(v1.capacity()); + PASSED; +#if PERFORMANCE_TEST_ON + std::cout << "[--------------------- Performance Testing ---------------------]\n"; + std::cout << "|---------------------|-------------|-------------|-------------|\n"; + std::cout << "| push_back |"; +#if LARGER_TEST_DATA_ON + CON_TEST_P1(vector, push_back, rand(), SCALE_LL(LEN1), SCALE_LL(LEN2), SCALE_LL(LEN3)); +#else + CON_TEST_P1(vector, push_back, rand(), SCALE_L(LEN1), SCALE_L(LEN2), SCALE_L(LEN3)); +#endif + std::cout << "\n"; + std::cout << "|---------------------|-------------|-------------|-------------|\n"; + PASSED; +#endif + std::cout << "[----------------- End container test : vector -----------------]\n"; +} + +} // namespace vector_test +} // namespace test +} // namespace mystl +#endif // !MYTINYSTL_VECTOR_TEST_H_ + diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/appveyor.yml b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/appveyor.yml new file mode 100644 index 0000000..faaba8d --- /dev/null +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/appveyor.yml @@ -0,0 +1,21 @@ +version: 2.0.1{build} + +branches: + only: + - master + +image: + - Visual Studio 2015 + - Visual Studio 2017 + +configuration: + - Release + +build: + parallel: true + project: MSVC\MyTinySTL_VS2015.sln + +test_script: + - cmd: cd .\MSVC\x64\Release\ + - cmd: MyTinySTL.exe + From 01c71207be0e51a0256fe1203d531d923598e296 Mon Sep 17 00:00:00 2001 From: Khara0 <2106107467@qq.com> Date: Mon, 16 Dec 2024 21:00:26 +0800 Subject: [PATCH 2/5] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=BA=86Test=E5=88=86?= =?UTF-8?q?=E6=94=AF=E7=9A=84=E9=83=A8=E5=88=86=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MyTinySTL-master/Test/CMakeLists.txt | 0 .../Test/Lib/redbud/io/color.h | 0 .../Test/Lib/redbud/platform.h | 0 .../MyTinySTL-master/Test/README.md | 0 .../Test/algorithm_performance_test.h | 173 +++++++++--------- .../MyTinySTL-master/Test/algorithm_test.h | 44 ++--- .../MyTinySTL-master/Test/deque_test.h | 49 ++--- .../MyTinySTL-master/Test/list_test.h | 0 .../MyTinySTL-master/Test/map_test.h | 0 .../MyTinySTL-master/Test/queue_test.h | 0 .../MyTinySTL-master/Test/set_test.h | 0 .../MyTinySTL-master/Test/stack_test.h | 0 .../MyTinySTL-master/Test/string_test.h | 0 .../MyTinySTL-master/Test/test.cpp | 0 .../MyTinySTL-master/Test/test.h | 0 .../Test/unordered_map_test.h | 0 .../Test/unordered_set_test.h | 0 .../MyTinySTL-master/Test/vector_test.h | 0 18 files changed, 134 insertions(+), 132 deletions(-) mode change 100644 => 100755 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/CMakeLists.txt mode change 100644 => 100755 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/Lib/redbud/io/color.h mode change 100644 => 100755 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/Lib/redbud/platform.h mode change 100644 => 100755 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/README.md mode change 100644 => 100755 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/algorithm_performance_test.h mode change 100644 => 100755 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/algorithm_test.h mode change 100644 => 100755 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/deque_test.h mode change 100644 => 100755 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/list_test.h mode change 100644 => 100755 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/map_test.h mode change 100644 => 100755 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/queue_test.h mode change 100644 => 100755 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/set_test.h mode change 100644 => 100755 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/stack_test.h mode change 100644 => 100755 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/string_test.h mode change 100644 => 100755 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/test.cpp mode change 100644 => 100755 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/test.h mode change 100644 => 100755 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/unordered_map_test.h mode change 100644 => 100755 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/unordered_set_test.h mode change 100644 => 100755 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/vector_test.h diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/CMakeLists.txt b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/CMakeLists.txt old mode 100644 new mode 100755 diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/Lib/redbud/io/color.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/Lib/redbud/io/color.h old mode 100644 new mode 100755 diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/Lib/redbud/platform.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/Lib/redbud/platform.h old mode 100644 new mode 100755 diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/README.md b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/README.md old mode 100644 new mode 100755 diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/algorithm_performance_test.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/algorithm_performance_test.h old mode 100644 new mode 100755 index 675e5b2..f6c9b97 --- a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/algorithm_performance_test.h +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/algorithm_performance_test.h @@ -1,108 +1,107 @@ -#ifndef MYTINYSTL_ALGORITHM_PERFORMANCE_TEST_H_ -#define MYTINYSTL_ALGORITHM_PERFORMANCE_TEST_H_ - -// 仅仅针对 sort, binary_search 做了性能测试 +#ifndef MYTINYSTL_ALGORITHM_PERFORMANCE_TEST_H_ // 预处理指令,防止头文件被重复包含 +#define MYTINYSTL_ALGORITHM_PERFORMANCE_TEST_H_ // 定义宏,用于防止头文件被重复包含 +// 包含标准库中的算法头文件 #include +// 包含自定义的算法头文件 #include "../MyTinySTL/algorithm.h" +// 包含测试相关的头文件 #include "test.h" -namespace mystl -{ -namespace test +namespace mystl // 命名空间mystl { -namespace algorithm_performance_test +namespace test // 命名空间test { +namespace algorithm_performance_test // 命名空间algorithm_performance_test,用于算法性能测试 -// 函数性能测试宏定义 +{ + // 函数性能测试宏定义,用于测试单个函数的性能 #define FUN_TEST1(mode, fun, count) do { \ - std::string fun_name = #fun; \ - srand((int)time(0)); \ - char buf[10]; \ - clock_t start, end; \ - int *arr = new int[count]; \ - for(size_t i = 0; i < count; ++i) *(arr + i) = rand(); \ - start = clock(); \ - mode::fun(arr, arr + count); \ - end = clock(); \ - int n = static_cast(static_cast(end - start) \ - / CLOCKS_PER_SEC * 1000); \ - std::snprintf(buf, sizeof(buf), "%d", n); \ - std::string t = buf; \ - t += "ms |"; \ - std::cout << std::setw(WIDE) << t; \ - delete []arr; \ -} while(0) + std::string fun_name = #fun; // 将函数名转换为字符串形式 \ + srand((int)time(0)); // 设置随机种子,确保每次运行结果的随机性 \ + char buf[10]; // 用于存储性能测试结果的字符数组 \ + clock_t start, end; // 定义开始和结束时间变量 \ + int *arr = new int[count]; // 分配数组内存 \ + for(size_t i = 0; i < count; ++i) *(arr + i) = rand(); // 填充随机数 \ + start = clock(); // 记录开始时间 \ + mode::fun(arr, arr + count); // 调用函数 \ + end = clock(); // 记录结束时间 \ + int n = static_cast(static_cast(end - start) // 计算时间差 \ + / CLOCKS_PER_SEC * 1000); // 转换为毫秒 \ + std::snprintf(buf, sizeof(buf), "%d", n); // 将时间差格式化为字符串 \ + std::string t = buf; // 将格式化的字符串赋值给字符串变量 \ + t += "ms |"; // 添加单位 \ + std::cout << std::setw(WIDE) << t; // 输出结果,WIDE为预定义的宽度 \ + delete []arr; // 释放内存 \ + } while(0) + // 函数性能测试宏定义,用于测试需要两个参数的函数的性能 #define FUN_TEST2(mode, fun, count) do { \ - std::string fun_name = #fun; \ - srand((int)time(0)); \ - char buf[10]; \ - clock_t start, end; \ - int *arr = new int[count]; \ - for(size_t i = 0; i < count; ++i) *(arr + i) = rand(); \ - start = clock(); \ - for(size_t i = 0; i < count; ++i) \ - mode::fun(arr, arr + count, rand()); \ - end = clock(); \ - int n = static_cast(static_cast(end - start) \ - / CLOCKS_PER_SEC * 1000); \ - std::snprintf(buf, sizeof(buf), "%d", n); \ - std::string t = buf; \ - t += "ms |"; \ - std::cout << std::setw(WIDE) << t; \ - delete []arr; \ -} while(0) + std::string fun_name = #fun; // 将函数名转换为字符串形式 \ + srand((int)time(0)); // 设置随机种子,确保每次运行结果的随机性 \ + char buf[10]; // 用于存储性能测试结果的字符数组 \ + clock_t start, end; // 定义开始和结束时间变量 \ + int *arr = new int[count]; // 分配数组内存 \ + for(size_t i = 0; i < count; ++i) *(arr + i) = rand(); // 填充随机数 \ + start = clock(); // 记录开始时间 \ + for(size_t i = 0; i < count; ++i) \ + mode::fun(arr, arr + count, rand()); // 调用函数,第二个参数为随机数 \ + end = clock(); // 记录结束时间 \ + int n = static_cast(static_cast(end - start) // 计算时间差 \ + / CLOCKS_PER_SEC * 1000); // 转换为毫秒 \ + std::snprintf(buf, sizeof(buf), "%d", n); // 将时间差格式化为字符串 \ + std::string t = buf; // 将格式化的字符串赋值给字符串变量 \ + t += "ms |"; // 添加单位 \ + std::cout << std::setw(WIDE) << t; // 输出结果,WIDE为预定义的宽度 \ + delete []arr; // 释放内存 \ + } while(0) -void binary_search_test() -{ - std::cout << "[------------------- function : binary_search ------------------]" << std::endl; - std::cout << "| orders of magnitude |"; - TEST_LEN(LEN1, LEN2, LEN3, WIDE); - std::cout << "| std |"; - FUN_TEST2(std, binary_search, LEN1); - FUN_TEST2(std, binary_search, LEN2); - FUN_TEST2(std, binary_search, LEN3); - std::cout << std::endl << "| mystl |"; - FUN_TEST2(mystl, binary_search, LEN1); - FUN_TEST2(mystl, binary_search, LEN2); - FUN_TEST2(mystl, binary_search, LEN3); - std::cout << std::endl; -} + void binary_search_test() // 二分查找性能测试函数 + { + std::cout << "[------------------- function : binary_search ------------------]" << std::endl; + std::cout << "| orders of magnitude |"; + TEST_LEN(LEN1, LEN2, LEN3, WIDE); // 输出测试长度的表头 + std::cout << "| std |"; // 输出标准库性能测试的表头 + FUN_TEST2(std, binary_search, LEN1); // 测试标准库的二分查找性能 + FUN_TEST2(std, binary_search, LEN2); + FUN_TEST2(std, binary_search, LEN3); + std::cout << std::endl << "| mystl |"; // 输出自定义库性能测试的表头 + FUN_TEST2(mystl, binary_search, LEN1); // 测试自定义库的二分查找性能 + FUN_TEST2(mystl, binary_search, LEN2); + FUN_TEST2(mystl, binary_search, LEN3); + std::cout << std::endl; // 输出换行 + } -void sort_test() -{ - std::cout << "[----------------------- function : sort -----------------------]" << std::endl; - std::cout << "| orders of magnitude |"; - TEST_LEN(LEN1, LEN2, LEN3, WIDE); - std::cout << "| std |"; - FUN_TEST1(std, sort, LEN1); - FUN_TEST1(std, sort, LEN2); - FUN_TEST1(std, sort, LEN3); - std::cout << std::endl << "| mystl |"; - FUN_TEST1(mystl, sort, LEN1); - FUN_TEST1(mystl, sort, LEN2); - FUN_TEST1(mystl, sort, LEN3); - std::cout << std::endl; -} + void sort_test() // 排序性能测试函数 + { + std::cout << "[----------------------- function : sort -----------------------]" << std::endl; + std::cout << "| orders of magnitude |"; // 输出测试长度的表头 + TEST_LEN(LEN1, LEN2, LEN3, WIDE); + std::cout << "| std |"; // 输出标准库性能测试的表头 + FUN_TEST1(std, sort, LEN1); // 测试标准库的排序性能 + FUN_TEST1(std, sort, LEN2); + FUN_TEST1(std, sort, LEN3); + std::cout << std::endl << "| mystl |"; // 输出自定义库性能测试的表头 + FUN_TEST1(mystl, sort, LEN1); // 测试自定义库的排序性能 + FUN_TEST1(mystl, sort, LEN2); + FUN_TEST1(mystl, sort, LEN3); + std::cout << std::endl; // 输出换行 + } -void algorithm_performance_test() -{ - -#if PERFORMANCE_TEST_ON - std::cout << "[===============================================================]" << std::endl; - std::cout << "[--------------- Run algorithm performance test ----------------]" << std::endl; - sort_test(); - binary_search_test(); - std::cout << "[--------------- End algorithm performance test ----------------]" << std::endl; - std::cout << "[===============================================================]" << std::endl; + void algorithm_performance_test() // 算法性能测试入口函数 + { +#if PERFORMANCE_TEST_ON // 如果定义了性能测试宏,则执行以下代码 + std::cout << "[===============================================================]" << std::endl; + std::cout << "[--------------- Run algorithm performance test ----------------]" << std::endl; + sort_test(); // 执行排序性能测试 + binary_search_test(); // 执行二分查找性能测试 + std::cout << "[--------------- End algorithm performance test ----------------]" << std::endl; + std::cout << "[===============================================================]" << std::endl; #endif // PERFORMANCE_TEST_ON - -} + } } // namespace algorithm_performance_test } // namespace test } // namespace mystl #endif // !MYTINYSTL_ALGORITHM_PERFORMANCE_TEST_H_ - diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/algorithm_test.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/algorithm_test.h old mode 100644 new mode 100755 index 92eccdc..3160b8d --- a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/algorithm_test.h +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/algorithm_test.h @@ -1,21 +1,21 @@ -#ifndef MYTINYSTL_ALGORITHM_TEST_H_ -#define MYTINYSTL_ALGORITHM_TEST_H_ - -// 算法测试: 包含了 mystl 的 81 个算法测试 +#ifndef MYTINYSTL_ALGORITHM_TEST_H_ // 防止头文件被重复包含 +#define MYTINYSTL_ALGORITHM_TEST_H_ // 同上 +// 包含标准库中的算法、函数和数值操作头文件 #include #include #include +// 包含自定义的算法和向量容器头文件 #include "../MyTinySTL/algorithm.h" #include "../MyTinySTL/vector.h" #include "test.h" -namespace mystl +namespace mystl // 命名空间mystl { -namespace test +namespace test // 命名空间test { - +// 取消宏定义max和min,以避免与标准库中的max和min冲突 #ifdef max #pragma message("#undefing marco max") #undef max @@ -26,25 +26,27 @@ namespace test #undef min #endif // min +// 针对_MSC_VER(微软编译器)的特殊处理,用于禁用特定的编译器警告 #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4389) #endif // _MSC_VER -namespace algorithm_test -{ - -// 一些可能会用到的辅助数据和函数 -int for_each_sum = 0; - -int gen() { return 5; } -int r(int i) { return (i * 5 + 1) % 9; } -bool is_odd(int i) { return i & 1; } -bool is_even(int i) { return !(i & 1); } -void arr_sum(int i) { for_each_sum += i; } -bool cmp(const int& a, const int& b) { return b < a; } -int unary_op(const int& x) { return x + 1; } -int binary_op(const int& x, const int& y) { return x + y; } +namespace algorithm_test // 命名空间algorithm_test,用于算法测试 +{ + // 一些辅助数据和函数,用于算法测试 + int for_each_sum = 0; // 用于累计求和的全局变量 + int gen() { return 5; } // 生成固定值的函数 + int r(int i) { return (i * 5 + 1) % 9; } // 一个简单的函数,用于生成测试数据 + bool is_odd(int i) { return i & 1; } // 判断奇数的函数 + bool is_even(int i) { return !(i & 1); } // 判断偶数的函数 + void arr_sum(int i) { for_each_sum += i; } // 累计求和的函数 + bool cmp(const int& a, const int& b) { return b < a; } // 用于比较的函数 + int unary_op(const int& x) { return x + 1; } // 一元操作函数 + int binary_op(const int& x, const int& y) { return x + y; } // 二元操作函数 + + // 以下是80个算法测试函数的简单测试 + // algobase test: 基础算法测试 // 以下为 80 个函数的简单测试 diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/deque_test.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/deque_test.h old mode 100644 new mode 100755 index 0793bf6..e77b5d4 --- a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/deque_test.h +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/deque_test.h @@ -1,40 +1,40 @@ -#ifndef MYTINYSTL_DEQUE_TEST_H_ -#define MYTINYSTL_DEQUE_TEST_H_ - -// deque test : 测试 deque 的接口和 push_front/push_back 的性能 +#ifndef MYTINYSTL_DEQUE_TEST_H_ // 防止头文件被重复包含 +#define MYTINYSTL_DEQUE_TEST_H_ // 同上 +// 包含标准库中的deque头文件 #include +// 包含自定义的deque头文件和测试框架头文件 #include "../MyTinySTL/deque.h" #include "test.h" -namespace mystl +namespace mystl // 命名空间mystl { -namespace test +namespace test // 命名空间test { -namespace deque_test +namespace deque_test // 命名空间deque_test,用于deque的测试 { - -void deque_test() +void deque_test() // 测试deque的接口和push_front/push_back的性能 { std::cout << "[===============================================================]" << std::endl; std::cout << "[----------------- Run container test : deque ------------------]" << std::endl; std::cout << "[-------------------------- API test ---------------------------]" << std::endl; - int a[] = { 1,2,3,4,5 }; - mystl::deque d1; - mystl::deque d2(5); - mystl::deque d3(5, 1); - mystl::deque d4(a, a + 5); - mystl::deque d5(d2); - mystl::deque d6(std::move(d2)); + int a[] = { 1,2,3,4,5 }; // 用于初始化的数组 + mystl::deque d1; // 空的deque + mystl::deque d2(5); // 指定大小的deque + mystl::deque d3(5, 1); // 指定大小和值的deque + mystl::deque d4(a, a + 5); // 由数组初始化的deque + mystl::deque d5(d2); // 拷贝构造的deque + mystl::deque d6(std::move(d2)); // 移动构造的deque mystl::deque d7; - d7 = d3; + d7 = d3; // 赋值拷贝 mystl::deque d8; - d8 = std::move(d3); - mystl::deque d9{ 1,2,3,4,5,6,7,8,9 }; + d8 = std::move(d3); // 赋值移动 + mystl::deque d9{ 1,2,3,4,5,6,7,8,9 }; // 列表初始化的deque mystl::deque d10; - d10 = { 1,2,3,4,5,6,7,8,9 }; + d10 = { 1,2,3,4,5,6,7,8,9 }; // 赋值列表初始化 + // 对deque的成员函数进行测试,FUN_AFTER宏用于打印函数执行后deque的状态 FUN_AFTER(d1, d1.assign(5, 1)); FUN_AFTER(d1, d1.assign(8, 8)); FUN_AFTER(d1, d1.assign(a, a + 5)); @@ -57,6 +57,7 @@ void deque_test() FUN_AFTER(d1, d1.clear()); FUN_AFTER(d1, d1.shrink_to_fit()); FUN_AFTER(d1, d1.swap(d4)); + // 测试访问元素的函数 FUN_VALUE(*(d1.begin())); FUN_VALUE(*(d1.end() - 1)); FUN_VALUE(*(d1.rbegin())); @@ -65,17 +66,19 @@ void deque_test() FUN_VALUE(d1.back()); FUN_VALUE(d1.at(1)); FUN_VALUE(d1[2]); + // 测试状态查询函数 std::cout << std::boolalpha; FUN_VALUE(d1.empty()); std::cout << std::noboolalpha; FUN_VALUE(d1.size()); FUN_VALUE(d1.max_size()); PASSED; -#if PERFORMANCE_TEST_ON + +#if PERFORMANCE_TEST_ON // 如果定义了性能测试宏,则执行以下代码 std::cout << "[--------------------- Performance Testing ---------------------]" << std::endl; std::cout << "|---------------------|-------------|-------------|-------------|" << std::endl; std::cout << "| push_front |"; -#if LARGER_TEST_DATA_ON +#if LARGER_TEST_DATA_ON // 如果定义了更大的测试数据宏,则执行以下代码 CON_TEST_P1(deque, push_front, rand(), SCALE_LL(LEN1), SCALE_LL(LEN2), SCALE_LL(LEN3)); #else CON_TEST_P1(deque, push_front, rand(), SCALE_L(LEN1), SCALE_L(LEN2), SCALE_L(LEN3)); @@ -94,9 +97,7 @@ void deque_test() #endif std::cout << "[----------------- End container test : deque ------------------]" << std::endl; } - } // namespace deque_test } // namespace test } // namespace mystl #endif // !MYTINYSTL_DEQUE_TEST_H_ - diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/list_test.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/list_test.h old mode 100644 new mode 100755 diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/map_test.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/map_test.h old mode 100644 new mode 100755 diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/queue_test.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/queue_test.h old mode 100644 new mode 100755 diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/set_test.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/set_test.h old mode 100644 new mode 100755 diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/stack_test.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/stack_test.h old mode 100644 new mode 100755 diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/string_test.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/string_test.h old mode 100644 new mode 100755 diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/test.cpp b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/test.cpp old mode 100644 new mode 100755 diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/test.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/test.h old mode 100644 new mode 100755 diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/unordered_map_test.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/unordered_map_test.h old mode 100644 new mode 100755 diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/unordered_set_test.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/unordered_set_test.h old mode 100644 new mode 100755 diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/vector_test.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/Test/vector_test.h old mode 100644 new mode 100755 From 6813dc20164c769b3d1eeecb37e1f2db557e1104 Mon Sep 17 00:00:00 2001 From: Shiina_cd Date: Mon, 16 Dec 2024 21:01:42 +0800 Subject: [PATCH 3/5] =?UTF-8?q?=E5=AF=B9stack.h=E5=81=9A=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MyTinySTL-master/MyTinySTL/stack.h | 327 ++++++++++-------- 1 file changed, 186 insertions(+), 141 deletions(-) diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/stack.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/stack.h index 39cb284..0a26db2 100644 --- a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/stack.h +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/stack.h @@ -1,173 +1,218 @@ -#ifndef MYTINYSTL_STACK_H_ +#ifndef MYTINYSTL_STACK_H_ // 预处理指令,防止头文件被重复包含 #define MYTINYSTL_STACK_H_ -//这是个头文件 + // 这个头文件包含了一个模板类 stack // stack : 栈 -#include "deque.h" - -namespace mystl -{ +#include "deque.h" // 包含 deque 类的头文件 -// 模板类 stack -// 参数一代表数据类型,参数二代表底层容器类型,缺省使用 mystl::deque 作为底层容器 -template > -class stack -{ -public: - typedef Container container_type; - // 使用底层容器的型别 - typedef typename Container::value_type value_type; - typedef typename Container::size_type size_type; - typedef typename Container::reference reference; - typedef typename Container::const_reference const_reference; - - static_assert(std::is_same::value, - "the value_type of Container should be same with T"); -private: - container_type c_; // 用底层容器表现 stack - -public: - // 构造、复制、移动函数 - stack() = default; - - explicit stack(size_type n) - :c_(n) - { - } - stack(size_type n, const value_type& value) - :c_(n, value) - { - } - - template - stack(IIter first, IIter last) - : c_(first, last) - { - } - - stack(std::initializer_list ilist) - :c_(ilist.begin(), ilist.end()) - { - } - - stack(const Container& c) - :c_(c) - { - } - stack(Container&& c) noexcept(std::is_nothrow_move_constructible::value) - :c_(mystl::move(c)) - { - } - - stack(const stack& rhs) - :c_(rhs.c_) - { - } - stack(stack&& rhs) noexcept(std::is_nothrow_move_constructible::value) - :c_(mystl::move(rhs.c_)) - { - } - - stack& operator=(const stack& rhs) - { - c_ = rhs.c_; - return *this; - } - stack& operator=(stack&& rhs) noexcept(std::is_nothrow_move_assignable::value) - { - c_ = mystl::move(rhs.c_); - return *this; - } - - stack& operator=(std::initializer_list ilist) - { - c_ = ilist; - return *this; - } - - ~stack() = default; - - // 访问元素相关操作 - reference top() { return c_.back(); } - const_reference top() const { return c_.back(); } - - // 容量相关操作 - bool empty() const noexcept { return c_.empty(); } - size_type size() const noexcept { return c_.size(); } - - // 修改容器相关操作 - - template - void emplace(Args&& ...args) - { c_.emplace_back(mystl::forward(args)...); } - - void push(const value_type& value) - { c_.push_back(value); } - void push(value_type&& value) - { c_.push_back(mystl::move(value)); } - - void pop() - { c_.pop_back(); } - - void clear() - { - while (!empty()) - pop(); - } - - void swap(stack& rhs) noexcept(noexcept(mystl::swap(c_, rhs.c_))) - { mystl::swap(c_, rhs.c_); } - -public: - friend bool operator==(const stack& lhs, const stack& rhs) { return lhs.c_ == rhs.c_; } - friend bool operator< (const stack& lhs, const stack& rhs) { return lhs.c_ < rhs.c_; } -}; - -// 重载比较操作符 -template -bool operator==(const stack& lhs, const stack& rhs) +namespace mystl // 命名空间 mystl,用于封装 mystl 库的组件 { - return lhs == rhs; -} - -template -bool operator<(const stack& lhs, const stack& rhs) -{ - return lhs < rhs; -} + // 模板类 stack + // 参数一代表数据类型,参数二代表底层容器类型,缺省使用 mystl::deque 作为底层容器 + template > + class stack + { + public: + typedef Container container_type; // 使用底层容器的型别 + typedef typename Container::value_type value_type; // 值类型 + typedef typename Container::size_type size_type; // 大小类型 + typedef typename Container::reference reference; // 引用类型 + typedef typename Container::const_reference const_reference; // 常量引用类型 + + static_assert(std::is_same::value, // 静态断言,确保 T 和 value_type 是相同的类型 + "the value_type of Container should be same with T"); + + private: + container_type c_; // 用底层容器表现 stack + + public: + // 构造、复制、移动函数 + stack() = default; // 默认构造函数 + + explicit stack(size_type n) // 构造函数,初始化指定数量的元素 + :c_(n) + { + } + stack(size_type n, const value_type& value) // 构造函数,初始化指定数量的相同元素 + :c_(n, value) + { + } + + template + stack(IIter first, IIter last) // 构造函数,使用迭代器范围初始化 + : c_(first, last) + { + } + + stack(std::initializer_list ilist) // 构造函数,使用初始化列表初始化 + :c_(ilist.begin(), ilist.end()) + { + } + + stack(const Container& c) // 构造函数,使用底层容器初始化 + :c_(c) + { + } + stack(Container&& c) noexcept(std::is_nothrow_move_constructible::value) // 移动构造函数 + :c_(mystl::move(c)) + { + } + + stack(const stack& rhs) // 复制构造函数 + :c_(rhs.c_) + { + } + stack(stack&& rhs) noexcept(std::is_nothrow_move_constructible::value) // 移动构造函数 + :c_(mystl::move(rhs.c_)) + { + } + + stack& operator=(const stack& rhs) // 复制赋值运算符 + { + c_ = rhs.c_; + return *this; + } + stack& operator=(stack&& rhs) noexcept(std::is_nothrow_move_assignable::value) // 移动赋值运算符 + { + c_ = mystl::move(rhs.c_); + return *this; + } + + stack& operator=(std::initializer_list ilist) // 初始化列表赋值运算符 + { + c_ = ilist; + return *this; + } + + ~stack() = default; // 默认析构函数 + + // 访问元素相关操作 + reference top() { return c_.back(); } // 返回栈顶元素的引用 + const_reference top() const { return c_.back(); } // 返回栈顶元素的常量引用 + + // 容量相关操作 + bool empty() const noexcept { return c_.empty(); } // 检查栈是否为空 + size_type size() const noexcept { return c_.size(); } // 返回栈的大小 + + // 修改容器相关操作 + template + void emplace(Args&& ...args) // 原地构造并添加元素到栈顶 + { + c_.emplace_back(mystl::forward(args)...); + } + + void push(const value_type& value) // 将元素添加到栈顶 + { + c_.push_back(value); + } + void push(value_type&& value) // 将移动构造的元素添加到栈顶 + { + c_.push_back(mystl::move(value)); + } + + void pop() // 移除栈顶元素 + { + c_.pop_back(); + } + + void clear() // 清空栈 + { + while (!empty()) + pop(); + } + + void swap(stack& rhs) noexcept(noexcept(mystl::swap(c_, rhs.c_))) // 交换两个栈的内容 + { + mystl::swap(c_, rhs.c_); + } + + public: + friend bool operator==(const stack& lhs, const stack& rhs) { return lhs.c_ == rhs.c_; } // 比较运算符,检查两个栈是否相等 + friend bool operator< (const stack& lhs, const stack& rhs) { return lhs.c_ < rhs.c_; } // 比较运算符,检查一个栈是否小于另一个栈 + }; + + // 重载比较操作符 + template + bool operator==(const stack& lhs, const stack& rhs) + { + return lhs == rhs; + } + + template + bool operator<(const stack& lhs, const stack& rhs) + { + return lhs < rhs; + } + + template + bool operator!=(const stack& lhs, const stack& rhs) + { + return !(lhs == rhs); + } + + template + bool operator>(const stack& lhs, const stack& rhs) + { + return rhs < lhs; + } + + template + bool operator<=(const stack& lhs, const stack& rhs) + { + return !(rhs < lhs); + } + + template + bool operator>=(const stack& lhs, const stack& rhs) + { + return !(lhs < rhs); + } + + // 重载 mystl 的 swap + template + void swap(stack& lhs, stack& rhs) noexcept(noexcept(lhs.swap(rhs))) + { + lhs.swap(rhs); + } +} // namespace mystl +#endif // !MYTINYSTL_STACK_H_ +// 比较运算符,检查两个栈是否不相等 template bool operator!=(const stack& lhs, const stack& rhs) { - return !(lhs == rhs); + return !(lhs == rhs); } +// 比较运算符,检查一个栈是否大于另一个栈 template bool operator>(const stack& lhs, const stack& rhs) { - return rhs < lhs; + return rhs < lhs; // 如果rhs小于lhs,则lhs大于rhs } +// 比较运算符,检查一个栈是否小于或等于另一个栈 template bool operator<=(const stack& lhs, const stack& rhs) { - return !(rhs < lhs); + return !(rhs < lhs); // 如果rhs不小于lhs,则lhs小于或等于rhs } +// 比较运算符,检查一个栈是否大于或等于另一个栈 template bool operator>=(const stack& lhs, const stack& rhs) { - return !(lhs < rhs); + return !(lhs < rhs); // 如果lhs不小于rhs,则lhs大于或等于rhs } -// 重载 mystl 的 swap +// 重载 mystl 的 swap 函数,用于交换两个 stack 对象的内容 +// 这个函数是友元函数,因为它需要访问 stack 的私有成员 template void swap(stack& lhs, stack& rhs) noexcept(noexcept(lhs.swap(rhs))) { - lhs.swap(rhs); + lhs.swap(rhs); // 调用 stack 类的 swap 方法 } -} // namespace mystl -#endif // !MYTINYSTL_STACK_H_ - +} // namespace mystl 结束命名空间 +#endif // !MYTINYSTL_STACK_H_ 结束头文件保护宏定义 \ No newline at end of file From e5fdcccf296497d6961c6e9ed2a262bb2136217c Mon Sep 17 00:00:00 2001 From: caoxin Date: Mon, 16 Dec 2024 21:04:44 +0800 Subject: [PATCH 4/5] update vector.h util.h unordered_ste.h --- .../MyTinySTL/unordered_set.h | 310 ++++++++++++------ .../MyTinySTL-master/MyTinySTL/util.h | 219 +++++++------ .../MyTinySTL-master/MyTinySTL/vector.h | 184 ++++++++--- 3 files changed, 473 insertions(+), 240 deletions(-) mode change 100644 => 100755 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/unordered_set.h mode change 100644 => 100755 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/util.h mode change 100644 => 100755 MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/vector.h diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/unordered_set.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/unordered_set.h old mode 100644 new mode 100755 index eb60589..ad5a2c1 --- a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/unordered_set.h +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/unordered_set.h @@ -144,44 +144,94 @@ public: // empalce / empalce_hint template - pair emplace(Args&& ...args) - { return ht_.emplace_unique(mystl::forward(args)...); } +pair emplace(Args&& ...args) +{ + // 使用哈希表的 emplace_unique 方法插入元素 + return ht_.emplace_unique(mystl::forward(args)...); +} - template - iterator emplace_hint(const_iterator hint, Args&& ...args) - { return ht_.emplace_unique_use_hint(hint, mystl::forward(args)...); } +// 就地构造并插入一个新的元素,使用 hint 提示位置 +template +iterator emplace_hint(const_iterator hint, Args&& ...args) +{ + // 使用哈希表的 emplace_unique_use_hint 方法插入元素 + return ht_.emplace_unique_use_hint(hint, mystl::forward(args)...); +} - // insert +// 插入元素 - pair insert(const value_type& value) - { return ht_.insert_unique(value); } - pair insert(value_type&& value) - { return ht_.emplace_unique(mystl::move(value)); } +// 插入一个值等于 value 的元素 +pair insert(const value_type& value) +{ + // 使用哈希表的 insert_unique 方法插入元素 + return ht_.insert_unique(value); +} - iterator insert(const_iterator hint, const value_type& value) - { return ht_.insert_unique_use_hint(hint, value); } - iterator insert(const_iterator hint, value_type&& value) - { return ht_.emplace_unique_use_hint(hint, mystl::move(value)); } +// 插入一个值等于 value 的右值引用元素 +pair insert(value_type&& value) +{ + // 使用哈希表的 emplace_unique 方法插入元素 + return ht_.emplace_unique(mystl::move(value)); +} - template - void insert(InputIterator first, InputIterator last) - { ht_.insert_unique(first, last); } +// 在 hint 提示位置插入一个值等于 value 的元素 +iterator insert(const_iterator hint, const value_type& value) +{ + // 使用哈希表的 insert_unique_use_hint 方法插入元素 + return ht_.insert_unique_use_hint(hint, value); +} - // erase / clear +// 在 hint 提示位置插入一个值等于 value 的右值引用元素 +iterator insert(const_iterator hint, value_type&& value) +{ + // 使用哈希表的 emplace_unique_use_hint 方法插入元素 + return ht_.emplace_unique_use_hint(hint, mystl::move(value)); +} - void erase(iterator it) - { ht_.erase(it); } - void erase(iterator first, iterator last) - { ht_.erase(first, last); } +// 插入一个范围的元素 +template +void insert(InputIterator first, InputIterator last) +{ + // 使用哈希表的 insert_unique 方法插入元素 + ht_.insert_unique(first, last); +} - size_type erase(const key_type& key) - { return ht_.erase_unique(key); } +// 删除和清除元素 - void clear() - { ht_.clear(); } +// 删除一个迭代器指向的元素 +void erase(iterator it) +{ + // 使用哈希表的 erase 方法删除元素 + ht_.erase(it); +} + +// 删除一个迭代器范围的元素 +void erase(iterator first, iterator last) +{ + // 使用哈希表的 erase 方法删除元素 + ht_.erase(first, last); +} + +// 删除一个键值等于 key 的元素 +size_type erase(const key_type& key) +{ + // 使用哈希表的 erase_unique 方法删除元素 + return ht_.erase_unique(key); +} + +// 清除所有元素 +void clear() +{ + // 使用哈希表的 clear 方法清除所有元素 + ht_.clear(); +} - void swap(unordered_set& other) noexcept - { ht_.swap(other.ht_); } +// 交换当前 unordered_set 对象与另一个 unordered_set 对象的内容 +void swap(unordered_set& other) noexcept +{ + // 使用哈希表的 swap 方法交换内容 + ht_.swap(other.ht_); +} // 查找相关 @@ -310,69 +360,83 @@ public: public: // 构造、复制、移动函数 - unordered_multiset() +// 默认构造函数,创建一个包含默认数量桶(100)的 unordered_multiset +unordered_multiset() :ht_(100, Hash(), KeyEqual()) - { - } +{ +} - explicit unordered_multiset(size_type bucket_count, +// 显式构造函数,创建一个包含指定数量桶的 unordered_multiset,可能还会指定哈希函数和键值比较函数 +explicit unordered_multiset(size_type bucket_count, const Hash& hash = Hash(), const KeyEqual& equal = KeyEqual()) :ht_(bucket_count, hash, equal) - { - } +{ +} - template - unordered_multiset(InputIterator first, InputIterator last, +// 模板构造函数,创建一个包含指定范围元素的 unordered_multiset,可能还会指定桶的数量和哈希函数和键值比较函数 +template +unordered_multiset(InputIterator first, InputIterator last, const size_type bucket_count = 100, const Hash& hash = Hash(), const KeyEqual& equal = KeyEqual()) : ht_(mystl::max(bucket_count, static_cast(mystl::distance(first, last))), hash, equal) - { - for (; first != last; ++first) - ht_.insert_multi_noresize(*first); - } +{ + // 将范围 [first, last) 中的元素插入到哈希表中 + for (; first != last; ++first) + ht_.insert_multi_noresize(*first); +} - unordered_multiset(std::initializer_list ilist, +// 构造函数,创建一个包含 initializer_list 中元素的 unordered_multiset,可能还会指定桶的数量和哈希函数和键值比较函数 +unordered_multiset(std::initializer_list ilist, const size_type bucket_count = 100, const Hash& hash = Hash(), const KeyEqual& equal = KeyEqual()) :ht_(mystl::max(bucket_count, static_cast(ilist.size())), hash, equal) - { - for (auto first = ilist.begin(), last = ilist.end(); first != last; ++first) - ht_.insert_multi_noresize(*first); - } +{ + // 将 initializer_list 中的元素插入到哈希表中 + for (auto first = ilist.begin(), last = ilist.end(); first != last; ++first) + ht_.insert_multi_noresize(*first); +} - unordered_multiset(const unordered_multiset& rhs) +// 拷贝构造函数,创建一个与 rhs 相等的 unordered_multiset +unordered_multiset(const unordered_multiset& rhs) :ht_(rhs.ht_) - { - } - unordered_multiset(unordered_multiset&& rhs) noexcept +{ +} + +// 移动构造函数,创建一个与 rhs 相等的 unordered_multiset,使用移动语义 +unordered_multiset(unordered_multiset&& rhs) noexcept : ht_(mystl::move(rhs.ht_)) - { - } +{ +} - unordered_multiset& operator=(const unordered_multiset& rhs) - { - ht_ = rhs.ht_; - return *this; - } - unordered_multiset& operator=(unordered_multiset&& rhs) - { - ht_ = mystl::move(rhs.ht_); - return *this; - } +// 拷贝赋值运算符,将 rhs 的内容赋值给当前 unordered_multiset +unordered_multiset& operator=(const unordered_multiset& rhs) +{ + ht_ = rhs.ht_; + return *this; +} - unordered_multiset& operator=(std::initializer_list ilist) - { - ht_.clear(); - ht_.reserve(ilist.size()); - for (auto first = ilist.begin(), last = ilist.end(); first != last; ++first) - ht_.insert_multi_noresize(*first); - return *this; - } +// 移动赋值运算符,将 rhs 的内容移动到当前 unordered_multiset +unordered_multiset& operator=(unordered_multiset&& rhs) +{ + ht_ = mystl::move(rhs.ht_); + return *this; +} - ~unordered_multiset() = default; +// 赋值运算符,将 initializer_list 中的元素赋值给当前 unordered_multiset +unordered_multiset& operator=(std::initializer_list ilist) +{ + ht_.clear(); + ht_.reserve(ilist.size()); + for (auto first = ilist.begin(), last = ilist.end(); first != last; ++first) + ht_.insert_multi_noresize(*first); + return *this; +} + +// 析构函数,使用默认实现 +~unordered_multiset() = default; // 迭代器相关 @@ -402,44 +466,94 @@ public: // emplace / emplace_hint template - iterator emplace(Args&& ...args) - { return ht_.emplace_multi(mystl::forward(args)...); } +iterator emplace(Args&& ...args) +{ + // 使用哈希表的 emplace_multi 方法插入元素 + return ht_.emplace_multi(mystl::forward(args)...); +} - template - iterator emplace_hint(const_iterator hint, Args&& ...args) - { return ht_.emplace_multi_use_hint(hint, mystl::forward(args)...); } +// 就地构造并插入一个新的元素,使用 hint 提示位置 +template +iterator emplace_hint(const_iterator hint, Args&& ...args) +{ + // 使用哈希表的 emplace_multi_use_hint 方法插入元素 + return ht_.emplace_multi_use_hint(hint, mystl::forward(args)...); +} - // insert +// 插入元素 - iterator insert(const value_type& value) - { return ht_.insert_multi(value); } - iterator insert(value_type&& value) - { return ht_.emplace_multi(mystl::move(value)); } +// 插入一个值等于 value 的元素 +iterator insert(const value_type& value) +{ + // 使用哈希表的 insert_multi 方法插入元素 + return ht_.insert_multi(value); +} - iterator insert(const_iterator hint, const value_type& value) - { return ht_.insert_multi_use_hint(hint, value); } - iterator insert(const_iterator hint, value_type&& value) - { return ht_.emplace_multi_use_hint(hint, mystl::move(value)); } +// 插入一个值等于 value 的右值引用元素 +iterator insert(value_type&& value) +{ + // 使用哈希表的 emplace_multi 方法插入元素 + return ht_.emplace_multi(mystl::move(value)); +} - template - void insert(InputIterator first, InputIterator last) - { ht_.insert_multi(first, last); } +// 在 hint 提示位置插入一个值等于 value 的元素 +iterator insert(const_iterator hint, const value_type& value) +{ + // 使用哈希表的 insert_multi_use_hint 方法插入元素 + return ht_.insert_multi_use_hint(hint, value); +} + +// 在 hint 提示位置插入一个值等于 value 的右值引用元素 +iterator insert(const_iterator hint, value_type&& value) +{ + // 使用哈希表的 emplace_multi_use_hint 方法插入元素 + return ht_.emplace_multi_use_hint(hint, mystl::move(value)); +} + +// 插入一个范围的元素 +template +void insert(InputIterator first, InputIterator last) +{ + // 使用哈希表的 insert_multi 方法插入元素 + ht_.insert_multi(first, last); +} - // erase / clear +// 删除和清除元素 - void erase(iterator it) - { ht_.erase(it); } - void erase(iterator first, iterator last) - { ht_.erase(first, last); } +// 删除一个迭代器指向的元素 +void erase(iterator it) +{ + // 使用哈希表的 erase 方法删除元素 + ht_.erase(it); +} - size_type erase(const key_type& key) - { return ht_.erase_multi(key); } +// 删除一个迭代器范围的元素 +void erase(iterator first, iterator last) +{ + // 使用哈希表的 erase 方法删除元素 + ht_.erase(first, last); +} - void clear() - { ht_.clear(); } +// 删除一个键值等于 key 的元素 +size_type erase(const key_type& key) +{ + // 使用哈希表的 erase_multi 方法删除元素 + return ht_.erase_multi(key); +} + +// 清除所有元素 +void clear() +{ + // 使用哈希表的 clear 方法清除所有元素 + ht_.clear(); +} - void swap(unordered_multiset& other) noexcept - { ht_.swap(other.ht_); } +// 交换当前 unordered_multiset 对象与另一个 unordered_multiset 对象的内容 +void swap(unordered_multiset& other) noexcept +{ + // 使用哈希表的 swap 方法交换内容 + ht_.swap(other.ht_); +} // 查找相关 diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/util.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/util.h old mode 100644 new mode 100755 index df6d583..49db96d --- a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/util.h +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/util.h @@ -21,173 +21,195 @@ typename std::remove_reference::type&& move(T&& arg) noexcept // forward template -T&& forward(typename std::remove_reference::type& arg) noexcept +T&& forward(typename std::remove_reference::type& arg) noexcept // noexcept 表示函数不会抛出异常 { - return static_cast(arg); + // 使用 static_cast 将左值引用转换为 T 类型的右值引用(如果 T 是右值引用)或左值引用(如果 T 是左值引用) + // 这是因为 T&& 在模板中会根据 T 的实际类型(是否包含引用)表现为左值引用或右值引用 + // 这种特性被称为“引用折叠”或“引用塌缩” + return static_cast(arg); } - + +// 第二个模板,用于右值引用的情况 template -T&& forward(typename std::remove_reference::type&& arg) noexcept +T&& forward(typename std::remove_reference::type&& arg) noexcept // 同样标记为 noexcept { - static_assert(!std::is_lvalue_reference::value, "bad forward"); - return static_cast(arg); + // 使用 static_assert 进行编译期检查,确保 T 不是左值引用 + // 如果 T 是左值引用,那么这个函数模板就不应该被实例化,因为它只处理右值引用的情况 + static_assert(!std::is_lvalue_reference::value, "bad forward: T must not be an lvalue reference"); + + // 与第一个模板类似,使用 static_cast 将参数转换为 T 类型的引用 + // 在这里,由于参数本身就是右值引用,所以转换后的类型也一定是右值引用 + return static_cast(arg); } - // swap +// 交换两个类型为 Tp 的对象 lhs 和 rhs 的值 template void swap(Tp& lhs, Tp& rhs) { + // 使用 mystl::move 来移动 lhs 的值到临时对象 tmp + // 这样做可以避免在 lhs 和 rhs 相等时的自我赋值问题 auto tmp(mystl::move(lhs)); + // 将 rhs 的值移动到 lhs lhs = mystl::move(rhs); + // 将 tmp(原 lhs 的值)移动到 rhs rhs = mystl::move(tmp); } +// 交换两个范围 [first1, last1) 和 [first2, first2 + (last1 - first1)) 的元素 template ForwardIter2 swap_range(ForwardIter1 first1, ForwardIter1 last1, ForwardIter2 first2) { + // 遍历两个范围,使用 mystl::swap 交换对应的元素 for (; first1 != last1; ++first1, (void) ++first2) mystl::swap(*first1, *first2); + // 返回第二个范围的末尾迭代器 return first2; } +// 交换两个类型为 Tp 的数组 a 和 b,它们的大小都是 N template void swap(Tp(&a)[N], Tp(&b)[N]) { + // 使用 swap_range 函数来交换两个数组的元素 mystl::swap_range(a, a + N, b); } - // -------------------------------------------------------------------------------------- // pair // 结构体模板 : pair // 两个模板参数分别表示两个数据的类型 // 用 first 和 second 来分别取出第一个数据和第二个数据 +// 定义一个存储两个值的模板结构体 pair template struct pair { + // 定义 pair 中两个元素的类型 typedef Ty1 first_type; typedef Ty2 second_type; + // pair 的两个数据成员,存储两个不同类型的值 first_type first; // 保存第一个数据 second_type second; // 保存第二个数据 - // default constructiable - template ::value && - std::is_default_constructible::value, void>::type> - constexpr pair() + // 默认构造函数,当两个类型都可以默认构造时 + template ::value && + std::is_default_constructible::value, void>::type> + constexpr pair() : first(), second() { } - // implicit constructiable for this type + // 拷贝构造函数,当两个类型都可以拷贝构造并且可以隐式转换时 template ::value && - std::is_copy_constructible::value && - std::is_convertible::value && - std::is_convertible::value, int>::type = 0> - constexpr pair(const Ty1& a, const Ty2& b) + std::is_copy_constructible::value && + std::is_copy_constructible::value && + std::is_convertible::value && + std::is_convertible::value, int>::type> + constexpr pair(const Ty1& a, const Ty2& b) : first(a), second(b) { } - // explicit constructible for this type + // 显式拷贝构造函数,当两个类型都可以拷贝构造但不能隐式转换时 template ::value && - std::is_copy_constructible::value && - (!std::is_convertible::value || - !std::is_convertible::value), int>::type = 0> - explicit constexpr pair(const Ty1& a, const Ty2& b) + std::is_copy_constructible::value && + std::is_copy_constructible::value && + (!std::is_convertible::value || + !std::is_convertible::value), int>::type> + explicit constexpr pair(const Ty1& a, const Ty2& b) : first(a), second(b) { } + // 拷贝赋值运算符,使用默认实现 pair(const pair& rhs) = default; + // 移动构造函数,使用默认实现 pair(pair&& rhs) = default; - // implicit constructiable for other type + // 完美转发构造函数,当两个类型都可以构造并且可以隐式转换时 template ::value && - std::is_constructible::value && - std::is_convertible::value && - std::is_convertible::value, int>::type = 0> - constexpr pair(Other1&& a, Other2&& b) + std::is_constructible::value && + std::is_constructible::value && + std::is_convertible::value && + std::is_convertible::value, int>::type> + constexpr pair(Other1&& a, Other2&& b) : first(mystl::forward(a)), - second(mystl::forward(b)) + second(mystl::forward(b)) { } - // explicit constructiable for other type + // 显式完美转发构造函数,当两个类型都可以构造但不能隐式转换时 template ::value && - std::is_constructible::value && - (!std::is_convertible::value || - !std::is_convertible::value), int>::type = 0> - explicit constexpr pair(Other1&& a, Other2&& b) + std::is_constructible::value && + std::is_constructible::value && + (!std::is_convertible::value || + !std::is_convertible::value), int>::type> + explicit constexpr pair(Other1&& a, Other2&& b) : first(mystl::forward(a)), - second(mystl::forward(b)) + second(mystl::forward(b)) { } - // implicit constructiable for other pair + // 拷贝构造函数,用于从其他类型的 pair 构造当前 pair template ::value && - std::is_constructible::value && - std::is_convertible::value && - std::is_convertible::value, int>::type = 0> - constexpr pair(const pair& other) + std::is_constructible::value && + std::is_constructible::value && + std::is_convertible::value && + std::is_convertible::value, int>::type> + constexpr pair(const pair& other) : first(other.first), - second(other.second) + second(other.second) { } - // explicit constructiable for other pair + // 显式拷贝构造函数,用于从其他类型的 pair 构造当前 pair template ::value && - std::is_constructible::value && - (!std::is_convertible::value || - !std::is_convertible::value), int>::type = 0> - explicit constexpr pair(const pair& other) + std::is_constructible::value && + std::is_constructible::value && + (!std::is_convertible::value || + !std::is_convertible::value), int>::type> + explicit constexpr pair(const pair& other) : first(other.first), - second(other.second) + second(other.second) { } - // implicit constructiable for other pair + // 完美转发构造函数,用于从其他类型的 pair 构造当前 pair template ::value && - std::is_constructible::value && - std::is_convertible::value && - std::is_convertible::value, int>::type = 0> - constexpr pair(pair&& other) + std::is_constructible::value && + std::is_constructible::value && + std::is_convertible::value && + std::is_convertible::value, int>::type> + constexpr pair(pair&& other) : first(mystl::forward(other.first)), - second(mystl::forward(other.second)) + second(mystl::forward(other.second)) { } - // explicit constructiable for other pair + // 显式完美转发构造函数,用于从其他类型的 pair 构造当前 pair template ::value && - std::is_constructible::value && - (!std::is_convertible::value || - !std::is_convertible::value), int>::type = 0> - explicit constexpr pair(pair&& other) + std::is_constructible::value && + std::is_constructible::value && + (!std::is_convertible::value || + !std::is_convertible::value), int>::type> + explicit constexpr pair(pair&& other) : first(mystl::forward(other.first)), - second(mystl::forward(other.second)) + second(mystl::forward(other.second)) { } - // copy assign for this pair + // 拷贝赋值运算符,将 rhs 的值赋给当前 pair 对象 pair& operator=(const pair& rhs) { if (this != &rhs) @@ -197,6 +219,7 @@ struct pair } return *this; } +}; // move assign for this pair pair& operator=(pair&& rhs) @@ -219,71 +242,83 @@ struct pair } // move assign for other pair - template - pair& operator=(pair&& other) - { - first = mystl::forward(other.first); - second = mystl::forward(other.second); - return *this; - } + // 移动赋值运算符,用于将另一个 pair 对象的值移动到当前 pair 对象中 +template +pair& operator=(pair&& other) +{ + // 使用完美转发将 other 对象的第一个值移动到当前对象的第一个值 + first = mystl::forward(other.first); + // 使用完美转发将 other 对象的第二个值移动到当前对象的第二个值 + second = mystl::forward(other.second); + // 返回当前对象的引用 + return *this; +} - ~pair() = default; +// 析构函数,使用默认的析构函数 +~pair() = default; - void swap(pair& other) +// 交换当前 pair 对象与另一个 pair 对象的值 +void swap(pair& other) +{ + // 如果两个 pair 对象不是同一个对象,则进行交换 + if (this != &other) { - if (this != &other) - { - mystl::swap(first, other.first); - mystl::swap(second, other.second); - } + // 交换第一个值 + mystl::swap(first, other.first); + // 交换第二个值 + mystl::swap(second, other.second); } - -}; +} // 重载比较操作符 +// 比较两个 pair 对象是否相等 template bool operator==(const pair& lhs, const pair& rhs) { + // 如果两个 pair 对象的第一个元素和第二个元素都相等,则返回 true return lhs.first == rhs.first && lhs.second == rhs.second; } +// 比较两个 pair 对象的大小 template bool operator<(const pair& lhs, const pair& rhs) { + // 如果第一个元素小于 rhs 的第一个元素,或者第一个元素相等且第二个元素小于 rhs 的第二个元素,则返回 true return lhs.first < rhs.first || (lhs.first == rhs.first && lhs.second < rhs.second); } +// 比较两个 pair 对象是否不相等 template bool operator!=(const pair& lhs, const pair& rhs) { + // 如果两个 pair 对象不相等,则返回 true return !(lhs == rhs); } +// 比较两个 pair 对象的大小,反向比较 template bool operator>(const pair& lhs, const pair& rhs) { + // 如果 rhs 对象小于 lhs 对象,则返回 true return rhs < lhs; } +// 比较两个 pair 对象的大小,反向比较小于或等于 template bool operator<=(const pair& lhs, const pair& rhs) { + // 如果 rhs 对象小于 lhs 对象,则返回 false,否则返回 true return !(rhs < lhs); } +// 比较两个 pair 对象的大小,反向比较大于或等于 template bool operator>=(const pair& lhs, const pair& rhs) { + // 如果 lhs 对象小于 rhs 对象,则返回 false,否则返回 true return !(lhs < rhs); } -// 重载 mystl 的 swap -template -void swap(pair& lhs, pair& rhs) -{ - lhs.swap(rhs); -} - // 全局函数,让两个数据成为一个 pair template pair make_pair(Ty1&& first, Ty2&& second) diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/vector.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/vector.h old mode 100644 new mode 100755 index 5192761..ac1e7b9 --- a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/vector.h +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/vector.h @@ -70,58 +70,71 @@ private: public: // 构造、复制、移动、析构函数 - vector() noexcept +// 构造一个空的 vector 对象,不抛出异常 +vector() noexcept { try_init(); } - explicit vector(size_type n) +// 构造一个包含 n 个默认初始化元素的 vector 对象 +explicit vector(size_type n) { fill_init(n, value_type()); } - vector(size_type n, const value_type& value) +// 构造一个包含 n 个指定值 value 的 vector 对象 +vector(size_type n, const value_type& value) { fill_init(n, value); } - template ::value, int>::type = 0> - vector(Iter first, Iter last) - { - MYSTL_DEBUG(!(last < first)); - range_init(first, last); - } +// 模板构造函数,构造一个包含 [first, last) 范围内元素的 vector 对象 +// 要求 Iter 是输入迭代器 +template ::value, int>::type = 0> +vector(Iter first, Iter last) +{ + MYSTL_DEBUG(!(last < first)); // 确保 first 在 last 之前 + range_init(first, last); // 初始化范围 +} - vector(const vector& rhs) - { - range_init(rhs.begin_, rhs.end_); - } +// 拷贝构造函数,构造一个与 rhs 相等的 vector 对象 +vector(const vector& rhs) +{ + range_init(rhs.begin_, rhs.end_); // 使用范围初始化 +} - vector(vector&& rhs) noexcept - :begin_(rhs.begin_), - end_(rhs.end_), - cap_(rhs.cap_) - { - rhs.begin_ = nullptr; - rhs.end_ = nullptr; - rhs.cap_ = nullptr; - } +// 移动构造函数,构造一个与 rhs 相等的 vector 对象,不抛出异常 +vector(vector&& rhs) noexcept + :begin_(rhs.begin_), + end_(rhs.end_), + cap_(rhs.cap_) +{ + rhs.begin_ = nullptr; // 将 rhs 的资源置空 + rhs.end_ = nullptr; + rhs.cap_ = nullptr; +} - vector(std::initializer_list ilist) - { - range_init(ilist.begin(), ilist.end()); - } +// 构造一个包含 initializer_list 中元素的 vector 对象 +vector(std::initializer_list ilist) +{ + range_init(ilist.begin(), ilist.end()); // 使用范围初始化 +} - vector& operator=(const vector& rhs); - vector& operator=(vector&& rhs) noexcept; +// 拷贝赋值运算符,将 rhs 的内容赋值给当前 vector 对象 +vector& operator=(const vector& rhs); - vector& operator=(std::initializer_list ilist) - { - vector tmp(ilist.begin(), ilist.end()); - swap(tmp); - return *this; - } +// 移动赋值运算符,将 rhs 的内容移动到当前 vector 对象,不抛出异常 +vector& operator=(vector&& rhs) noexcept; - ~vector() - { - destroy_and_recover(begin_, end_, cap_ - begin_); - begin_ = end_ = cap_ = nullptr; - } +// 接受一个 initializer_list 并将其内容赋值给当前 vector 对象 +vector& operator=(std::initializer_list ilist) +{ + vector tmp(ilist.begin(), ilist.end()); // 创建临时 vector + swap(tmp); // 交换当前 vector 与临时 vector 的内容 + return *this; +} + +// 析构函数,释放 vector 对象占用的资源 +~vector() +{ + destroy_and_recover(begin_, end_, cap_ - begin_); // 销毁并回收元素 + begin_ = end_ = cap_ = nullptr; // 将指针置空 +} public: @@ -326,33 +339,49 @@ private: /*****************************************************************************************/ // 复制赋值操作符 + +// 拷贝赋值运算符,将另一个 vector 对象 rhs 的内容赋值给当前 vector 对象 template vector& vector::operator=(const vector& rhs) { + // 如果当前对象和 rhs 不是同一个对象,则继续赋值操作 if (this != &rhs) { + // 获取 rhs 的长度(元素数量) const auto len = rhs.size(); + + // 如果 rhs 的容量大于当前 vector 的容量,需要重新分配内存 if (len > capacity()) { + // 创建一个临时 vector 对象 tmp,包含 rhs 的所有元素 vector tmp(rhs.begin(), rhs.end()); + // 交换当前 vector 对象和临时 vector 对象的内容 swap(tmp); } - else if (size() >= len) + else if (size() >= len) // 如果当前 vector 的容量足够大 { + // 使用 mystl::copy 函数将 rhs 的元素复制到当前 vector 的开始位置 auto i = mystl::copy(rhs.begin(), rhs.end(), begin()); + // 销毁多余的元素 data_allocator::destroy(i, end_); + // 更新 end_ 指针的位置 end_ = begin_ + len; } - else + else // 如果当前 vector 的容量不足以容纳 rhs 的所有元素,但足以容纳当前的元素 { + // 将 rhs 的元素复制到当前 vector 的开始位置,覆盖现有的元素 mystl::copy(rhs.begin(), rhs.begin() + size(), begin_); + // 使用 uninitialized_copy 将 rhs 的剩余元素复制到当前 vector 的末尾 mystl::uninitialized_copy(rhs.begin() + size(), rhs.end(), end_); + // 更新容量和 end_ 指针的位置 cap_ = end_ = begin_ + len; } } + // 返回当前 vector 对象的引用 return *this; } + // 移动赋值操作符 template vector& vector::operator=(vector&& rhs) noexcept @@ -368,19 +397,29 @@ vector& vector::operator=(vector&& rhs) noexcept } // 预留空间大小,当原容量小于要求大小时,才会重新分配 +// vector::reserve 函数,调整 vector 的容量至少为 n,如果当前容量已经足够则不作任何操作 template void vector::reserve(size_type n) { + // 如果当前 vector 的容量小于 n,则需要扩容 if (capacity() < n) { + // 如果请求的容量超过了 vector 最大可能的容量,则抛出长度错误异常 THROW_LENGTH_ERROR_IF(n > max_size(), "n can not larger than max_size() in vector::reserve(n)"); + // 保存当前 vector 的大小(元素数量) const auto old_size = size(); + // 分配新的内存空间,容量为 n auto tmp = data_allocator::allocate(n); + // 将旧内存空间中的所有元素移动到新内存空间 mystl::uninitialized_move(begin_, end_, tmp); + // 释放旧的内存空间 data_allocator::deallocate(begin_, cap_ - begin_); + // 更新 vector 的开始指针为新的内存空间 begin_ = tmp; + // 更新 vector 的结束指针为新内存空间的末尾(不包括新分配的未使用空间) end_ = tmp + old_size; + // 更新 vector 的容量指针 cap_ = begin_ + n; } } @@ -466,32 +505,48 @@ void vector::pop_back() } // 在 pos 处插入元素 +// 在指定位置 pos 插入一个值 value 的副本 template typename vector::iterator vector::insert(const_iterator pos, const value_type& value) { + // 调试断言,确保 pos 在有效范围内 MYSTL_DEBUG(pos >= begin() && pos <= end()); + // 将 const_iterator 转换为 iterator iterator xpos = const_cast(pos); + // 计算 pos 到 begin() 的距离 const size_type n = pos - begin_; + // 如果 vector 未满且插入位置在末尾 if (end_ != cap_ && xpos == end_) { + // 在末尾就地构造新元素 data_allocator::construct(mystl::address_of(*end_), value); + // 移动 end_ 指针 ++end_; } else if (end_ != cap_) { + // 在非满的 vector 中插入元素 auto new_end = end_; + // 在末尾就地构造一个临时元素 data_allocator::construct(mystl::address_of(*end_), *(end_ - 1)); + // 移动末尾元素 ++new_end; - auto value_copy = value; // 避免元素因以下复制操作而被改变 + // 复制值以避免在复制过程中被覆盖 + auto value_copy = value; + // 从插入点开始,将元素向后复制 mystl::copy_backward(xpos, end_ - 1, end_); + // 插入新元素 *xpos = mystl::move(value_copy); + // 更新 end_ 指针 end_ = new_end; } else { + // 如果 vector 已满,需要重新分配内存并插入元素 reallocate_insert(xpos, value); } + // 返回插入元素的位置 return begin_ + n; } @@ -619,25 +674,32 @@ destroy_and_recover(iterator first, iterator last, size_type n) } // get_new_cap 函数 +// 计算 vector 需要的新容量 template typename vector::size_type -vector:: -get_new_cap(size_type add_size) +vector::get_new_cap(size_type add_size) { + // 获取当前 vector 的容量 const auto old_size = capacity(); + // 如果添加的元素数量使得新容量超过最大可能的容量,则抛出长度错误异常 THROW_LENGTH_ERROR_IF(old_size > max_size() - add_size, "vector's size too big"); + // 如果当前容量加上一半的容量或者添加的元素数量超过了最大容量减去16, + // 则直接计算新容量为当前容量加上添加的元素数量 if (old_size > max_size() - old_size / 2) { + // 计算新容量,确保不超过最大容量 return old_size + add_size > max_size() - 16 ? old_size + add_size : old_size + add_size + 16; } + // 如果当前容量为0,新容量至少为添加的元素数量或16(取较大者) + // 否则,新容量为当前容量的1.5倍和当前容量加上添加的元素数量中较大的一个 const size_type new_size = old_size == 0 ? mystl::max(add_size, static_cast(16)) : mystl::max(old_size + old_size / 2, old_size + add_size); + // 返回计算出的新容量 return new_size; } - // fill_assign 函数 template void vector:: @@ -681,29 +743,39 @@ copy_assign(IIter first, IIter last, input_iterator_tag) } // 用 [first, last) 为容器赋值 +// 使用 forward_iterator_tag 标记的迭代器从范围 [first, last) 复制并分配元素给当前 vector template template -void vector:: -copy_assign(FIter first, FIter last, forward_iterator_tag) +void vector::copy_assign(FIter first, FIter last, forward_iterator_tag) { + // 计算要复制的元素数量 const size_type len = mystl::distance(first, last); + // 如果要复制的元素数量大于当前 vector 的容量,则需要创建一个新的临时 vector if (len > capacity()) { + // 创建一个临时 vector 并交换内容 vector tmp(first, last); swap(tmp); } - else if (size() >= len) + else if (size() >= len) // 如果当前 vector 的大小足以容纳所有元素 { + // 使用 mystl::copy 将元素复制到 vector 的开始位置 auto new_end = mystl::copy(first, last, begin_); + // 销毁多余的元素 data_allocator::destroy(new_end, end_); + // 更新 end_ 指针 end_ = new_end; } - else + else // 如果当前 vector 的大小不足以容纳所有元素,但小于要复制的元素数量 { + // 计算 mid 指针,指向要复制的元素的中点 auto mid = first; mystl::advance(mid, size()); + // 将前 size() 个元素复制到 vector 的开始位置 mystl::copy(first, mid, begin_); + // 使用 uninitialized_copy 将剩余的元素复制到 vector 的末尾 auto new_end = mystl::uninitialized_copy(mid, last, end_); + // 更新 end_ 指针 end_ = new_end; } } @@ -736,26 +808,38 @@ reallocate_emplace(iterator pos, Args&& ...args) } // 重新分配空间并在 pos 处插入元素 +// 在指定位置 pos 插入值 value 时,如果需要,重新分配内存以插入元素 template void vector::reallocate_insert(iterator pos, const value_type& value) { + // 计算插入新元素后所需的新容量 const auto new_size = get_new_cap(1); + // 分配新的内存空间 auto new_begin = data_allocator::allocate(new_size); + // 初始化 new_end 指针为新内存空间的开始 auto new_end = new_begin; + // 复制 value 以避免在以下操作中被修改 const value_type& value_copy = value; try { + // 将 [begin_, pos) 区间的元素移动到新内存空间 new_end = mystl::uninitialized_move(begin_, pos, new_begin); + // 在新内存空间中 pos 对应的位置构造新元素 data_allocator::construct(mystl::address_of(*new_end), value_copy); + // 移动 new_end 指针 ++new_end; + // 将 [pos, end_) 区间的元素移动到新内存空间 new_end = mystl::uninitialized_move(pos, end_, new_end); } catch (...) { + // 如果发生异常,释放新分配的内存并重新抛出异常 data_allocator::deallocate(new_begin, new_size); throw; } + // 销毁旧内存空间中的元素并释放内存 destroy_and_recover(begin_, end_, cap_ - begin_); + // 更新 vector 的指针为新内存空间 begin_ = new_begin; end_ = new_end; cap_ = new_begin + new_size; From 4d5cdc804d29e9ea8e4cfc11a19302c0c241015e Mon Sep 17 00:00:00 2001 From: Shiina_cd Date: Mon, 16 Dec 2024 21:15:58 +0800 Subject: [PATCH 5/5] =?UTF-8?q?=E5=AF=B9queue.h=E5=81=9A=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MyTinySTL-master/MyTinySTL/queue.h | 705 +++++++++--------- 1 file changed, 356 insertions(+), 349 deletions(-) diff --git a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/queue.h b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/queue.h index 6a4a939..643539d 100644 --- a/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/queue.h +++ b/MyTinySTL/src/MyTinySTL-master/MyTinySTL-master/MyTinySTL/queue.h @@ -1,364 +1,371 @@ -#ifndef MYTINYSTL_QUEUE_H_ +#ifndef MYTINYSTL_QUEUE_H_ // 预处理指令,防止头文件被重复包含 #define MYTINYSTL_QUEUE_H_ // 这个头文件包含了两个模板类 queue 和 priority_queue // queue : 队列 // priority_queue : 优先队列 -#include "deque.h" -#include "vector.h" -#include "functional.h" -#include "heap_algo.h" +#include "deque.h" // 包含 deque 类的头文件 +#include "vector.h" // 包含 vector 类的头文件 +#include "functional.h" // 包含 functional 头文件,提供比较函数等 +#include "heap_algo.h" // 包含堆算法的头文件 -namespace mystl +namespace mystl // 命名空间 mystl,用于封装 mystl 库的组件 { -// 模板类 queue -// 参数一代表数据类型,参数二代表底层容器类型,缺省使用 mystl::deque 作为底层容器 -template > -class queue -{ -public: - typedef Container container_type; - // 使用底层容器的型别 - typedef typename Container::value_type value_type; - typedef typename Container::size_type size_type; - typedef typename Container::reference reference; - typedef typename Container::const_reference const_reference; - - static_assert(std::is_same::value, - "the value_type of Container should be same with T"); -private: - container_type c_; // 用底层容器表现 queue - -public: - // 构造、复制、移动函数 - - queue() = default; - - explicit queue(size_type n) - :c_(n) - { - } - queue(size_type n, const value_type& value) - :c_(n, value) - { - } - - template - queue(IIter first, IIter last) - :c_(first, last) - { - } - - queue(std::initializer_list ilist) - :c_(ilist.begin(), ilist.end()) - { - } - - queue(const Container& c) - :c_(c) - { - } - queue(Container&& c) noexcept(std::is_nothrow_move_constructible::value) - :c_(mystl::move(c)) - { - } - - queue(const queue& rhs) - :c_(rhs.c_) - { - } - queue(queue&& rhs) noexcept(std::is_nothrow_move_constructible::value) - :c_(mystl::move(rhs.c_)) - { - } - - queue& operator=(const queue& rhs) - { - c_ = rhs.c_; - return *this; - } - queue& operator=(queue&& rhs) noexcept(std::is_nothrow_move_assignable::value) - { - c_ = mystl::move(rhs.c_); - return *this; - } - - queue& operator=(std::initializer_list ilist) - { - c_ = ilist; - return *this; - } - - ~queue() = default; - - // 访问元素相关操作 - reference front() { return c_.front(); } - const_reference front() const { return c_.front(); } - reference back() { return c_.back(); } - const_reference back() const { return c_.back(); } - - // 容量相关操作 - bool empty() const noexcept { return c_.empty(); } - size_type size() const noexcept { return c_.size(); } - - // 修改容器相关操作 - template - void emplace(Args&& ...args) - { c_.emplace_back(mystl::forward(args)...); } - - void push(const value_type& value) - { c_.push_back(value); } - void push(value_type&& value) - { c_.emplace_back(mystl::move(value)); } - - void pop() - { c_.pop_front(); } - - void clear() - { - while (!empty()) - pop(); - } - - void swap(queue& rhs) noexcept(noexcept(mystl::swap(c_, rhs.c_))) - { mystl::swap(c_, rhs.c_); } - -public: - friend bool operator==(const queue& lhs, const queue& rhs) { return lhs.c_ == rhs.c_; } - friend bool operator< (const queue& lhs, const queue& rhs) { return lhs.c_ < rhs.c_; } -}; - -// 重载比较操作符 -template -bool operator==(const queue& lhs, const queue& rhs) -{ - return lhs == rhs; -} - -template -bool operator!=(const queue& lhs, const queue& rhs) -{ - return !(lhs == rhs); -} - -template -bool operator<(const queue& lhs, const queue& rhs) -{ - return lhs < rhs; -} - -template -bool operator>(const queue& lhs, const queue& rhs) -{ - return rhs < lhs; -} - -template -bool operator<=(const queue& lhs, const queue& rhs) -{ - return !(rhs < lhs); -} - -template -bool operator>=(const queue& lhs, const queue& rhs) -{ - return !(lhs < rhs); -} - -// 重载 mystl 的 swap -template -void swap(queue& lhs, queue& rhs) noexcept(noexcept(lhs.swap(rhs))) -{ - lhs.swap(rhs); -} - -/*****************************************************************************************/ + // 模板类 queue + // 参数一代表数据类型,参数二代表底层容器类型,缺省使用 mystl::deque 作为底层容器 + template > + class queue + { + public: + typedef Container container_type; // 使用底层容器的型别 + typedef typename Container::value_type value_type; // 值类型 + typedef typename Container::size_type size_type; // 大小类型 + typedef typename Container::reference reference; // 引用类型 + typedef typename Container::const_reference const_reference; // 常量引用类型 + + static_assert(std::is_same::value, // 静态断言,确保 T 和 value_type 是相同的类型 + "the value_type of Container should be same with T"); + + private: + container_type c_; // 用底层容器表现 queue + + public: + // 构造、复制、移动函数 + queue() = default; // 默认构造函数 + + explicit queue(size_type n) // 构造函数,初始化指定数量的元素 + :c_(n) + { + } + queue(size_type n, const value_type& value) // 构造函数,初始化指定数量的相同元素 + :c_(n, value) + { + } + + template + queue(IIter first, IIter last) // 构造函数,使用迭代器范围初始化 + : c_(first, last) + { + } + + queue(std::initializer_list ilist) // 构造函数,使用初始化列表初始化 + :c_(ilist.begin(), ilist.end()) + { + } + + queue(const Container& c) // 构造函数,使用底层容器初始化 + :c_(c) + { + } + queue(Container&& c) noexcept(std::is_nothrow_move_constructible::value) // 移动构造函数 + :c_(mystl::move(c)) + { + } + + queue(const queue& rhs) // 复制构造函数 + :c_(rhs.c_) + { + } + queue(queue&& rhs) noexcept(std::is_nothrow_move_constructible::value) // 移动构造函数 + :c_(mystl::move(rhs.c_)) + { + } + + queue& operator=(const queue& rhs) // 复制赋值运算符 + { + c_ = rhs.c_; + return *this; + } + queue& operator=(queue&& rhs) noexcept(std::is_nothrow_move_assignable::value) // 移动赋值运算符 + { + c_ = mystl::move(rhs.c_); + return *this; + } + + queue& operator=(std::initializer_list ilist) // 初始化列表赋值运算符 + { + c_ = ilist; + return *this; + } + + ~queue() = default; // 默认析构函数 + + // 访问元素相关操作 + reference front() { return c_.front(); } // 返回队头元素的引用 + const_reference front() const { return c_.front(); } // 返回队头元素的常量引用 + reference back() { return c_.back(); } // 返回队尾元素的引用 + const_reference back() const { return c_.back(); } // 返回队尾元素的常量引用 + + // 容量相关操作 + bool empty() const noexcept { return c_.empty(); } // 检查队列是否为空 + size_type size() const noexcept { return c_.size(); } // 返回队列的大小 + + // 修改容器相关操作 + template + void emplace(Args&& ...args) // 原地构造并添加元素到队尾 + { + c_.emplace_back(mystl::forward(args)...); + } + + void push(const value_type& value) // 将元素添加到队尾 + { + c_.push_back(value); + } + void push(value_type&& value) // 将移动构造的元素添加到队尾 + { + c_.emplace_back(mystl::move(value)); + } + + void pop() // 移除队头元素 + { + c_.pop_front(); + } + + void clear() // 清空队列 + { + while (!empty()) + pop(); + } + + void swap(queue& rhs) noexcept(noexcept(mystl::swap(c_, rhs.c_))) // 交换两个队列的内容 + { + mystl::swap(c_, rhs.c_); + } + + public: + friend bool operator==(const queue& lhs, const queue& rhs) // 比较运算符,检查两个队列是否相等 + { + return lhs.c_ == rhs.c_; + } + friend bool operator< (const queue& lhs, const queue& rhs) // 比较运算符,检查一个队列是否小于另一个队列 + { + return lhs.c_ < rhs.c_; + } + }; + + // 重载比较操作符 + template + bool operator==(const queue& lhs, const queue& rhs) + { + return lhs == rhs; + } + + template + bool operator!=(const queue& lhs, const queue& rhs) + { + return !(lhs == rhs); + } + + template + bool operator<(const queue& lhs, const queue& rhs) + { + return lhs < rhs; + } + + template + bool operator>(const queue& lhs, const queue& rhs) + { + return rhs < lhs; + } + + template + bool operator<=(const queue& lhs, const queue& rhs) + { + return !(rhs < lhs); + } + + template + bool operator>=(const queue& lhs, const queue& rhs) + { + return !(lhs < rhs); + } + + // 重载 mystl 的 swap + template + void swap(queue& lhs, queue& rhs) noexcept(noexcept(lhs.swap(rhs))) + { + lhs.swap(rhs); + } + /*****************************************************************************************/ // 模板类 priority_queue // 参数一代表数据类型,参数二代表容器类型,缺省使用 mystl::vector 作为底层容器 // 参数三代表比较权值的方式,缺省使用 mystl::less 作为比较方式 -template , - class Compare = mystl::less> -class priority_queue -{ -public: - typedef Container container_type; - typedef Compare value_compare; - // 使用底层容器的型别 - typedef typename Container::value_type value_type; - typedef typename Container::size_type size_type; - typedef typename Container::reference reference; - typedef typename Container::const_reference const_reference; - - static_assert(std::is_same::value, - "the value_type of Container should be same with T"); - -private: - container_type c_; // 用底层容器来表现 priority_queue - value_compare comp_; // 权值比较的标准 - -public: - // 构造、复制、移动函数 - priority_queue() = default; - - priority_queue(const Compare& c) - :c_(), comp_(c) - { - } - - explicit priority_queue(size_type n) - :c_(n) - { - mystl::make_heap(c_.begin(), c_.end(), comp_); - } - priority_queue(size_type n, const value_type& value) - :c_(n, value) - { - mystl::make_heap(c_.begin(), c_.end(), comp_); - } - - template - priority_queue(IIter first, IIter last) - :c_(first, last) - { - mystl::make_heap(c_.begin(), c_.end(), comp_); - } - - priority_queue(std::initializer_list ilist) - :c_(ilist) - { - mystl::make_heap(c_.begin(), c_.end(), comp_); - } - - priority_queue(const Container& s) - :c_(s) - { - mystl::make_heap(c_.begin(), c_.end(), comp_); - } - priority_queue(Container&& s) - :c_(mystl::move(s)) - { - mystl::make_heap(c_.begin(), c_.end(), comp_); - } - - priority_queue(const priority_queue& rhs) - :c_(rhs.c_), comp_(rhs.comp_) - { - mystl::make_heap(c_.begin(), c_.end(), comp_); - } - priority_queue(priority_queue&& rhs) - :c_(mystl::move(rhs.c_)), comp_(rhs.comp_) - { - mystl::make_heap(c_.begin(), c_.end(), comp_); - } - - priority_queue& operator=(const priority_queue& rhs) - { - c_ = rhs.c_; - comp_ = rhs.comp_; - mystl::make_heap(c_.begin(), c_.end(), comp_); - return *this; - } - priority_queue& operator=(priority_queue&& rhs) - { - c_ = mystl::move(rhs.c_); - comp_ = rhs.comp_; - mystl::make_heap(c_.begin(), c_.end(), comp_); - return *this; - } - priority_queue& operator=(std::initializer_list ilist) - { - c_ = ilist; - comp_ = value_compare(); - mystl::make_heap(c_.begin(), c_.end(), comp_); - return *this; - } - - ~priority_queue() = default; - -public: - - // 访问元素相关操作 - const_reference top() const { return c_.front(); } - - // 容量相关操作 - bool empty() const noexcept { return c_.empty(); } - size_type size() const noexcept { return c_.size(); } - - // 修改容器相关操作 - template - void emplace(Args&& ...args) - { - c_.emplace_back(mystl::forward(args)...); - mystl::push_heap(c_.begin(), c_.end(), comp_); - } - - void push(const value_type& value) - { - c_.push_back(value); - mystl::push_heap(c_.begin(), c_.end(), comp_); - } - void push(value_type&& value) - { - c_.push_back(mystl::move(value)); - mystl::push_heap(c_.begin(), c_.end(), comp_); - } - - void pop() - { - mystl::pop_heap(c_.begin(), c_.end(), comp_); - c_.pop_back(); - } - - void clear() - { - while (!empty()) - pop(); - } - - void swap(priority_queue& rhs) noexcept(noexcept(mystl::swap(c_, rhs.c_)) && - noexcept(mystl::swap(comp_, rhs.comp_))) - { - mystl::swap(c_, rhs.c_); - mystl::swap(comp_, rhs.comp_); - } - -public: - friend bool operator==(const priority_queue& lhs, const priority_queue& rhs) - { - return lhs.c_ == rhs.c_; - } - friend bool operator!=(const priority_queue& lhs, const priority_queue& rhs) - { - return lhs.c_ != rhs.c_; - } -}; - -// 重载比较操作符 -template -bool operator==(priority_queue& lhs, - priority_queue& rhs) -{ - return lhs == rhs; -} - -template -bool operator!=(priority_queue& lhs, - priority_queue& rhs) -{ - return lhs != rhs; -} - -// 重载 mystl 的 swap -template -void swap(priority_queue& lhs, - priority_queue& rhs) noexcept(noexcept(lhs.swap(rhs))) -{ - lhs.swap(rhs); -} + template , + class Compare = mystl::less> + class priority_queue + { + public: + typedef Container container_type; // 使用底层容器的型别 + typedef Compare value_compare; // 用于比较的函数对象类型 + typedef typename Container::value_type value_type; // 值类型 + typedef typename Container::size_type size_type; // 大小类型 + typedef typename Container::reference reference; // 引用类型 + typedef typename Container::const_reference const_reference; // 常量引用类型 + + static_assert(std::is_same::value, // 静态断言,确保 T 和 value_type 是相同的类型 + "the value_type of Container should be same with T"); + + private: + container_type c_; // 用底层容器来表现 priority_queue + value_compare comp_; // 权值比较的标准 + + public: + // 构造、复制、移动函数 + priority_queue() = default; // 默认构造函数 + + priority_queue(const Compare& comp) // 构造函数,指定比较函数 + :c_(), comp_(comp) + { + } + + explicit priority_queue(size_type n) // 构造函数,初始化指定数量的元素 + :c_(n) + { + mystl::make_heap(c_.begin(), c_.end(), comp_); // 构建为堆 + } + priority_queue(size_type n, const value_type& value) // 构造函数,初始化指定数量的相同元素 + :c_(n, value) + { + mystl::make_heap(c_.begin(), c_.end(), comp_); // 构建为堆 + } + + template + priority_queue(IIter first, IIter last) // 构造函数,使用迭代器范围初始化 + : c_(first, last) + { + mystl::make_heap(c_.begin(), c_.end(), comp_); // 构建为堆 + } + + priority_queue(std::initializer_list ilist) // 构造函数,使用初始化列表初始化 + :c_(ilist) + { + mystl::make_heap(c_.begin(), c_.end(), comp_); // 构建为堆 + } + + priority_queue(const Container& s) // 构造函数,使用底层容器初始化 + :c_(s) + { + mystl::make_heap(c_.begin(), c_.end(), comp_); // 构建为堆 + } + priority_queue(Container&& s) // 移动构造函数 + :c_(mystl::move(s)) + { + mystl::make_heap(c_.begin(), c_.end(), comp_); // 构建为堆 + } + + priority_queue(const priority_queue& rhs) // 复制构造函数 + :c_(rhs.c_), comp_(rhs.comp_) + { + mystl::make_heap(c_.begin(), c_.end(), comp_); // 构建为堆 + } + priority_queue(priority_queue&& rhs) // 移动构造函数 + :c_(mystl::move(rhs.c_)), comp_(rhs.comp_) + { + mystl::make_heap(c_.begin(), c_.end(), comp_); // 构建为堆 + } + + priority_queue& operator=(const priority_queue& rhs) // 复制赋值运算符 + { + c_ = rhs.c_; + comp_ = rhs.comp_; + mystl::make_heap(c_.begin(), c_.end(), comp_); + return *this; + } + priority_queue& operator=(priority_queue&& rhs) // 移动赋值运算符 + { + c_ = mystl::move(rhs.c_); + comp_ = rhs.comp_; + mystl::make_heap(c_.begin(), c_.end(), comp_); + return *this; + } + priority_queue& operator=(std::initializer_list ilist) // 初始化列表赋值运算符 + { + c_ = ilist; + comp_ = value_compare(); + mystl::make_heap(c_.begin(), c_.end(), comp_); + return *this; + } + + ~priority_queue() = default; // 默认析构函数 + + // 访问元素相关操作 + const_reference top() const { return c_.front(); } // 返回堆顶元素的常量引用 + + // 容量相关操作 + bool empty() const noexcept { return c_.empty(); } // 检查优先队列是否为空 + size_type size() const noexcept { return c_.size(); } // 返回优先队列的大小 + + // 修改容器相关操作 + template + void emplace(Args&& ...args) // 原地构造并添加元素到优先队列 + { + c_.emplace_back(mystl::forward(args)...); + mystl::push_heap(c_.begin(), c_.end(), comp_); // 维护堆的性质 + } + + void push(const value_type& value) // 将元素添加到优先队列 + { + c_.push_back(value); + mystl::push_heap(c_.begin(), c_.end(), comp_); // 维护堆的性质 + } + void push(value_type&& value) // 将移动构造的元素添加到优先队列 + { + c_.push_back(mystl::move(value)); + mystl::push_heap(c_.begin(), c_.end(), comp_); // 维护堆的性质 + } + + void pop() // 移除堆顶元素 + { + mystl::pop_heap(c_.begin(), c_.end(), comp_); // 维护堆的性质 + c_.pop_back(); + } + + void clear() // 清空优先队列 + { + while (!empty()) + pop(); + } + + void swap(priority_queue& rhs) noexcept(noexcept(mystl::swap(c_, rhs.c_)) && + noexcept(mystl::swap(comp_, rhs.comp_))) + { + mystl::swap(c_, rhs.c_); + mystl::swap(comp_, rhs.comp_); // 交换比较函数对象 + } + + public: + friend bool operator==(const priority_queue& lhs, const priority_queue& rhs) // 比较运算符,检查两个优先队列是否相等 + { + return lhs.c_ == rhs.c_; + } + friend bool operator!=(const priority_queue& lhs, const priority_queue& rhs) // 比较运算符,检查两个优先队列是否不相等 + { + return lhs.c_ != rhs.c_; + } + }; + + // 重载比较操作符 + template + bool operator==(priority_queue& lhs, priority_queue& rhs) + { + return lhs == rhs; + } + + template + bool operator!=(priority_queue& lhs, priority_queue& rhs) + { + return lhs != rhs; + } + + // 重载 mystl 的 swap + template + void swap(priority_queue& lhs, priority_queue& rhs) noexcept(noexcept(lhs.swap(rhs))) + { + lhs.swap(rhs); + } } // namespace mystl -#endif // !MYTINYSTL_QUEUE_H_ - +#endif // !MYTINYSTL_QUEUE_H_ \ No newline at end of file