From a96e155a71a1d03b976d73d9c0020eceb3d79ad4 Mon Sep 17 00:00:00 2001 From: Trevor Welsby Date: Sun, 17 Jan 2016 19:24:54 +1000 Subject: [PATCH] Fully support int64_t/uint64_t numbers, add unsigned type --- doc/doxygen_sqlite3.db | Bin 0 -> 81920 bytes src/json.hpp | 1537 ++++++++++++++++++---------------------- src/json.hpp.re2c | 382 ++++++++-- test/unit.cpp | 1247 ++++++++++++++++++++++++-------- 4 files changed, 1998 insertions(+), 1168 deletions(-) create mode 100644 doc/doxygen_sqlite3.db diff --git a/doc/doxygen_sqlite3.db b/doc/doxygen_sqlite3.db new file mode 100644 index 0000000000000000000000000000000000000000..b0b9b32d64b3c62b0f995c3f1ada95fc20b3bce4 GIT binary patch literal 81920 zcmeIb349#Kbtl|iP0S3)fp`-H&mo5wNPy^`nVy691(6hQ5~N5`6x7q*LqY@r2pEu} zPB$grM`FiuWIK)>uj4q0^Epm7jyK1~j-9NNIHxyR$2puk-c6j(PGaYd_g_~}_w*bP zC1qtB_>t3HRj;aEy{cDLUGLR<=gu4-sk*7k_~Z?%n#wA36jfFBrBaHbsQ7;x|K(p2 zFLPu7PnzEDPgVN=GTs3wP5UZ^U9A19_I3W+F6(UiECpsM@N!V#9?HqdPW;SEbm4c2 zc3jc^QTto%FSI|@TgmI4ha z5MR=vBvh3wi!bIcOXG|9%aZs){<1i}fWIt?&*v`-g@bck-8c@dSUF8^`iWEA5QO_)8+*!C&I>Is7FS*Z50EobZ=9ah1PlUD}(KgjP|s zC$zU}f31C1`-1if?S~LC`!`F0Sqi*F6j+?lwy7gyWA5abb;F&SuxxjVEKs#HvBz&r zj8Bg_j$2XQp?#k+XCBdd$b>a%-I!87jOynJ6qd%desaUTQFbQ*J1ii6XKqaECXY?J zl_}+o$vN6;)MAfLJMPqy`5oFi!s@g~t*I&H{fjjqQMRUBStoMobZFVtXcepxfjZ~)+ zi%HK^b#i3vYUd)datg1mbtAEm^kA(WpS<0%fGoaYO(f=%p3#vTfS-F0S&b93NeiXU z?ZW#w&(fJBD@Vp}SYsm-i{_F3k+G5Lh&4L$xH~yKIx~kT zd#dV;jK>qC+s4t`waz$MX^%{e=X3ea7+$etyOY&;2kEvZC#~D_=8(14=+*Jbk?OS@ zb2YO1k*V>q?bjwIa)dlOaAT}G;8;~_;Lx}|eZw8AP7RzJpPsbcfwS(!_|yOe9+;Z6 z*$d4TS4sEfb3@0k%tb#gBcD;Q>;FgX2efx<-=RH=@BJ}tSi4W#1K!`D{e;$|E!1M< zU&#MYzDPa?;Mu=f3cSK7FjwnQIjb+5r>#^4uP>dirPTnlFQH(Z+ZR(X!S0J_H0Sq) zac!{*hF?IVILFUV(rvY1`FmJE@O&37Loj`EiPn$JcbMzv-J`8jYivK47Rvd)vs3F< z8RI8tA%gSc?47fIj6yKp@95Ijsy_42p%_T+*Yet<>I-LolF+(48UNG$e@y#R+M9cW z`~O#1_s*g-OMzJm+${xiw~@2Y#!vbre%8}3fmQ49vvL6;Ushs-ek3SaZ8P~d@+qA6 zpWzWSa`tbQ0(VJ)-IY1sDU}^Qjg5|9!`66g*cdi&0ySa}57QNF*vjjco-^`!+sI_} zLdGf^hHF(y#hmGsY{zhhjkX{Qf!?}}+9}m4l`0vxkT>;A$u$kf(JPgTZWIwwDP>&O zTCIIpnICSuS^PTdK!3b+)K~@ zLRvkqOl)Vdnx()j1zrXUQ2tLSuTqp(sk(ZHY$vzL2gu)Rsh6RuhDCb)YP@^(YV}Tk z)hds=QhF($JPq5TJr52j>nYRlyKtq~`6^yJXs;lZ=1(`S#K*njp?>e%3= z)c*5Br;eUPwiAOVhf*g`;s5#L$NN&FW{qZoz(dymeEb$55;1daApWn|QyVm}=r{8&_qHIQcy zc8?@{Z*NDedv~|0jEp(%V}dx=bakAChgliJ27AO##A4k&J?br1E5m<^|Hec0@;K0> z*20E0Z;Qve_x3canU^wb@Mpril8DnLKik7!eJe!Mf@y>_ko#)GVjeH{z`Wp1de z{ph>s?&kg0xZ9faS|1x4Vcu-Ou64dy{W2^kT;?Pshc`ooLee-Dinxwx&d(2KE{{96gACnABS6pqd1;Ir$mO_I z3sV3zhovct7e6~M;HP*LKZV`+$?NzrH{(ZNg`a^1bp6-Vb&9%<^lA$b znEeY=;7-Tfcy~IjK6{2O3sQFyOKae@E3`uhB;3UwA-e7EW2?nXw(O1e1x>e#!9}?C zq10r{(d#+$;`Gbs&NGY-b$X})e;DR37QpzHr!?bm3|J#zi`@Be&`C)`D` zvsq>-FiU~|2Nc-qEkdom)A&h^;%Ds%{H&p${;LiAEZ>Nq?v?miwirK4aS55~|9lO< z%6{-ad!d2ZzgY^*Qs7&c0$aSjXxwI(pZ|SPAJsnb6syr$T=aCa*E`S^r}F(f!wg4$vz`Ag3}M9M?gA033Q=cyy6R4G z30X}J>bUl(j}n!aj@3f!?hVg?gqx62(xb+{hT^qe&%7tz-QO>@ID8?oxTs$rUKDCr zed=8_5vROdk<34Uh(W+^aBfp1z0EGBc5jf?37#x0Cg zp*!TPR_7=KtNloM6GJ}f`afS?q`>yiZ^FvgO7b=GJLJQ}BbP~1{YiC9J+Bs!{B87? zo)61t`&omT8eZxkOte6=1zIDg%8%eS`4F^dR^0=je)R~$ z^q!xGV$Ln4#moSnmNo;hExjk^qS(RBn}K@Oy)iLrRoz`Fx>m9^@qB7eiV<2$P=M89$>a^4D6Rl1^eCK=C#R|PntMmbEk;9Ud>Sy zX_0=8sY20Y)&#B@b#4xzuC84Rs7B=I^GUOP`}Y0Nr}F7T@9Q(#$QM>9zn%P$hC-iN zw@z8zrqI-drWMqNVeO4ofqTn61m&+@im{<{H|G>-a-z)`QSrk~m7~__HtzxdFmaGC3@_xx-D;EJ~TVOtBn|CoCZ&`@M z!9Zf88J$hs-uMC-#CY~Rs+#XJNs93nSP8S$@JMAB506X@vzdQ#8a6$U5|}CFTCiis zb@%o#<+U0s2avBZZw)ZDXU7h<7^JK*x_a-}5v`}T7PKuE6T*b+Fckcfp*%cRr6G!# zPWeB9$p|a`pt@Q42jw@Ehm;&5=-<+nAlzC;I67@&24zdtmK9CuS(`{1J;!@MPVer> z$tU6AYF~h4f#M~h!p%u92WpKM?^<4?8$kC5#)F&=(X&(~cDO1!ffH^kI%L%{WC^bK z5|TA@^HQW93=~)!VEzbYfUlmv1O#~lot;~ZuQ6!j%f6q&1imXk0l&OJ-`55N#av!2 z^*fvnr59Hu8|cF?L&1~oO?Pq%TqUe)yyQ5)q!oxc@w4rl25yj`OY--iZwnCT6G z-x*-wF}775o))`MHtl&@n$BiVq1e{UyG3>zXWk)yiefW+FXhKN{su^-MxPh_>}4v7xP7@TrSvl!K&!6bD-;bE}t<^aVWUaIBK!!W2T;EyJvXZP}H4(adBl24xr-E8`Sl^C6ovT`Qlf6bv_0qIkGD+srH# zP-ew)vyM}=Ts@P|mnyDyp2lMa7tyPkSUtwN~w~w4KrVHb0s@-4~Mc13ym~#MJtO&fxtP})a{B{E|zkY zoWX5J7>=u#3Z`2$GIlZR7IKaO!e?DW&u1&ytU1og${0DTXlF7Gvnr7_^M!J;SjuK> zy^zc1?Gm?!kwHV8l2O)+I?b*d8N)>VK-?_aPRUW;#0x9BhMNV|D<%kH7Al67LB3)o zj}WYPOmisoUC4hR#-OYm_P(>H^I`op2HHwZ-GdQ51UMLpyoL(s91~_6?2{9N>CeXL@dbw;D zb*JR!j7%{D9F*7d!Ym72;Q-SLQms?&8{Rk6i8v_>>NgvOH#eBJxx14e%S1ji3Y|+gY0hh^^P;5r8&=n2*e;DRLl^e?2m7iAr zM2)Nc>RI(M_50LcRR5YRBn5JXJWGCv{08}&w$kVS-wX1;!Yi}D>ba6pDWaKXHkUE; z85?|3aI@6JOQD-%UeMj7&8w_8KrWr>}1Tct~|>M!wAJR1nzN*Imay) za|VVeW{gZ8-3zlTXE_uoS1^j0l3W+O zylq)#HiOQ0i)PkARD~Cn2azj9$1I>}IRm4j2wN^zAx~!yH=Cc}P^CgPV}W-w#e!7; zr`fh;lq|d#a;T!TinY&vOr?gA)6HE1DhEymvzAO3 z)1M8R*$zgjQF1H5FmH3HO2Kq;c_WuC+j+N)Ij2;?TyCKQFt@wqV+<;<+g7%e*E7X( z(J2*-9AFLItzbwNOskSVz@acn&^mLad<8S1Qz*Nbe=rrQ006vgJF&t#jRBGcm=m$(3qB`nPU`ZDd0yU&%Q+tjJh4bQcXPm5RD$ zI=Y>AF#Y6B<<)fmzW`^Y+V5*WqrF3WRGUZslDvvsR==kHruv9FsC*G~!Vo)5r3{~5 zKu%ftHhtyH*Su5gs76W|B6gqbT-nge8FWr1legVmq3o1PR?f)6VpGmCOR)RY4kUdK zP%+x9p-xv@R4N#~jEmLkY6|tW(Gmh(Ywnqgka<24ZGlQP4RIqm`Vv_G@i%KSoZ4q`+MYB*S(>;xuD`#vMYf!;5u`LBE?Lg9VfJ(7a zC}6u>#)M~=3RbCz-YQ#0hR%wZPm5^{Ky(4a8e(TKk7L@wt_{0f+G4AO&1R*thLFKl zT$WZ*NW0aF^8Z5RwTkvGZCaa8{tx*@GE8=mrRrDIUsXS-dg_Br{`X;kyqtgOb-)!9 zJ*HSXr#sl*R*HFpE+{s((O4HP+jLTGJ17gwY_5UDqllFi+vsfGEjieTXR%2w7c9!m z?Lg9NfeJP<`9c8`xef-zw42Mi6|5kxV`S+z)l9De5E!E6elEQlK<$jurB?ySY_kza zucSC-jVwm5UdFPIT@coP!@_4z9upO;+?Cz*3IMg+;-`B6gzpI_SIA(yl>?#5dVy{V zv2KGO%9V_fO)m#f0bdXJ&?wvZT*ESI<9h=PSfT4>IiGVg>23h!+HCopWo^66FbgHh z5crhCzTGUs+MR=qoLj^?Q^bcPx~v^YdMQw8_c54W0-y@^<=EJ`cFx513Ev#Lsh1tY z27l3|z3eP*i!V0hx^7^_z+#K(sE{jTr7qz^4j+$Z!G&o*s~t#s5m2GK@>Y8WXJK1Z zUIOchl>d{;n-ua#i!y^-ic$V3Kh3EI=b`gmj}b_T(Yic z|D2K)LuDfqu+UT8)wD6PFgz*#+j>ETGn8z8vm!@qJ|d|t05$_83pW9D+P;|<7l5e8 zBY3C__&aMifv(S)sJ_LyTVwh~Ph_K~ioxpqQ@0tPUe@OhAAqi7Xn_PR&rlnb(d-Dc z9+aJdGX7WRE83v8U0Y7RPJWO4Jozu=HKdPpLI0=DTq^6xZ{;5^y&D7O4%J7Q!GK}B z;7;yJou*8|RZ#q45Ip5)=fwdDG3#1pCdTCq)u0gCJ$_-~liUltfTV|+?L{LQE_d}# z%7CnY{mCcLw2M1vwRD1RL7SkY(WlP^s^&D*yg@5VsF>bQ2}~1yo)twTuI-`wRR7$a zS_vDg_8ZF!NL$xUGu9S`@#-~qa%CPVo9j|in>Mk;lu7GjiM+^K<`jomk^{s_HsOm^ z2&xCwrCA!w@`>2W$mCSjD`x1Zxe6>=P)1HOTq-2;2LyOE92$#p$59hk2$)$3tYuNr zYPie!_kUg?-ymNiKSkb4o+GyUuj&`nkEzcqzomRkd0u%^8CLR?!nME6CqM@-@b(8v zROWjNW?BQJTuu zflw-Zop^_i(7vF?l3zey1ZsFuJu;JWX4EgM4x@!xMscq65^CrAdy%@4ZI$@=wV~gY z+KNMSYkIUgjFoTNT{{SvwG75*r4T^n5M}3sGb0qLfv8?+x&%jRU&=4N$!xXuAQ0KM zcs{y|H^t9@0Wx-Z>`Ko80IXZAPyl9LY-r1-UZf#u*?uIYna&y;{CxO~jScKW{5duN zc$OB!FtrI~E!~R@b$dh%LGS53Ai}d#t%)$hIgQTvK~T=7erp2*OKOia6wtRVhED^L z9jH%&#-+=hS(N|RLR7AO34VV+qCKfS3@w0-@bmS1u!^4rqaZiEW+?l7XzO*v7`>D$d5=vC**X=Y z+S8Mhn9m_IrPI2;=@AM`*S7|+9AQ1a30o*!zrBT4q&HKb847S}Ko`5D#wfhXgG{pJ1#oIc5kk{LX&Dt zR!f?^HnsA>W{IQMrg|V&1rID@o?dT6qdq4|MomiL@S7EagzmYZnOs#8eX7C_Q(Hqfdr zJBie_EHxC5*$?u+qYD0wgO`6s`BOEaZdZrY$JO_#zoh;RSwxEDA?yl%nEWRBy0!|l z!!_+K+J6np|4|5&O5nge4{=t$l%8Xzmh+YICx*oI}CYLM~f` zU=+u*de+fPC5Tj97t%#L5AotoCgCU)A)u+?)I0-ObP;lsf>WtjS;!we_pYC(ilW^xyZ_HllfrGlnm4poK- z7g9LLl}(7K3lIY0gbyOejE-~Piglesxw-)WOOc0$RY8{RLpGA%0Q>UhJ`fdBLR^p^9S%nskcwMn7e|!P>422qC}qv<94coP ztg?-RN(cc#$Bap(d*}ox1mqy_84^&C;X+~u4Fjqf0O4G|h_lH|sg%jNK(v=b<#A+& zQ`xKq5kNj$E>#MUFXEIu2c3e7RnR$90SW;IP{%25rJRABx0JOVi0&bcb#RcmgG04B zgrCEpN|2dXpv_`I69Cd&9MfmYpp^^X91z6n?gm%saViQqb{+}=nL;6BLzDxd zbSB54paPMDJUfH#EMst@tIJS3$P^)Vgrb0TuY^LE6mY0sa7`QXbMyriG%%PT`GgGa zHr@X(S4#Z+|FpIZe*XRhCxNdg4%tgqFe%`V;7rg`cd6aV-zmSQd`Ni~8p0(dUBVeA z7^$VqIb8&h1<^4?S$POHz{`1vpP_tU7cI)Fj#LW zppt{Ww{SoW@pcZH1QL-S^@h?0fFO^DmJm83 z2SFU95%BH;Au4os3Y7JoLRtqI} zaJUX(DWn4!u2AR5Kn(z~>8${QzC=r*e7YAvm~&fB0>&0{y_Lv|%9;5h>@U&j%_tXo z5-q33^d?$)n>jDNkv5}^+&#SkKt>y#t#ledxi+df&ic0J{}srnFt=eA%IC4#mY~c5 zMJ4Dm;axoFQ|r^RQ^i& z1?4@;V*qXUmp+NsRV?Ub*m@R!WeAC=;2L@)Ik0U7nij=E`UHU5&8_L<0Lo`t>wKh- z0my8lijuw$K;;r9A}3z&n8IV|uP>FJ{sC&~zr?HUCrq?MsMhD}5X z`iptn*7FdFr;kveHq(9jFn}OrYpME{zL%ENW*YZ82DLj2TaNj*B4-SPc2a2zQxcRf zOK7AG-4iHLLJbLORXGU#ppsE`(uaU-q0P=GeGou&0)QeF^a`;V1G%Zb0cL&!3sA`} zxyAGW0JT#JO790yxdd?Cc{n~+~_W+e_8^y!)ZVJ>!hcUeiKxP{)t@KU+LCV;2 zgPh(0pkkY?5Z(VT$JSqYhw`&8VDFC%clF2i><)$m^e?dE!CnX&CC~!2pf09EEewiX z6<2u;-@CNo#G?`l+L2HRtw321Vt(D$G1ruBsD~D)OSUHjRBPRj7>9y_Z64Z~&;Y~o z1|2ZSbMd)hK-U&qTHAVvLsg(X35^pITT44%sT84UiXAGpYZeA)zB0w2+R50tJGpin z1A~{sSnglAy)jL(@$ z9@@0oYaFT#v+oyBtu>qGa;P@i8*2qr>*e4+4h2;Ks6{}x8B-2)ymZ5Ywhok2p-2i{ zZKEuqN;znEV;pAjy$Ee0FuDzWB`7?W@XdOTK|zr-i?s%tjd+2A2~-wLDDTlJ)^aeU zp5#!_+Jky2lqlU2RxAKR5nk7eMSM0w6SjDnLzST?fe%`I|4{vUC^ldVoyF&YUZ6X$ z{0M_;r$eOC^?$GO9g6n%+Fxk@OZ#PL0sg4=UhD*(g+9<#?UHs(+pP^~>$JsM2l+?x zzsc{DUxS43qmU7PH+e0*1zm@B@F}vNWXVR-O*$bv__F#%^|#bdL3;Ru>O0jps!yro z_Nv;v0%}9HDawdqgOW(A?y55n8vN%>QDtTZGo8$o&76TqZ(mmXUkBU0x#T?}w3Lw8 z_awVyXc-M9MQBL}>G;>=JQ*T1G*^TcEhZh$B|AlE!9vn;G?@^gd*+ilUrxqFDA`5k z{Aw~LLUZSlId_sBB9!PPbM__Yh)^s}=5!=A5t`FMv|mUP5z>I?GxOBA(n)y?f%`fC zzd_OdPWyB1ceT%GKdpUO`#$YE;RU#g8-W+K`?Ouq3`l8K{RO_!rdw3jM+7)iQzL-~sGr^^3Seo6T$oF}|fc?0GDuBYP)qzt4}d3G@&|J3!A4BlBt$k)4`ltFJk zA^*_zgbco_i;%xdJ}w&g%;RLmj^u3-dg^JiBA0wjgq}oNU-Fg+J%P~bRz&FP7SjEWq$@%dr2Smd5g`|$_aHKMG?BNkjyoc_lwYZga(oqL}+L}ncJH@FGA-KN+*Xz=xi66 zyE=JJgw7z;ojfZ-r{|Hm3zKI==oCWplBY%JWG9*1kvt_rCpt;zHEuxnIy{doJ&-&iLiZvxl{_p$hX%>A zXOj1d&_P0$E=vxI&;f*!$wMNve=k|`mE=JY+K14Wk_SX+4?@41+%H4(XlS1Z?Zy)O z0m}cb@_9x3C+#bc0sgV}dDsE^jP?ob#vUGRIfp zKGKAG4fDuF+)X^9?o*5KSGYw@sms*`kXR_nKVeS!lJduB3j2$>bFh*4#=|j3JZ<(I zj+NQ-O3Y%<2V)P5@URF!B*Irj_(2iAEW!`4=R>he?AaB&D4zF=_zUcLC3c=YAB+u& z_;c*p6+0`QXGHvI_Pi21#hwqwPO|6a*a`N0Aa5Ho(E!^#dDL0-zc6N*mG|zEuQN|{5tVWiTJhRxrRN9vDNHZ zh^=DJd~79qnz0q^nTz$XXEwH+J@r^Odk(~wvFG;KQugeREn&~T*kbnF7F)!gTVe~@ zb8~C~dv1u$XV3Mqd)RYrtcyL@#FFf}GB%GrSH$MBXLqcVJ(tB2?71`+XU|2k7<(>^ zb+G3>u{rG771P)=8H0^5@Ws3s%!1J;<^Kop>3>)Jzgb(OE!C2mM*f9-72N+t^1Jvt z_%!)x@cswM_ma1P^PeVF>=7P@7Qu0H09?Nv`-BzX`I!1|>feFm|499x>aT#`Kc;?I zeLuMUE$VZSJx-_<+&nl7PT!;Ea349PE>n{#0hj-+^5@DIl;6bO;b-F>9kk>d%Ddwp z9kzITSKOlm7jN&3dvxgH?fJMz2QS{fC+^YVi??^gJvxB#_T6!h4q?2#A@0#ZjJMat zJvxl>_V&0(2QuDX8~5l?=5KT`b2vJjc^nAunM~5`t-WK=hpvD_Yro$R<-x>Gl zz{VTOqeB~SsErP8yuCW^(c#Tg=>X?%bck~}I>>n(9p-pL4m!~B_FUYfLmhA55%=g| z$J<-t9v$v@dvn~Q10HX0jC*v*;|*BRL65iB#63Ff`5PVh{EZHMyuCi|(ZSE-=UviNvbiAbID^dkF&{m%u`UA`i)z$XV`Nr_Oy6D#h%sJlOp^Cdrrn47vbCNIUajV zgm1Cu_1I1Jd?Yr_o+Gg;dk)8@*wczlisz&3c`Y`BJrp;Su(#0t zZHStIdL3jjHLWqJ)6th2YN9E&s7jR-SZz|7W2@ISg$nOLGiD|ga+Rx^YD7TiYAB>k zA+@2XvNqM(x@Juc2dpLSYKr5^N#Mv;Rhjw-H|xgWQ(L{{qZC=HP4hyjQ^T1m>(?kG z5fu7D!}To;Lx+{S?qnx`&U05@G&;U&S!*J;!tn(bVZkrwwHq!RiUzx)o)~rG3)-=K zkToLUjC*+TIC_}d$&h+DsjbN|L^3rVWeELz_y!33EH$40Li^dLgDksd{3|?Ip|lt_ z+~waZ;3mOpj1?X_eg){Oz=&?ba+Lp9EB7hT{d=eOwB~51v>fgM{44hHKaCT<+vI+- zldQ*g`4`mxu6_i2@hbM;131C^3)l*IukvbS6@NvK+F-j%8C7WG`IrE~nvJKL`6S-F zO(WHAk6LKkOxdP(P2>PFjV<#QAZ0bvu9BKlOp9x)N6mDeU|E>NH^q~2Uk9pxEjFUm(Z2(n{GNL^};M=f|3D55n?gYfG- zYMZmfG*&rY@(%Ql9n5^^rbmW)JZfl@>)bgb5K=I8J4TJMRUWmP*+`v?H9P51bD4Y` zLcg)cqb4yMmNc@#qgF6WHN~_P!^anl3q83tUI)PX17Mtx@NdgC;g@;T4(3Ye-z$nx z=;uSX$D_6^!?q?5z|ar%%>}L?+dp@bH>piSV z(&Qi02o?}hXOtGO>KVXfgZYE0>z+m`y~a^jKZwR{8Kt(adEW47% zZ11JEp1O&7$D_k_2J=qiIW)XPpg0UC7$$nZ@)_lC)g|fiYz7)~^inu(W#ihrMU5!n4r}HrgMvYp zVh$!_ASlEoatF6u3k3sK7$A_uh3kU-D2HmJYn10uZ7%&MIaC`3nQe>|u5G~-2?U@y zY7YW}pDYw{^hyDupA57FZRJ(GFkFc)!aN0xli*@Ji~~Ta4qBJU1?3$VEn!gY?ozMg zP*8R>Y{=sv^M~3Ry-Q5Z>p<)Y6Ee_DdxS%^(d9VFp&UI6)iPk}lrtF^KtOYhe3mLB z!O}yeG|Hi1#s-!|V7UT%MYwNErGiF214B!=KMS3}s(@;JO?OF38&q2Q=H)lW<^8L^m_A^-(Iq3J}Z>q2_iV57YI3sd6Ns|D&xZ|BluFC&*jK2(tq4UVM+A zS9P4#zYR8mjx^@~w9V8OsI3)@!zN~9(q#Za0^CxdnzjI>x3T|q>tW5CZZ!ZJ^zU$6 zYRrIO>0w}3phk&W==P=`0uYQuwNxfZLvCsrZ7hXteUMyf*G#!yr!S*GC?vEL9^ZQ4 zZV1Tj?;T&jAP{yQLC9`YeFjnW9Rc0Z^gTS`j^c8bDAa zYH1-WeF{K&8*_V<|C7p?qWu!A`km62ke?woS&tLBNi~f#wz0#A&2O*Tu4OAtwSi>fDm~a zlq)jtg$R0csUZ3c_zcs}xo}aE7Qs>|Bm=zwsdasWTOiiH(?#a{A^$$O|6ph^)sriL z<_yXelq^A%-n&h<*nP})C#W3=Q5H9+J>mr0>ci}U+`ZRmp4A6zn7aTueedSxxoupG zZJ4nLk$!J)^Nh?VL&Kbu|K}=~744(i5c#_LkI>qgQn%t}-}8ukaeq6ZjZs=%s_&m& zDRx#9=yon$8jNBIYOFe+%cLW225Lr}JKI70K#W3KQyN00=vArC^0=isrr zaZxwZ2Bwagt{0+&%TNodUyYgB z8rzV4M5OP)S!J}XZ8D4G91b?ObtiV#unn!dVRW5gc6d7C?7)#{xJGB#pEVm02pRok z9p|8%yAy?AjsAigsgI^)a4;ICC{`po88xnnCFwXb4c1~!SI39p8!D28CD4>!oTRSn zP7FxA*x_LmoKCO?j#Pn=-vm}8wVV+JmvbiH|Boop_jwvRJ@d#PKwl@T{+jwMPWgWu zcl%$ezpJo5ez`mGsBFgc*!ZM_lW+Jfgvp8#NGcjm+zfLuE^Ar*JPkhcFT-icsqTa; zE8<+pd9ZC2f@L{$gTl|k^~vGx#AR9djB%HM4az*y!={!qewi~M1<2K)BnRG4&UYuS zH<{;}x4y}|*Psg0efTomrvwRH8K1mmO*+g|S@SAHA4*^b-JtyY;AmxUcjBBR2EBgY zwonSxpsaqlW!c!B$jY*8IC2{Wztb&Ma9oM_ZA&_pba%p#;AO}$T)wpoLi6ZDa7whZ zJ8{ehW)9kdGkv6*(AWYbX7nONW&_=cy^Ts~o&R1)%%bZNo$A}JMEt~HYG7C8a*z-D+TZ!QiEm*5zi-Xo0=mF_=#osxi_jl}Q#EBA8 z?##~4?NHnVw;mi`jv|%FEKSRn0F}-T<+f@u#9NGXSPX%mijkY{u#Yy@6(Vy;{ON{Z z$Br7XtYx@*B+;QauaIsQhibL!=yu*QZHkG!eFGtqXC(zc#%q^ zYvZd~`4Ui~e^KpFt|!j7L!W>6v>|r*>xlFJk15)J(=2Tj`6ZnC52{~P-vrCwUsirh zvi>XQxpP^Eaw1V;lo0a+{bpt#&6MQgvzg5ak&o#MOFNX2#JOPR$a*A)p-)9tlmz3; zk%W=mGq?oon&9jzkdhhvbxy)IC{8BXiz5?kq!`h~5`$J)a!?5=D>=I;GQl>hL}qD# za(ECOUWkb=!6!b^e#dlpESc(7g#CZz7j!6x6K1f3{DMN*i2O2cXnu!s zHF2h4zLpdda#>HR!DM92Maq>p zFzmv`$s{WO?}Y0g<#Ukye?K(w$CXj?ySVfBftQ}=D|5V4t>vo_!@yMtoQS}hI{eMR z34r5d^YC2&KND6C?iV0vY6tT84612opc&P)16e$SYTDfzM>Xw0_RgT1c82&-O*@dz znN;)Qy%WrvK{fV^cMUOr2Gu~{1hR9u&$xTH4_z~<=Ea-nSbuqrS5hM$yoX_k2!@$p zQ2`D_U=0a|lXRG3sX*eHgEjJ8A%}i%2Xce1|I3tpjpY9qai{kl^?$3MR)q$DI#2ma zTo&3FoEg%$A!Gy+Ev*ba^O$z0gH59?c1L^@DyKPrxflkEK(K0~4rp1FbQ@lr;A94O z@ZliAhQ%kWGHpT9w}2%)618;ilfDTcXuh;GwUwR*P^OLRt8^7WFs;*4(zfZ$c8rFFIRBebM8I#B5m0NHJB+o!Jq2-ovl8ahZ{1rYq)wA4{cR{)f6<0&ZZ zQlK^tjM5H(VAH9kwiw_4>k6#@RJ1txNn+t9-iOo&lz+t?06oa*{QdIg@ZnGJd`9xF z+*>e?5AL4o&S@mP&+DU`I+fw>#4ULoA~&Wls1ljU-+4FN0AAVHshsIfT$Q!eju&6( zVPwO@xa06Cy1zSdUKZbQcNifNgQ9yvfwiRN$#kc3usddj*p|%(cxCU5Wfp5>o zV__z!1}M=O;gj$Y8tlCp;@kAd>&WWxk?~BBY>XM@|4!wCf?K{OZtj+0<@ZhMHrN5Z z5as=u$JlzOa({Q?hU_5Om$HW>=gZL@VFQ^V&{Z;zKU<6qbShSN;l@zQ3A?e05m{fj6D4@liXxpUbNCfpf)|n#-3i;TpvHs}wt49x=9A!l z(YO2ND%ZOc(AXEk*IKisWMamBQ_I>&3=^q(bX#~*4}XU?{_>8DhsdXGvq|0F+F;}b z=5vW&Q$k8|v>JJrdcz&{g31pq77`u5qsHI^rSYJCA(aHXsC9jm|GSi{iuNAp{eF^^ zNkRR0_2<>st4GykxMlkeB)t@W{ky}Wm}Wv?5ntRDmW#+Woo)moV?!pg1^*CSSd;>C z`p6kzBzvRdLt{r+km?JGBf0&QJ#b+`bqpkfF=eG;3{wX(h4HayMykv-Tm#6#%SBM& zE%U?5RK2{4Cn2lj?t=e|pnzWFvT(^|eDZeFoFcsl9~nXMQ$%x!6(CRaxLOg{E9!*< zji6APZCfJMvDho{q!C%9p(R|a*WFVreXW{)8sw4@3RZ{ z{hn9;LHPg@X8w2o(N5)Pcj8J@>2nm%7RLb+nDn?OkA!zmlHvJhfdq_TWGYL3E7fzHMQow)m% z*e1t6ax??|L5nXm0i$!f*TQfSmtoa8T4 zhNXbR*a7i>UrBJYo;7 zjmV1e!A3ERa3M#HD*4GISwm(`hjK7sgz({oNQhcq8FP9yRD2RA8srh^%S!xNpjJj> zs_b3Wp`1zVZeF6Sy1pP8Ke#d?nwBTOjgjFSIhiJl$*t&61{2vJ9#8YH~w-g+U{iZjMmC|Ao;W+}^LX4qETy3i; zOA0Pdl6(B!Y9zwX&%gg4QnXKL&uJO*AF%7`;{M-n;soFjn*ko0DVsNf+Ycv9*qI%b z8y)#^CaJ<`5hQEvb4-Ff0C!E$HuVq1YDXLL3raSwftqs-ICMlU%N~SZCn$0HO8qk^ zQG!s;mc<-|2Pm95_`0C}XPN|vG&AsFCSeBQC@O*rJM)ncky3*5paeP%pHji2@fro# zcd7)7lvRV1$Dk5)|LJfa@&&8~(K$enKs!&dZw&wTMr%~WF|4frfs-umUTwRBNL$hd>Sq-8&i1ZsDvl=-N)D=j(>C%p3ow=$mvYtwDZ0&bz7r> z)L_?8{-3X$P_&=d#$m&C{2`m9+nfU1Z}d2A1H@EzT~$^v=Z@A zGhl@?$SEL_K_(15+#mz!-Z%piHo`k!@H@95tTmB`tG@p3#BMp8)_)-d8ymdrw;6u? z)^;cQ{e0LdMsT5{>MVTv9qd-`Z~7U`l!{r_wkIB3H+jW_MYsYCo-sx~%tBc6uQvYK zb_JdSPjsvFqqp%Q$F|)}DVZralNX}qOujgEsZ+7L6Hl}*zJ60uqnpHu4z0TH0EQU6 zC359Pf8#}zFQ0@X!=NCLXKXvAit?i~>t47&#Hq7?^dSyc<Y({Z=CUlN_C$7Z0NMlA>x zOHi(I;Httl;oT3Obxc@A%Il^H|0z(dY6lXZK{c?jRDxBQLI!?_^sHHQ;JU(qqqZV^ z4#A&W8P&7{SvG@e+BrF*`fypJ40}nrB5Xdv$rGy0!HJ8Tfk!H+oMti|FcW%bVe5Wt zTgVLRY3pxka0czo!e|K`K*Bp)0q)q`Tow*PoIKpi!5w9}U}b?vJCGDz|5re*Py0h= z0q{xfA?+aiecVI73`@R0PTonLz==Q~S*m^m763mC`@E0BDsK*6Jmw(NH_hKlua6p9 zV+H`_yzSfLGnRM|Q43pZ?2D3nnO^2WmaK3$!0cm=8!p&7wbFz9w^?bKRUSmRNTsF; zqje2!@Ss7Z><`;IWQ*mF9o6yc?ijnuT3zTt7fN9cikbbl>#jSo&4b1g%et~=d@!0- zI166yK>-P_XXi)U5f6_{9TPx{J?IrFtC_h%Y5(xpu_Yd~gOqg~#~Mx>J?Qc%12AtV zeK-fGMWvCb?DpMlK{Bi83GVX zZZ*XL7J4{ARaP>}up)=6)#VF8DQWM6NWcec)08+{5jWKAiTNQ z!|g?7Ez9cL9=y5D!zD%BK&`cqEkJUsAy;)_x-sS9mZDM!nB)YVYnC`uFuh6nf3fn1 zzW+~H@&8rw1LPTU3EID1&<6UX`fhbvJq6D_8o<7}{?c9&Dv+665qi>?_u)!T&u4W5 z4!s;W8iSoXc(W`yX>T5&+Bp(VdvgJmg)KYy1vFgC%$4B1HtRYryc5HAol}MfSTpT) zQYg3%Efy+p)(YQsSWDsE7xvj;5X{IFGj6Gp_7Z@~mEmR1hM7HhA%+XILf(e5Dm5zx z&zWWTc1nA33T5UCxC>#zn<9J+SKwh7TF|Cr!NeQ%nRQ?v15`VgYH6Zf+}v0atvbJe(#vcG}Y@ zUKK2wMff`_x{hvOHHU7o;TokfJl4W-BCscbf*Vkn!!uz=q-g3{7+8eUQ7pQd92^G2 zMx&edR6w;e0-5#{K)G$~Bc`7LkOLEnnR2;Yg!x7nZdS8pxEjkFdAK2kAL*Q4dYU}J zcExgPp857Y{S?YK;F%bHXdR~rjq6N4U#hrpmk8T`rtQM7q@8{eKp;<@m)o(7o zpT%~T0xus0x;$8$gN6+0RNe&VOds#^U?46KPI|ELMpXFyLHe4H!(?+X*yX{V8i#)4 zUb6bFT^`J%@$efEetnk*vt}YZkA-24jE7%O$m(NV9!!k!@ayK071LcFjE3>>YdeXy ztILBeFdlwQoM`zj5AuB;e)T+}>0Qsr;By^>{0rs(W!e@+`?~gJ?a#E|(|$wyMeS!W z3;ZCwfPJ_2M(qwf|BS&d_yh3!b1&=zWdJ<;H%ozUGYZ7L^Kh5}ZzDex_lEe}hvVKk z{`Mnr?<{}&;kb9khda&RJ{0#(@wXq0dnftZ2jkue{`Lbg?>OGnZtY{hzt;?e`Sf1z);Xo2bmOI!Nk!nZEm9Qbi zcyTi6;I@dOfDm}e3hM|&F9FCTSx9DUL{XqlYQ{03d1ao{y%9wLk*76LnqNZLyCtG1 z5H3+xT|*{JixZnWl;Om&U?)o%3f-2=R)+~9A)-{-wW+b9Nh8wKN|8uDu(7eCNw`Vv zaB4huj&6uBhD3liRCIvEgpo_8%WD}j@kF{Y&4gU91%7~t(v0)}Zl?dItsuWm-VATP zo$5#7Yj36UtMJUpeJC`Z?T>AZD~C6SO=9|5NVlkYO*m@chCXkJ_+VcPsfI||+Z$K* zu5Dm0w7#HbCPPndi7Q8Y>x?@3ii!25h=fM?h@@kiqpfRJT=UXI%Hd6M#V{qQCa1?> z^33IOF4o=CV=#sW=NPx5DvJ`Br(D<=SB?!F3n`WHc?iD{dxq4%f(Z>;8caU40pw5b zZBTB55}TH_D-DItCiZV-JJ=nCUFG|^uzG1T(AEp~_U(iP3!}F)fcfjLM9G-qG`04&BWwJ5jznIvAk8*8od_S>~FJ~+{!Lgh z47@R{+iE`4a{A<;cI1}5edsFH98xbeuag;nn_(^7irnhg?5c$6&|rQGQrl1F1gGo& zT;;5yy;s`<{oiNFfcjbZ_*$?0BqHzX&w3(!X{n}yg`HG%1Hy0%B3Of$nrM;Hb^UR6 zrF2?yK`l#d*CaDF9lNzmA>BZk&+og_x5N5gLd8PDH7(y)wUCg0i5DJgz{E2nj%;5; zCbn)hqx{Tfh#*Cp=q{hV8J;2e4q^tq$^jdqeSA7RL(Ys6Vp|>|?)7TRvGKww(Q4Wp zo(f++U4r^=t6KO-}*73~K;y2FMHi)2XYxpsC|qu64bksbiKvQ?^m(dFg-&R=%!ArU)KA zK;7sCuTeoD+t@g=OxQu4>jmvY*G4>sQ>2<&DxHZAQP+DxldrX8$(5~2kT8d+%f1%H zV1TwQh7Mxt-LG*|+Ld5UkVrG^gGS^(oQW7Mjg~CYsK=HTDAQa6=A{!>v$4ogoGH0! z!Hp?Bq(^L=M)4KZNYomk9i}f`|C7pkMf*|hDEWKxCUOuK|K6|Or!G)_QF#&x%EiG* z4+OrUTei#pDsSAP!-pb05G^^>l)3_C+R=lNBeZu z5{?;WSHGfYzplLt{(tsp3S@xqg8!dBM9%(w%Tb_2bx!f! z;M@BUQ)-i~aVWK)s-y-TYKYXxhF8Szq{^zWPUPPQyA?Xaj%Eub4^ZXR;O8C7-Dv+V z6AbEsKIs4ER@1v(e#%bjdOn0B6-W6u^rJY2k_V`J`VfvnnAJERkl#%G)(0_Q(i%vE!iAJ+fV#5};S&^0v3!^j=uCf0BvAg3sozkb^>;>_1I^#d2+aO{ zyHMZ(J+7QFT1gY@)dsilzcaP0w?K_&p6qj{Ge++AKsVrZ$8nX6cU>wo9Hm8tdc^mo$DySEJo5-O zQo=o!G`UhBqh&YJ8#~7i*PI)nK(-=dd|=kXbu0q`WCgK_N()8+wT*~Ta+syeV{cr zI+Xsz+8`mRV1m^|Uj{}yl)Z_8Pe8>%3?TzJl(GEn7|Rff+3-k*l1*$3 zRzcGxbBg!PBaxv2X5wChc$vcQ?y74Y%C^MnP;r6>k)d#vx~B;#B}Poi@#5+%&~2)8 zC}w!LOXlS8g6)pE^aJl88o&&>v2oGbgd5A=*c{vjCqkMazl-+)JJLrXsS&F{#?VgP zQjYM3&(;js51CetH;_UHqi?!Ym__9om?>0zPIFVK+a8Y0J$^QaJ09m@dgU-X9GMU$ zurP8OtU^Q$JQQiOFn!7o#aWi1G1SzR$c(|nyBv_ZI@<7HgxJEZAcGO_>o0dGMj{;? zUfi7^1LChcAE4YEGM5$F3N5MQ3C~9Pf0=Sv!QG#qfVRJ_?bMc% zKO-L{Pm;rAqxyCAQ|b?>kHa=V4mW;(TlrD!0uIYvK;Q|j~%4a$&Nj-HzS$qv{P6nKaQcUPt(?h z)|9X%8J;I#c}B0&@eo>6Lc39(LG~bBIyOv2m^rw66YrZQBa^z^=<_1Q47=&k2%J3P zV{kICX`(S4*a1XhhlMuQJxP4tgNx;Chj$V%c7jGTP`e_7E!tGxv`d{#jQ@ayCQ zxb=UU43L=mTj~eZr_>|rI^}Pbk13Y}9N+%+q6c4nFOSzk(}O3!yV!Q=9z6BcjRmnK zLjTK6Lnvm02d{i}I}9HH>@MCj9{lR<4}YM9kGmM?&IL@ov7s$h`8aU9};=wUq z-G;v_t*1xn>{#%t@~Q=bw+s2LbYVQ2Uo9k3j`OIFfjhQ$%CKP zx_YIC2nQ2-B!&k!taab1H3oUqIV5bM~s&$KheQwF? zwRn~r(S`??sm<|ikkOi;{6AOOsc1j0og!Z)-=+Qwtb80$KCe87$ku=NdN7~)l6a~0 zU_A4sc2n!YmgawopW3S)EO7p()O5^)WzLt(C9b#Bg9YVRph?Qh9t?lJY|eTwdoU3C zvX%a@2UDRhuP@+ZUiVA*kx2QUXvY=pC-F1;H%oz83fwgXD&G44BuDcejAFkup635A D-mA5} literal 0 HcmV?d00001 diff --git a/src/json.hpp b/src/json.hpp index a91edba4f..3563e9ce3 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -121,6 +121,8 @@ default; will be used in @ref string_t) in @ref boolean_t) @tparam NumberIntegerType type for JSON integer numbers (@c `int64_t` by default; will be used in @ref number_integer_t) +@tparam NumberUnsignedType type for JSON unsigned integer numbers (@c `uint64_t` by +default; will be used in @ref number_unsigned_t) @tparam NumberFloatType type for JSON floating-point numbers (@c `double` by default; will be used in @ref number_float_t) @tparam AllocatorType type of the allocator to use (@c `std::allocator` by @@ -182,6 +184,7 @@ template < class StringType = std::string, class BooleanType = bool, class NumberIntegerType = int64_t, + class NumberUnsignedType = uint64_t, class NumberFloatType = double, template class AllocatorType = std::allocator > @@ -194,6 +197,7 @@ class basic_json StringType, BooleanType, NumberIntegerType, + NumberUnsignedType, NumberFloatType, AllocatorType>; @@ -472,9 +476,10 @@ class basic_json > permitted. This description includes both integer and floating-point numbers. However, - C++ allows more precise storage if it is known whether the number is an - integer or a floating-point number. Therefore, two different types, @ref - number_integer_t and @ref number_float_t are used. + C++ allows more precise storage if it is known whether the number is a + signed integer, an unsigned integer or a floating-point number. Therefore, + three different types, @ref number_integer_t, @ref number_unsigned_t and + @ref number_float_t are used. To store integer numbers in C++, a type is defined by the template parameter @a NumberIntegerType which chooses the type to use. @@ -507,7 +512,7 @@ class basic_json that can be stored is `-9223372036854775808` (INT64_MIN). Integer numbers that are out of range will yield over/underflow when used in a constructor. During deserialization, too large or small integer numbers will be - automatically be stored as @ref number_float_t. + automatically be stored as @ref number_unsigned_t or @ref number_float_t. [RFC 7159](http://rfc7159.net/rfc7159) further states: > Note that when such software is used, numbers that are integers and are @@ -523,10 +528,84 @@ class basic_json @sa @ref number_float_t -- type for number values (floating-point) + @sa @ref number_unsigned_t -- type for number values (unsigned integer) + @since version 1.0.0 */ using number_integer_t = NumberIntegerType; + /*! + @brief a type for a number (unsigned) + + [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: + > The representation of numbers is similar to that used in most programming + > languages. A number is represented in base 10 using decimal digits. It + > contains an integer component that may be prefixed with an optional minus + > sign, which may be followed by a fraction part and/or an exponent part. + > Leading zeros are not allowed. (...) Numeric values that cannot be + > represented in the grammar below (such as Infinity and NaN) are not + > permitted. + + This description includes both integer and floating-point numbers. However, + C++ allows more precise storage if it is known whether the number is a + signed integer, an unsigned integer or a floating-point number. Therefore, + three different types, @ref number_integer_t, @ref number_unsigned_t and + @ref number_float_t are used. + + To store unsigned integer numbers in C++, a type is defined by the template + parameter @a NumberUnsignedType which chooses the type to use. + + #### Default type + + With the default values for @a NumberUnsignedType (`uint64_t`), the default + value for @a number_unsigned_t is: + + @code {.cpp} + uint64_t + @endcode + + #### Default behavior + + - The restrictions about leading zeros is not enforced in C++. Instead, + leading zeros in integer literals lead to an interpretation as octal + number. Internally, the value will be stored as decimal number. For + instance, the C++ integer literal `010` will be serialized to `8`. During + deserialization, leading zeros yield an error. + - Not-a-number (NaN) values will be serialized to `null`. + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) specifies: + > An implementation may set limits on the range and precision of numbers. + + When the default type is used, the maximal integer number that can be + stored is `18446744073709551615` (UINT64_MAX) and the minimal integer number + that can be stored is `0`. Integer numbers + that are out of range will yield over/underflow when used in a constructor. + During deserialization, too large or small integer numbers will be + automatically be stored as @ref number_integer_t or @ref number_float_t. + + [RFC 7159](http://rfc7159.net/rfc7159) further states: + > Note that when such software is used, numbers that are integers and are + > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense + > that implementations will agree exactly on their numeric values. + + As this range is a subrange (when considered in conjunction with the + number_integer_t type) of the exactly supported range [0, UINT64_MAX], this + class's integer type is interoperable. + + #### Storage + + Integer number values are stored directly inside a @ref basic_json type. + + @sa @ref number_float_t -- type for number values (floating-point) + + @sa @ref number_integer_t -- type for number values (integer) + + @since version 1.0.0 + */ + using number_unsigned_t = NumberUnsignedType; + /*! @brief a type for a number (floating-point) @@ -540,9 +619,10 @@ class basic_json > permitted. This description includes both integer and floating-point numbers. However, - C++ allows more precise storage if it is known whether the number is an - integer or a floating-point number. Therefore, two different types, @ref - number_integer_t and @ref number_float_t are used. + C++ allows more precise storage if it is known whether the number is a + signed integer, an unsigned integer or a floating-point number. Therefore, + three different types, @ref number_integer_t, @ref number_unsigned_t and + @ref number_float_t are used. To store floating-point numbers in C++, a type is defined by the template parameter @a NumberFloatType which chooses the type to use. @@ -588,6 +668,8 @@ class basic_json @sa @ref number_integer_t -- type for number values (integer) + @sa @ref number_unsigned_t -- type for number values (unsigned integer) + @since version 1.0.0 */ using number_float_t = NumberFloatType; @@ -618,7 +700,8 @@ class basic_json boolean, ///< boolean value number_integer, ///< number value (integer) number_float, ///< number value (floating-point) - discarded ///< discarded by the the parser callback function + discarded, ///< discarded by the the parser callback function + number_unsigned ///< number value (unsigned integer) }; @@ -660,6 +743,8 @@ class basic_json boolean_t boolean; /// number (integer) number_integer_t number_integer; + /// number (unsigned integer) + number_unsigned_t number_unsigned; /// number (floating-point) number_float_t number_float; @@ -669,6 +754,8 @@ class basic_json json_value(boolean_t v) noexcept : boolean(v) {} /// constructor for numbers (integer) json_value(number_integer_t v) noexcept : number_integer(v) {} + /// constructor for numbers (unsigned) + json_value(number_unsigned_t v) noexcept : number_unsigned(v) {} /// constructor for numbers (floating-point) json_value(number_float_t v) noexcept : number_float(v) {} /// constructor for empty values of a given type @@ -705,6 +792,12 @@ class basic_json number_integer = number_integer_t(0); break; } + + case value_t::number_unsigned: + { + number_unsigned = number_unsigned_t(0); + break; + } case value_t::number_float: { @@ -861,6 +954,8 @@ class basic_json (floating-point) value @sa @ref basic_json(const number_integer_t) -- create a number (integer) value + @sa @ref basic_json(const number_unsigned_t) -- create a number (unsigned) + value @since version 1.0.0 */ @@ -1225,13 +1320,71 @@ class basic_json template::value and - std::numeric_limits::is_integer, CompatibleNumberIntegerType>::type - = 0> + std::numeric_limits::is_integer and + std::numeric_limits::is_signed, + CompatibleNumberIntegerType>::type = 0> basic_json(const CompatibleNumberIntegerType val) noexcept : m_type(value_t::number_integer), m_value(static_cast(val)) {} + /*! + @brief create an unsigned integer number (explicit) + + Create an unsigned integer number JSON value with a given content. + + @tparam T helper type to compare number_unsigned_t and unsigned int + (not visible in) the interface. + + @param[in] val an integer to create a JSON number from + + @complexity Constant. + + @sa @ref basic_json(const CompatibleNumberUnsignedType) -- create a number + value (unsigned integer) from a compatible number type + + @since version 1.0.0 + */ + template::value) + and std::is_same::value + , int>::type = 0> + basic_json(const number_unsigned_t val) + : m_type(value_t::number_unsigned), m_value(val) + {} + + /*! + @brief create an unsigned number (implicit) + + Create an unsigned number JSON value with a given content. This constructor + allows any type that can be used to construct values of type @ref + number_unsigned_t. Examples may include the types `unsigned int`, `uint32_t`, + or `unsigned short`. + + @tparam CompatibleNumberUnsignedType an integer type which is compatible to + @ref number_unsigned_t. + + @param[in] val an unsigned integer to create a JSON number from + + @complexity Constant. + + @sa @ref basic_json(const number_unsigned_t) -- create a number value + (unsigned) + + @since version 1.0.0 + */ + template::value and + std::numeric_limits::is_integer and + !std::numeric_limits::is_signed, + CompatibleNumberUnsignedType>::type = 0> + basic_json(const CompatibleNumberUnsignedType val) noexcept + : m_type(value_t::number_unsigned), + m_value(static_cast(val)) + {} + /*! @brief create a floating-point number (explicit) @@ -1591,6 +1744,7 @@ class basic_json case value_t::boolean: case value_t::number_float: case value_t::number_integer: + case value_t::number_unsigned: case value_t::string: { if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end()) @@ -1614,6 +1768,13 @@ class basic_json m_value.number_integer = first.m_object->m_value.number_integer; break; } + + case value_t::number_unsigned: + { + assert(first.m_object != nullptr); + m_value.number_unsigned = first.m_object->m_value.number_unsigned; + break; + } case value_t::number_float: { @@ -1717,6 +1878,12 @@ class basic_json m_value = other.m_value.number_integer; break; } + + case value_t::number_unsigned: + { + m_value = other.m_value.number_unsigned; + break; + } case value_t::number_float: { @@ -1992,18 +2159,20 @@ class basic_json /*! @brief return whether value is a number - This function returns true iff the JSON value is a number. This includes + This function returns true if the JSON value is a number. This includes both integer and floating-point values. - @return `true` if type is number (regardless whether integer or - floating-type), `false` otherwise. + @return `true` if type is number (regardless whether integer, unsigned + integer or floating-type), `false` otherwise. @complexity Constant. @liveexample{The following code exemplifies @ref is_number for all JSON types.,is_number} - @sa @ref is_number_integer() -- check if value is an integer number + @sa @ref is_number_integer() -- check if value is an integer or unsigned + integer number + @sa @ref is_number_unsigned() -- check if value is an unsigned integer number @sa @ref is_number_float() -- check if value is a floating-point number @since version 1.0.0 @@ -2016,10 +2185,11 @@ class basic_json /*! @brief return whether value is an integer number - This function returns true iff the JSON value is an integer number. This - excludes floating-point values. + This function returns true if the JSON value is an integer or unsigned + integer number. This excludes floating-point values. - @return `true` if type is an integer number, `false` otherwise. + @return `true` if type is an integer or unsigned integer number, `false` + otherwise. @complexity Constant. @@ -2027,20 +2197,43 @@ class basic_json JSON types.,is_number_integer} @sa @ref is_number() -- check if value is a number + @sa @ref is_number_unsigned() -- check if value is an unsigned integer number @sa @ref is_number_float() -- check if value is a floating-point number @since version 1.0.0 */ bool is_number_integer() const noexcept { - return m_type == value_t::number_integer; + return m_type == value_t::number_integer or m_type == value_t::number_unsigned; + } + + /*! + @brief return whether value is an unsigned integer number + + This function returns true if the JSON value is an unsigned integer number. + This excludes floating-point and (signed) integer values. + + @return `true` if type is an unsigned integer number, `false` otherwise. + + @complexity Constant. + + @sa @ref is_number() -- check if value is a number + @sa @ref is_number_integer() -- check if value is an integer or unsigned + integer number + @sa @ref is_number_float() -- check if value is a floating-point number + + @since version 1.0.0 + */ + bool is_number_unsigned() const noexcept + { + return m_type == value_t::number_unsigned; } /*! @brief return whether value is a floating-point number - This function returns true iff the JSON value is a floating-point number. - This excludes integer values. + This function returns true if the JSON value is a floating-point number. + This excludes integer and unsigned integer values. @return `true` if type is a floating-point number, `false` otherwise. @@ -2051,6 +2244,7 @@ class basic_json @sa @ref is_number() -- check if value is number @sa @ref is_number_integer() -- check if value is an integer number + @sa @ref is_number_unsigned() -- check if value is an unsigned integer number @since version 1.0.0 */ @@ -2318,6 +2512,11 @@ class basic_json { return static_cast(m_value.number_integer); } + + case value_t::number_unsigned: + { + return static_cast(m_value.number_unsigned); + } case value_t::number_float: { @@ -2403,7 +2602,19 @@ class basic_json { return is_number_integer() ? &m_value.number_integer : nullptr; } + + /// get a pointer to the value (unsigned number) + number_unsigned_t* get_impl_ptr(number_unsigned_t*) noexcept + { + return is_number_unsigned() ? &m_value.number_unsigned : nullptr; + } + /// get a pointer to the value (unsigned number) + const number_unsigned_t* get_impl_ptr(const number_unsigned_t*) const noexcept + { + return is_number_unsigned() ? &m_value.number_unsigned : nullptr; + } + /// get a pointer to the value (floating-point number) number_float_t* get_impl_ptr(number_float_t*) noexcept { @@ -2472,8 +2683,8 @@ class basic_json @warning The pointer becomes invalid if the underlying JSON object changes. @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref - object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or @ref - number_float_t. + object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, + @ref number_unsigned_t, or @ref number_float_t. @return pointer to the internally stored JSON value if the requested pointer type @a PointerType fits to the JSON value; `nullptr` otherwise @@ -2523,8 +2734,8 @@ class basic_json state. @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref - object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or @ref - number_float_t. + object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, + @ref number_unsigned_t, or @ref number_float_t. @return pointer to the internally stored JSON value if the requested pointer type @a PointerType fits to the JSON value; `nullptr` otherwise @@ -3286,6 +3497,7 @@ class basic_json case value_t::boolean: case value_t::number_float: case value_t::number_integer: + case value_t::number_unsigned: case value_t::string: { if (not pos.m_it.primitive_iterator.is_begin()) @@ -3391,6 +3603,7 @@ class basic_json case value_t::boolean: case value_t::number_float: case value_t::number_integer: + case value_t::number_unsigned: case value_t::string: { if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end()) @@ -4080,6 +4293,12 @@ class basic_json break; } + case value_t::number_unsigned: + { + m_value.number_unsigned = 0; + break; + } + case value_t::number_float: { m_value.number_float = 0.0; @@ -4618,14 +4837,16 @@ class basic_json */ friend bool operator<(const value_t lhs, const value_t rhs) { - static constexpr std::array order = {{ + static constexpr std::array order = {{ 0, // null 3, // object 4, // array 5, // string 1, // boolean 2, // integer - 2 // float + 2, // float + 0, // filler for discarded (preserves existing value_t values) + 2 // unsigned } }; @@ -4701,6 +4922,10 @@ class basic_json { return lhs.m_value.number_integer == rhs.m_value.number_integer; } + case value_t::number_unsigned: + { + return lhs.m_value.number_unsigned == rhs.m_value.number_unsigned; + } case value_t::number_float: { return approx(lhs.m_value.number_float, rhs.m_value.number_float); @@ -4721,6 +4946,25 @@ class basic_json return approx(lhs.m_value.number_float, static_cast(rhs.m_value.number_integer)); } + else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float) + { + return approx(static_cast(lhs.m_value.number_unsigned), + rhs.m_value.number_float); + } + else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned) + { + return approx(lhs.m_value.number_float, + static_cast(rhs.m_value.number_unsigned)); + } + else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer) + { + return static_cast(lhs.m_value.number_unsigned) == rhs.m_value.number_integer; + } + else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned) + { + return lhs.m_value.number_integer == static_cast(rhs.m_value.number_unsigned); + } + return false; } @@ -4872,6 +5116,10 @@ class basic_json { return lhs.m_value.number_integer < rhs.m_value.number_integer; } + case value_t::number_unsigned: + { + return lhs.m_value.number_unsigned < rhs.m_value.number_unsigned; + } case value_t::number_float: { return lhs.m_value.number_float < rhs.m_value.number_float; @@ -4892,6 +5140,24 @@ class basic_json return lhs.m_value.number_float < static_cast(rhs.m_value.number_integer); } + else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float) + { + return static_cast(lhs.m_value.number_unsigned) < + rhs.m_value.number_float; + } + else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned) + { + return lhs.m_value.number_float < + static_cast(rhs.m_value.number_unsigned); + } + else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned) + { + return lhs.m_value.number_integer < static_cast(rhs.m_value.number_unsigned); + } + else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer) + { + return static_cast(lhs.m_value.number_unsigned) < rhs.m_value.number_integer; + } // We only reach this line if we cannot compare values. In that case, // we compare types. Note we have to call the operator explicitly, @@ -5455,6 +5721,12 @@ class basic_json return; } + case value_t::number_unsigned: + { + o << m_value.number_unsigned; + return; + } + case value_t::number_float: { // 15 digits of precision allows round-trip IEEE 754 @@ -6665,789 +6937,386 @@ class basic_json m_start = m_cursor; assert(m_start != nullptr); - - { - lexer_char_t yych; - unsigned int yyaccept = 0; - static const unsigned char yybm[] = - { - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 32, 32, 0, 0, 32, 0, 0, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 96, 64, 0, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 192, 192, 192, 192, 192, 192, 192, 192, - 192, 192, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 0, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, - }; - if ((m_limit - m_cursor) < 5) - { - yyfill(); // LCOV_EXCL_LINE; + + { + lexer_char_t yych; + unsigned int yyaccept = 0; + static const unsigned char yybm[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 32, 32, 0, 0, 32, 0, 0, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 96, 64, 0, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 192, 192, 192, 192, 192, 192, 192, 192, + 192, 192, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 0, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + }; + if ((m_limit - m_cursor) < 5) yyfill(); // LCOV_EXCL_LINE; + yych = *m_cursor; + if (yych <= ':') { + if (yych <= ' ') { + if (yych <= '\n') { + if (yych <= 0x00) goto basic_json_parser_28; + if (yych <= 0x08) goto basic_json_parser_30; + if (yych >= '\n') goto basic_json_parser_4; + } else { + if (yych == '\r') goto basic_json_parser_2; + if (yych <= 0x1F) goto basic_json_parser_30; } - yych = *m_cursor; - if (yych <= ':') - { - if (yych <= ' ') - { - if (yych <= '\n') - { - if (yych <= 0x00) - { - goto basic_json_parser_28; - } - if (yych <= 0x08) - { - goto basic_json_parser_30; - } - if (yych >= '\n') - { - goto basic_json_parser_4; - } - } - else - { - if (yych == '\r') - { - goto basic_json_parser_2; - } - if (yych <= 0x1F) - { - goto basic_json_parser_30; - } - } + } else { + if (yych <= ',') { + if (yych == '"') goto basic_json_parser_27; + if (yych <= '+') goto basic_json_parser_30; + goto basic_json_parser_16; + } else { + if (yych <= '/') { + if (yych <= '-') goto basic_json_parser_23; + goto basic_json_parser_30; + } else { + if (yych <= '0') goto basic_json_parser_24; + if (yych <= '9') goto basic_json_parser_26; + goto basic_json_parser_18; } - else - { - if (yych <= ',') - { - if (yych == '"') - { - goto basic_json_parser_27; - } - if (yych <= '+') - { - goto basic_json_parser_30; - } - goto basic_json_parser_16; - } - else - { - if (yych <= '/') - { - if (yych <= '-') - { - goto basic_json_parser_23; - } - goto basic_json_parser_30; - } - else - { - if (yych <= '0') - { - goto basic_json_parser_24; - } - if (yych <= '9') - { - goto basic_json_parser_26; - } - goto basic_json_parser_18; - } - } - } - } - else - { - if (yych <= 'n') - { - if (yych <= ']') - { - if (yych == '[') - { - goto basic_json_parser_8; - } - if (yych <= '\\') - { - goto basic_json_parser_30; - } - goto basic_json_parser_10; - } - else - { - if (yych == 'f') - { - goto basic_json_parser_22; - } - if (yych <= 'm') - { - goto basic_json_parser_30; - } - goto basic_json_parser_20; - } - } - else - { - if (yych <= '{') - { - if (yych == 't') - { - goto basic_json_parser_21; - } - if (yych <= 'z') - { - goto basic_json_parser_30; - } - goto basic_json_parser_12; - } - else - { - if (yych <= '}') - { - if (yych <= '|') - { - goto basic_json_parser_30; - } - goto basic_json_parser_14; - } - else - { - if (yych == 0xEF) - { - goto basic_json_parser_6; - } - goto basic_json_parser_30; - } - } - } - } -basic_json_parser_2: - ++m_cursor; - yych = *m_cursor; - goto basic_json_parser_5; -basic_json_parser_3: - { - return scan(); - } -basic_json_parser_4: - ++m_cursor; - if (m_limit <= m_cursor) - { - yyfill(); // LCOV_EXCL_LINE; - } - yych = *m_cursor; -basic_json_parser_5: - if (yybm[0 + yych] & 32) - { - goto basic_json_parser_4; - } - goto basic_json_parser_3; -basic_json_parser_6: - yyaccept = 0; - yych = *(m_marker = ++m_cursor); - if (yych == 0xBB) - { - goto basic_json_parser_64; - } -basic_json_parser_7: - { - return token_type::parse_error; - } -basic_json_parser_8: - ++m_cursor; - { - return token_type::begin_array; - } -basic_json_parser_10: - ++m_cursor; - { - return token_type::end_array; - } -basic_json_parser_12: - ++m_cursor; - { - return token_type::begin_object; - } -basic_json_parser_14: - ++m_cursor; - { - return token_type::end_object; - } -basic_json_parser_16: - ++m_cursor; - { - return token_type::value_separator; - } -basic_json_parser_18: - ++m_cursor; - { - return token_type::name_separator; - } -basic_json_parser_20: - yyaccept = 0; - yych = *(m_marker = ++m_cursor); - if (yych == 'u') - { - goto basic_json_parser_60; - } - goto basic_json_parser_7; -basic_json_parser_21: - yyaccept = 0; - yych = *(m_marker = ++m_cursor); - if (yych == 'r') - { - goto basic_json_parser_56; - } - goto basic_json_parser_7; -basic_json_parser_22: - yyaccept = 0; - yych = *(m_marker = ++m_cursor); - if (yych == 'a') - { - goto basic_json_parser_51; - } - goto basic_json_parser_7; -basic_json_parser_23: - yych = *++m_cursor; - if (yych <= '/') - { - goto basic_json_parser_7; - } - if (yych <= '0') - { - goto basic_json_parser_50; - } - if (yych <= '9') - { - goto basic_json_parser_41; - } - goto basic_json_parser_7; -basic_json_parser_24: - yyaccept = 1; - yych = *(m_marker = ++m_cursor); - if (yych <= 'D') - { - if (yych == '.') - { - goto basic_json_parser_43; - } - } - else - { - if (yych <= 'E') - { - goto basic_json_parser_44; - } - if (yych == 'e') - { - goto basic_json_parser_44; - } - } -basic_json_parser_25: - { - return token_type::value_number; - } -basic_json_parser_26: - yyaccept = 1; - yych = *(m_marker = ++m_cursor); - goto basic_json_parser_42; -basic_json_parser_27: - yyaccept = 0; - yych = *(m_marker = ++m_cursor); - if (yych <= 0x0F) - { - goto basic_json_parser_7; - } - goto basic_json_parser_32; -basic_json_parser_28: - ++m_cursor; - { - return token_type::end_of_input; - } -basic_json_parser_30: - yych = *++m_cursor; - goto basic_json_parser_7; -basic_json_parser_31: - ++m_cursor; - if (m_limit <= m_cursor) - { - yyfill(); // LCOV_EXCL_LINE; - } - yych = *m_cursor; -basic_json_parser_32: - if (yybm[0 + yych] & 64) - { - goto basic_json_parser_31; - } - if (yych <= 0x0F) - { - goto basic_json_parser_33; - } - if (yych <= '"') - { - goto basic_json_parser_35; - } - goto basic_json_parser_34; -basic_json_parser_33: - m_cursor = m_marker; - if (yyaccept == 0) - { - goto basic_json_parser_7; - } - else - { - goto basic_json_parser_25; - } -basic_json_parser_34: - ++m_cursor; - if (m_limit <= m_cursor) - { - yyfill(); // LCOV_EXCL_LINE; - } - yych = *m_cursor; - if (yych <= 'e') - { - if (yych <= '/') - { - if (yych == '"') - { - goto basic_json_parser_31; - } - if (yych <= '.') - { - goto basic_json_parser_33; - } - goto basic_json_parser_31; - } - else - { - if (yych <= '\\') - { - if (yych <= '[') - { - goto basic_json_parser_33; - } - goto basic_json_parser_31; - } - else - { - if (yych == 'b') - { - goto basic_json_parser_31; - } - goto basic_json_parser_33; - } - } - } - else - { - if (yych <= 'q') - { - if (yych <= 'f') - { - goto basic_json_parser_31; - } - if (yych == 'n') - { - goto basic_json_parser_31; - } - goto basic_json_parser_33; - } - else - { - if (yych <= 's') - { - if (yych <= 'r') - { - goto basic_json_parser_31; - } - goto basic_json_parser_33; - } - else - { - if (yych <= 't') - { - goto basic_json_parser_31; - } - if (yych <= 'u') - { - goto basic_json_parser_37; - } - goto basic_json_parser_33; - } - } - } -basic_json_parser_35: - ++m_cursor; - { - return token_type::value_string; - } -basic_json_parser_37: - ++m_cursor; - if (m_limit <= m_cursor) - { - yyfill(); // LCOV_EXCL_LINE; - } - yych = *m_cursor; - if (yych <= '@') - { - if (yych <= '/') - { - goto basic_json_parser_33; - } - if (yych >= ':') - { - goto basic_json_parser_33; - } - } - else - { - if (yych <= 'F') - { - goto basic_json_parser_38; - } - if (yych <= '`') - { - goto basic_json_parser_33; - } - if (yych >= 'g') - { - goto basic_json_parser_33; - } - } -basic_json_parser_38: - ++m_cursor; - if (m_limit <= m_cursor) - { - yyfill(); // LCOV_EXCL_LINE; - } - yych = *m_cursor; - if (yych <= '@') - { - if (yych <= '/') - { - goto basic_json_parser_33; - } - if (yych >= ':') - { - goto basic_json_parser_33; - } - } - else - { - if (yych <= 'F') - { - goto basic_json_parser_39; - } - if (yych <= '`') - { - goto basic_json_parser_33; - } - if (yych >= 'g') - { - goto basic_json_parser_33; - } - } -basic_json_parser_39: - ++m_cursor; - if (m_limit <= m_cursor) - { - yyfill(); // LCOV_EXCL_LINE; - } - yych = *m_cursor; - if (yych <= '@') - { - if (yych <= '/') - { - goto basic_json_parser_33; - } - if (yych >= ':') - { - goto basic_json_parser_33; - } - } - else - { - if (yych <= 'F') - { - goto basic_json_parser_40; - } - if (yych <= '`') - { - goto basic_json_parser_33; - } - if (yych >= 'g') - { - goto basic_json_parser_33; - } - } -basic_json_parser_40: - ++m_cursor; - if (m_limit <= m_cursor) - { - yyfill(); // LCOV_EXCL_LINE; - } - yych = *m_cursor; - if (yych <= '@') - { - if (yych <= '/') - { - goto basic_json_parser_33; - } - if (yych <= '9') - { - goto basic_json_parser_31; - } - goto basic_json_parser_33; - } - else - { - if (yych <= 'F') - { - goto basic_json_parser_31; - } - if (yych <= '`') - { - goto basic_json_parser_33; - } - if (yych <= 'f') - { - goto basic_json_parser_31; - } - goto basic_json_parser_33; - } -basic_json_parser_41: - yyaccept = 1; - m_marker = ++m_cursor; - if ((m_limit - m_cursor) < 3) - { - yyfill(); // LCOV_EXCL_LINE; - } - yych = *m_cursor; -basic_json_parser_42: - if (yybm[0 + yych] & 128) - { - goto basic_json_parser_41; - } - if (yych <= 'D') - { - if (yych != '.') - { - goto basic_json_parser_25; - } - } - else - { - if (yych <= 'E') - { - goto basic_json_parser_44; - } - if (yych == 'e') - { - goto basic_json_parser_44; - } - goto basic_json_parser_25; - } -basic_json_parser_43: - yych = *++m_cursor; - if (yych <= '/') - { - goto basic_json_parser_33; - } - if (yych <= '9') - { - goto basic_json_parser_48; - } - goto basic_json_parser_33; -basic_json_parser_44: - yych = *++m_cursor; - if (yych <= ',') - { - if (yych != '+') - { - goto basic_json_parser_33; - } - } - else - { - if (yych <= '-') - { - goto basic_json_parser_45; - } - if (yych <= '/') - { - goto basic_json_parser_33; - } - if (yych <= '9') - { - goto basic_json_parser_46; - } - goto basic_json_parser_33; - } -basic_json_parser_45: - yych = *++m_cursor; - if (yych <= '/') - { - goto basic_json_parser_33; - } - if (yych >= ':') - { - goto basic_json_parser_33; - } -basic_json_parser_46: - ++m_cursor; - if (m_limit <= m_cursor) - { - yyfill(); // LCOV_EXCL_LINE; - } - yych = *m_cursor; - if (yych <= '/') - { - goto basic_json_parser_25; - } - if (yych <= '9') - { - goto basic_json_parser_46; - } - goto basic_json_parser_25; -basic_json_parser_48: - yyaccept = 1; - m_marker = ++m_cursor; - if ((m_limit - m_cursor) < 3) - { - yyfill(); // LCOV_EXCL_LINE; - } - yych = *m_cursor; - if (yych <= 'D') - { - if (yych <= '/') - { - goto basic_json_parser_25; - } - if (yych <= '9') - { - goto basic_json_parser_48; - } - goto basic_json_parser_25; - } - else - { - if (yych <= 'E') - { - goto basic_json_parser_44; - } - if (yych == 'e') - { - goto basic_json_parser_44; - } - goto basic_json_parser_25; - } -basic_json_parser_50: - yyaccept = 1; - yych = *(m_marker = ++m_cursor); - if (yych <= 'D') - { - if (yych == '.') - { - goto basic_json_parser_43; - } - goto basic_json_parser_25; - } - else - { - if (yych <= 'E') - { - goto basic_json_parser_44; - } - if (yych == 'e') - { - goto basic_json_parser_44; - } - goto basic_json_parser_25; - } -basic_json_parser_51: - yych = *++m_cursor; - if (yych != 'l') - { - goto basic_json_parser_33; - } - yych = *++m_cursor; - if (yych != 's') - { - goto basic_json_parser_33; - } - yych = *++m_cursor; - if (yych != 'e') - { - goto basic_json_parser_33; - } - ++m_cursor; - { - return token_type::literal_false; - } -basic_json_parser_56: - yych = *++m_cursor; - if (yych != 'u') - { - goto basic_json_parser_33; - } - yych = *++m_cursor; - if (yych != 'e') - { - goto basic_json_parser_33; - } - ++m_cursor; - { - return token_type::literal_true; - } -basic_json_parser_60: - yych = *++m_cursor; - if (yych != 'l') - { - goto basic_json_parser_33; - } - yych = *++m_cursor; - if (yych != 'l') - { - goto basic_json_parser_33; - } - ++m_cursor; - { - return token_type::literal_null; - } -basic_json_parser_64: - yych = *++m_cursor; - if (yych != 0xBF) - { - goto basic_json_parser_33; - } - ++m_cursor; - { - return scan(); } } + } else { + if (yych <= 'n') { + if (yych <= ']') { + if (yych == '[') goto basic_json_parser_8; + if (yych <= '\\') goto basic_json_parser_30; + goto basic_json_parser_10; + } else { + if (yych == 'f') goto basic_json_parser_22; + if (yych <= 'm') goto basic_json_parser_30; + goto basic_json_parser_20; + } + } else { + if (yych <= '{') { + if (yych == 't') goto basic_json_parser_21; + if (yych <= 'z') goto basic_json_parser_30; + goto basic_json_parser_12; + } else { + if (yych <= '}') { + if (yych <= '|') goto basic_json_parser_30; + goto basic_json_parser_14; + } else { + if (yych == 0xEF) goto basic_json_parser_6; + goto basic_json_parser_30; + } + } + } + } +basic_json_parser_2: + ++m_cursor; + yych = *m_cursor; + goto basic_json_parser_5; +basic_json_parser_3: + { return scan(); } +basic_json_parser_4: + ++m_cursor; + if (m_limit <= m_cursor) yyfill(); // LCOV_EXCL_LINE; + yych = *m_cursor; +basic_json_parser_5: + if (yybm[0+yych] & 32) { + goto basic_json_parser_4; + } + goto basic_json_parser_3; +basic_json_parser_6: + yyaccept = 0; + yych = *(m_marker = ++m_cursor); + if (yych == 0xBB) goto basic_json_parser_64; +basic_json_parser_7: + { return token_type::parse_error; } +basic_json_parser_8: + ++m_cursor; + { return token_type::begin_array; } +basic_json_parser_10: + ++m_cursor; + { return token_type::end_array; } +basic_json_parser_12: + ++m_cursor; + { return token_type::begin_object; } +basic_json_parser_14: + ++m_cursor; + { return token_type::end_object; } +basic_json_parser_16: + ++m_cursor; + { return token_type::value_separator; } +basic_json_parser_18: + ++m_cursor; + { return token_type::name_separator; } +basic_json_parser_20: + yyaccept = 0; + yych = *(m_marker = ++m_cursor); + if (yych == 'u') goto basic_json_parser_60; + goto basic_json_parser_7; +basic_json_parser_21: + yyaccept = 0; + yych = *(m_marker = ++m_cursor); + if (yych == 'r') goto basic_json_parser_56; + goto basic_json_parser_7; +basic_json_parser_22: + yyaccept = 0; + yych = *(m_marker = ++m_cursor); + if (yych == 'a') goto basic_json_parser_51; + goto basic_json_parser_7; +basic_json_parser_23: + yych = *++m_cursor; + if (yych <= '/') goto basic_json_parser_7; + if (yych <= '0') goto basic_json_parser_50; + if (yych <= '9') goto basic_json_parser_41; + goto basic_json_parser_7; +basic_json_parser_24: + yyaccept = 1; + yych = *(m_marker = ++m_cursor); + if (yych <= 'D') { + if (yych == '.') goto basic_json_parser_43; + } else { + if (yych <= 'E') goto basic_json_parser_44; + if (yych == 'e') goto basic_json_parser_44; + } +basic_json_parser_25: + { return token_type::value_number; } +basic_json_parser_26: + yyaccept = 1; + yych = *(m_marker = ++m_cursor); + goto basic_json_parser_42; +basic_json_parser_27: + yyaccept = 0; + yych = *(m_marker = ++m_cursor); + if (yych <= 0x0F) goto basic_json_parser_7; + goto basic_json_parser_32; +basic_json_parser_28: + ++m_cursor; + { return token_type::end_of_input; } +basic_json_parser_30: + yych = *++m_cursor; + goto basic_json_parser_7; +basic_json_parser_31: + ++m_cursor; + if (m_limit <= m_cursor) yyfill(); // LCOV_EXCL_LINE; + yych = *m_cursor; +basic_json_parser_32: + if (yybm[0+yych] & 64) { + goto basic_json_parser_31; + } + if (yych <= 0x0F) goto basic_json_parser_33; + if (yych <= '"') goto basic_json_parser_35; + goto basic_json_parser_34; +basic_json_parser_33: + m_cursor = m_marker; + if (yyaccept == 0) { + goto basic_json_parser_7; + } else { + goto basic_json_parser_25; + } +basic_json_parser_34: + ++m_cursor; + if (m_limit <= m_cursor) yyfill(); // LCOV_EXCL_LINE; + yych = *m_cursor; + if (yych <= 'e') { + if (yych <= '/') { + if (yych == '"') goto basic_json_parser_31; + if (yych <= '.') goto basic_json_parser_33; + goto basic_json_parser_31; + } else { + if (yych <= '\\') { + if (yych <= '[') goto basic_json_parser_33; + goto basic_json_parser_31; + } else { + if (yych == 'b') goto basic_json_parser_31; + goto basic_json_parser_33; + } + } + } else { + if (yych <= 'q') { + if (yych <= 'f') goto basic_json_parser_31; + if (yych == 'n') goto basic_json_parser_31; + goto basic_json_parser_33; + } else { + if (yych <= 's') { + if (yych <= 'r') goto basic_json_parser_31; + goto basic_json_parser_33; + } else { + if (yych <= 't') goto basic_json_parser_31; + if (yych <= 'u') goto basic_json_parser_37; + goto basic_json_parser_33; + } + } + } +basic_json_parser_35: + ++m_cursor; + { return token_type::value_string; } +basic_json_parser_37: + ++m_cursor; + if (m_limit <= m_cursor) yyfill(); // LCOV_EXCL_LINE; + yych = *m_cursor; + if (yych <= '@') { + if (yych <= '/') goto basic_json_parser_33; + if (yych >= ':') goto basic_json_parser_33; + } else { + if (yych <= 'F') goto basic_json_parser_38; + if (yych <= '`') goto basic_json_parser_33; + if (yych >= 'g') goto basic_json_parser_33; + } +basic_json_parser_38: + ++m_cursor; + if (m_limit <= m_cursor) yyfill(); // LCOV_EXCL_LINE; + yych = *m_cursor; + if (yych <= '@') { + if (yych <= '/') goto basic_json_parser_33; + if (yych >= ':') goto basic_json_parser_33; + } else { + if (yych <= 'F') goto basic_json_parser_39; + if (yych <= '`') goto basic_json_parser_33; + if (yych >= 'g') goto basic_json_parser_33; + } +basic_json_parser_39: + ++m_cursor; + if (m_limit <= m_cursor) yyfill(); // LCOV_EXCL_LINE; + yych = *m_cursor; + if (yych <= '@') { + if (yych <= '/') goto basic_json_parser_33; + if (yych >= ':') goto basic_json_parser_33; + } else { + if (yych <= 'F') goto basic_json_parser_40; + if (yych <= '`') goto basic_json_parser_33; + if (yych >= 'g') goto basic_json_parser_33; + } +basic_json_parser_40: + ++m_cursor; + if (m_limit <= m_cursor) yyfill(); // LCOV_EXCL_LINE; + yych = *m_cursor; + if (yych <= '@') { + if (yych <= '/') goto basic_json_parser_33; + if (yych <= '9') goto basic_json_parser_31; + goto basic_json_parser_33; + } else { + if (yych <= 'F') goto basic_json_parser_31; + if (yych <= '`') goto basic_json_parser_33; + if (yych <= 'f') goto basic_json_parser_31; + goto basic_json_parser_33; + } +basic_json_parser_41: + yyaccept = 1; + m_marker = ++m_cursor; + if ((m_limit - m_cursor) < 3) yyfill(); // LCOV_EXCL_LINE; + yych = *m_cursor; +basic_json_parser_42: + if (yybm[0+yych] & 128) { + goto basic_json_parser_41; + } + if (yych <= 'D') { + if (yych != '.') goto basic_json_parser_25; + } else { + if (yych <= 'E') goto basic_json_parser_44; + if (yych == 'e') goto basic_json_parser_44; + goto basic_json_parser_25; + } +basic_json_parser_43: + yych = *++m_cursor; + if (yych <= '/') goto basic_json_parser_33; + if (yych <= '9') goto basic_json_parser_48; + goto basic_json_parser_33; +basic_json_parser_44: + yych = *++m_cursor; + if (yych <= ',') { + if (yych != '+') goto basic_json_parser_33; + } else { + if (yych <= '-') goto basic_json_parser_45; + if (yych <= '/') goto basic_json_parser_33; + if (yych <= '9') goto basic_json_parser_46; + goto basic_json_parser_33; + } +basic_json_parser_45: + yych = *++m_cursor; + if (yych <= '/') goto basic_json_parser_33; + if (yych >= ':') goto basic_json_parser_33; +basic_json_parser_46: + ++m_cursor; + if (m_limit <= m_cursor) yyfill(); // LCOV_EXCL_LINE; + yych = *m_cursor; + if (yych <= '/') goto basic_json_parser_25; + if (yych <= '9') goto basic_json_parser_46; + goto basic_json_parser_25; +basic_json_parser_48: + yyaccept = 1; + m_marker = ++m_cursor; + if ((m_limit - m_cursor) < 3) yyfill(); // LCOV_EXCL_LINE; + yych = *m_cursor; + if (yych <= 'D') { + if (yych <= '/') goto basic_json_parser_25; + if (yych <= '9') goto basic_json_parser_48; + goto basic_json_parser_25; + } else { + if (yych <= 'E') goto basic_json_parser_44; + if (yych == 'e') goto basic_json_parser_44; + goto basic_json_parser_25; + } +basic_json_parser_50: + yyaccept = 1; + yych = *(m_marker = ++m_cursor); + if (yych <= 'D') { + if (yych == '.') goto basic_json_parser_43; + goto basic_json_parser_25; + } else { + if (yych <= 'E') goto basic_json_parser_44; + if (yych == 'e') goto basic_json_parser_44; + goto basic_json_parser_25; + } +basic_json_parser_51: + yych = *++m_cursor; + if (yych != 'l') goto basic_json_parser_33; + yych = *++m_cursor; + if (yych != 's') goto basic_json_parser_33; + yych = *++m_cursor; + if (yych != 'e') goto basic_json_parser_33; + ++m_cursor; + { return token_type::literal_false; } +basic_json_parser_56: + yych = *++m_cursor; + if (yych != 'u') goto basic_json_parser_33; + yych = *++m_cursor; + if (yych != 'e') goto basic_json_parser_33; + ++m_cursor; + { return token_type::literal_true; } +basic_json_parser_60: + yych = *++m_cursor; + if (yych != 'l') goto basic_json_parser_33; + yych = *++m_cursor; + if (yych != 'l') goto basic_json_parser_33; + ++m_cursor; + { return token_type::literal_null; } +basic_json_parser_64: + yych = *++m_cursor; + if (yych != 0xBF) goto basic_json_parser_33; + ++m_cursor; + { return scan(); } + } } @@ -7627,17 +7496,40 @@ basic_json_parser_64: @throw std::range_error if passed value is out of range */ - long double get_number() const + void get_number(basic_json& result) const { - // conversion - typename string_t::value_type* endptr; + typename string_t::value_type* float_endptr, *endptr; assert(m_start != nullptr); - const auto float_val = std::strtold(reinterpret_cast(m_start), - &endptr); + + // Parse it as an integer + if(*reinterpret_cast(m_start) != '-') { + // Unsigned + result.m_value.number_unsigned = strtoull(reinterpret_cast(m_start),&endptr,10); + result.m_type = value_t::number_unsigned; + } + else { + // Signed + result.m_value.number_integer = strtoll(reinterpret_cast(m_start),&endptr,10); + result.m_type = value_t::number_integer; + } - // return float_val if the whole number was translated and NAN - // otherwise - return (reinterpret_cast(endptr) == m_cursor) ? float_val : NAN; + // Parse it as a double + const auto float_val = strtold(reinterpret_cast(m_start),&endptr); + long double int_part; + const auto frac_part = std::modf(float_val, &int_part); + + // Test if the double or integer is a better representation + if(!approx(frac_part, static_cast(0)) || + (result.m_type == value_t::number_unsigned && !approx(int_part, static_cast(result.m_value.number_unsigned))) || + (result.m_type == value_t::number_integer && !approx(int_part, static_cast(result.m_value.number_integer)))) { + result.m_value.number_float = float_val; + result.m_type = value_t::number_float; + } + + if(reinterpret_cast(endptr) != m_cursor) { + result.m_value.number_float = NAN; + result.m_type = value_t::number_float; + } } private: @@ -7867,11 +7759,12 @@ basic_json_parser_64: case lexer::token_type::value_number: { - auto float_val = m_lexer.get_number(); + m_lexer.get_number(result); // NAN is returned if token could not be translated // completely - if (std::isnan(float_val)) + if (result.m_type == value_t::number_float && + std::isnan(result.m_value.number_float)) { throw std::invalid_argument(std::string("parse error - ") + m_lexer.get_token() + " is not a number"); @@ -7879,20 +7772,6 @@ basic_json_parser_64: get_token(); - // check if conversion loses precision - const auto int_val = static_cast(float_val); - if (approx(float_val, static_cast(int_val))) - { - // we would not lose precision -> return int - result.m_type = value_t::number_integer; - result.m_value = int_val; - } - else - { - // we would lose precision -> return float - result.m_type = value_t::number_float; - result.m_value = static_cast(float_val); - } break; } diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index a733f0979..8d342e485 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -121,6 +121,8 @@ default; will be used in @ref string_t) in @ref boolean_t) @tparam NumberIntegerType type for JSON integer numbers (@c `int64_t` by default; will be used in @ref number_integer_t) +@tparam NumberUnsignedType type for JSON unsigned integer numbers (@c `uint64_t` by +default; will be used in @ref number_unsigned_t) @tparam NumberFloatType type for JSON floating-point numbers (@c `double` by default; will be used in @ref number_float_t) @tparam AllocatorType type of the allocator to use (@c `std::allocator` by @@ -182,6 +184,7 @@ template < class StringType = std::string, class BooleanType = bool, class NumberIntegerType = int64_t, + class NumberUnsignedType = uint64_t, class NumberFloatType = double, template class AllocatorType = std::allocator > @@ -194,6 +197,7 @@ class basic_json StringType, BooleanType, NumberIntegerType, + NumberUnsignedType, NumberFloatType, AllocatorType>; @@ -472,9 +476,10 @@ class basic_json > permitted. This description includes both integer and floating-point numbers. However, - C++ allows more precise storage if it is known whether the number is an - integer or a floating-point number. Therefore, two different types, @ref - number_integer_t and @ref number_float_t are used. + C++ allows more precise storage if it is known whether the number is a + signed integer, an unsigned integer or a floating-point number. Therefore, + three different types, @ref number_integer_t, @ref number_unsigned_t and + @ref number_float_t are used. To store integer numbers in C++, a type is defined by the template parameter @a NumberIntegerType which chooses the type to use. @@ -507,7 +512,7 @@ class basic_json that can be stored is `-9223372036854775808` (INT64_MIN). Integer numbers that are out of range will yield over/underflow when used in a constructor. During deserialization, too large or small integer numbers will be - automatically be stored as @ref number_float_t. + automatically be stored as @ref number_unsigned_t or @ref number_float_t. [RFC 7159](http://rfc7159.net/rfc7159) further states: > Note that when such software is used, numbers that are integers and are @@ -523,10 +528,84 @@ class basic_json @sa @ref number_float_t -- type for number values (floating-point) + @sa @ref number_unsigned_t -- type for number values (unsigned integer) + @since version 1.0.0 */ using number_integer_t = NumberIntegerType; + /*! + @brief a type for a number (unsigned) + + [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: + > The representation of numbers is similar to that used in most programming + > languages. A number is represented in base 10 using decimal digits. It + > contains an integer component that may be prefixed with an optional minus + > sign, which may be followed by a fraction part and/or an exponent part. + > Leading zeros are not allowed. (...) Numeric values that cannot be + > represented in the grammar below (such as Infinity and NaN) are not + > permitted. + + This description includes both integer and floating-point numbers. However, + C++ allows more precise storage if it is known whether the number is a + signed integer, an unsigned integer or a floating-point number. Therefore, + three different types, @ref number_integer_t, @ref number_unsigned_t and + @ref number_float_t are used. + + To store unsigned integer numbers in C++, a type is defined by the template + parameter @a NumberUnsignedType which chooses the type to use. + + #### Default type + + With the default values for @a NumberUnsignedType (`uint64_t`), the default + value for @a number_unsigned_t is: + + @code {.cpp} + uint64_t + @endcode + + #### Default behavior + + - The restrictions about leading zeros is not enforced in C++. Instead, + leading zeros in integer literals lead to an interpretation as octal + number. Internally, the value will be stored as decimal number. For + instance, the C++ integer literal `010` will be serialized to `8`. During + deserialization, leading zeros yield an error. + - Not-a-number (NaN) values will be serialized to `null`. + + #### Limits + + [RFC 7159](http://rfc7159.net/rfc7159) specifies: + > An implementation may set limits on the range and precision of numbers. + + When the default type is used, the maximal integer number that can be + stored is `18446744073709551615` (UINT64_MAX) and the minimal integer number + that can be stored is `0`. Integer numbers + that are out of range will yield over/underflow when used in a constructor. + During deserialization, too large or small integer numbers will be + automatically be stored as @ref number_integer_t or @ref number_float_t. + + [RFC 7159](http://rfc7159.net/rfc7159) further states: + > Note that when such software is used, numbers that are integers and are + > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense + > that implementations will agree exactly on their numeric values. + + As this range is a subrange (when considered in conjunction with the + number_integer_t type) of the exactly supported range [0, UINT64_MAX], this + class's integer type is interoperable. + + #### Storage + + Integer number values are stored directly inside a @ref basic_json type. + + @sa @ref number_float_t -- type for number values (floating-point) + + @sa @ref number_integer_t -- type for number values (integer) + + @since version 1.0.0 + */ + using number_unsigned_t = NumberUnsignedType; + /*! @brief a type for a number (floating-point) @@ -540,9 +619,10 @@ class basic_json > permitted. This description includes both integer and floating-point numbers. However, - C++ allows more precise storage if it is known whether the number is an - integer or a floating-point number. Therefore, two different types, @ref - number_integer_t and @ref number_float_t are used. + C++ allows more precise storage if it is known whether the number is a + signed integer, an unsigned integer or a floating-point number. Therefore, + three different types, @ref number_integer_t, @ref number_unsigned_t and + @ref number_float_t are used. To store floating-point numbers in C++, a type is defined by the template parameter @a NumberFloatType which chooses the type to use. @@ -588,6 +668,8 @@ class basic_json @sa @ref number_integer_t -- type for number values (integer) + @sa @ref number_unsigned_t -- type for number values (unsigned integer) + @since version 1.0.0 */ using number_float_t = NumberFloatType; @@ -618,7 +700,8 @@ class basic_json boolean, ///< boolean value number_integer, ///< number value (integer) number_float, ///< number value (floating-point) - discarded ///< discarded by the the parser callback function + discarded, ///< discarded by the the parser callback function + number_unsigned ///< number value (unsigned integer) }; @@ -660,6 +743,8 @@ class basic_json boolean_t boolean; /// number (integer) number_integer_t number_integer; + /// number (unsigned integer) + number_unsigned_t number_unsigned; /// number (floating-point) number_float_t number_float; @@ -669,6 +754,8 @@ class basic_json json_value(boolean_t v) noexcept : boolean(v) {} /// constructor for numbers (integer) json_value(number_integer_t v) noexcept : number_integer(v) {} + /// constructor for numbers (unsigned) + json_value(number_unsigned_t v) noexcept : number_unsigned(v) {} /// constructor for numbers (floating-point) json_value(number_float_t v) noexcept : number_float(v) {} /// constructor for empty values of a given type @@ -705,6 +792,12 @@ class basic_json number_integer = number_integer_t(0); break; } + + case value_t::number_unsigned: + { + number_unsigned = number_unsigned_t(0); + break; + } case value_t::number_float: { @@ -861,6 +954,8 @@ class basic_json (floating-point) value @sa @ref basic_json(const number_integer_t) -- create a number (integer) value + @sa @ref basic_json(const number_unsigned_t) -- create a number (unsigned) + value @since version 1.0.0 */ @@ -1225,13 +1320,71 @@ class basic_json template::value and - std::numeric_limits::is_integer, CompatibleNumberIntegerType>::type - = 0> + std::numeric_limits::is_integer and + std::numeric_limits::is_signed, + CompatibleNumberIntegerType>::type = 0> basic_json(const CompatibleNumberIntegerType val) noexcept : m_type(value_t::number_integer), m_value(static_cast(val)) {} + /*! + @brief create an unsigned integer number (explicit) + + Create an unsigned integer number JSON value with a given content. + + @tparam T helper type to compare number_unsigned_t and unsigned int + (not visible in) the interface. + + @param[in] val an integer to create a JSON number from + + @complexity Constant. + + @sa @ref basic_json(const CompatibleNumberUnsignedType) -- create a number + value (unsigned integer) from a compatible number type + + @since version 1.0.0 + */ + template::value) + and std::is_same::value + , int>::type = 0> + basic_json(const number_unsigned_t val) + : m_type(value_t::number_unsigned), m_value(val) + {} + + /*! + @brief create an unsigned number (implicit) + + Create an unsigned number JSON value with a given content. This constructor + allows any type that can be used to construct values of type @ref + number_unsigned_t. Examples may include the types `unsigned int`, `uint32_t`, + or `unsigned short`. + + @tparam CompatibleNumberUnsignedType an integer type which is compatible to + @ref number_unsigned_t. + + @param[in] val an unsigned integer to create a JSON number from + + @complexity Constant. + + @sa @ref basic_json(const number_unsigned_t) -- create a number value + (unsigned) + + @since version 1.0.0 + */ + template::value and + std::numeric_limits::is_integer and + !std::numeric_limits::is_signed, + CompatibleNumberUnsignedType>::type = 0> + basic_json(const CompatibleNumberUnsignedType val) noexcept + : m_type(value_t::number_unsigned), + m_value(static_cast(val)) + {} + /*! @brief create a floating-point number (explicit) @@ -1591,6 +1744,7 @@ class basic_json case value_t::boolean: case value_t::number_float: case value_t::number_integer: + case value_t::number_unsigned: case value_t::string: { if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end()) @@ -1614,6 +1768,13 @@ class basic_json m_value.number_integer = first.m_object->m_value.number_integer; break; } + + case value_t::number_unsigned: + { + assert(first.m_object != nullptr); + m_value.number_unsigned = first.m_object->m_value.number_unsigned; + break; + } case value_t::number_float: { @@ -1717,6 +1878,12 @@ class basic_json m_value = other.m_value.number_integer; break; } + + case value_t::number_unsigned: + { + m_value = other.m_value.number_unsigned; + break; + } case value_t::number_float: { @@ -1992,18 +2159,20 @@ class basic_json /*! @brief return whether value is a number - This function returns true iff the JSON value is a number. This includes + This function returns true if the JSON value is a number. This includes both integer and floating-point values. - @return `true` if type is number (regardless whether integer or - floating-type), `false` otherwise. + @return `true` if type is number (regardless whether integer, unsigned + integer or floating-type), `false` otherwise. @complexity Constant. @liveexample{The following code exemplifies @ref is_number for all JSON types.,is_number} - @sa @ref is_number_integer() -- check if value is an integer number + @sa @ref is_number_integer() -- check if value is an integer or unsigned + integer number + @sa @ref is_number_unsigned() -- check if value is an unsigned integer number @sa @ref is_number_float() -- check if value is a floating-point number @since version 1.0.0 @@ -2016,10 +2185,11 @@ class basic_json /*! @brief return whether value is an integer number - This function returns true iff the JSON value is an integer number. This - excludes floating-point values. + This function returns true if the JSON value is an integer or unsigned + integer number. This excludes floating-point values. - @return `true` if type is an integer number, `false` otherwise. + @return `true` if type is an integer or unsigned integer number, `false` + otherwise. @complexity Constant. @@ -2027,20 +2197,43 @@ class basic_json JSON types.,is_number_integer} @sa @ref is_number() -- check if value is a number + @sa @ref is_number_unsigned() -- check if value is an unsigned integer number @sa @ref is_number_float() -- check if value is a floating-point number @since version 1.0.0 */ bool is_number_integer() const noexcept { - return m_type == value_t::number_integer; + return m_type == value_t::number_integer or m_type == value_t::number_unsigned; + } + + /*! + @brief return whether value is an unsigned integer number + + This function returns true if the JSON value is an unsigned integer number. + This excludes floating-point and (signed) integer values. + + @return `true` if type is an unsigned integer number, `false` otherwise. + + @complexity Constant. + + @sa @ref is_number() -- check if value is a number + @sa @ref is_number_integer() -- check if value is an integer or unsigned + integer number + @sa @ref is_number_float() -- check if value is a floating-point number + + @since version 1.0.0 + */ + bool is_number_unsigned() const noexcept + { + return m_type == value_t::number_unsigned; } /*! @brief return whether value is a floating-point number - This function returns true iff the JSON value is a floating-point number. - This excludes integer values. + This function returns true if the JSON value is a floating-point number. + This excludes integer and unsigned integer values. @return `true` if type is a floating-point number, `false` otherwise. @@ -2051,6 +2244,7 @@ class basic_json @sa @ref is_number() -- check if value is number @sa @ref is_number_integer() -- check if value is an integer number + @sa @ref is_number_unsigned() -- check if value is an unsigned integer number @since version 1.0.0 */ @@ -2318,6 +2512,11 @@ class basic_json { return static_cast(m_value.number_integer); } + + case value_t::number_unsigned: + { + return static_cast(m_value.number_unsigned); + } case value_t::number_float: { @@ -2403,7 +2602,19 @@ class basic_json { return is_number_integer() ? &m_value.number_integer : nullptr; } + + /// get a pointer to the value (unsigned number) + number_unsigned_t* get_impl_ptr(number_unsigned_t*) noexcept + { + return is_number_unsigned() ? &m_value.number_unsigned : nullptr; + } + /// get a pointer to the value (unsigned number) + const number_unsigned_t* get_impl_ptr(const number_unsigned_t*) const noexcept + { + return is_number_unsigned() ? &m_value.number_unsigned : nullptr; + } + /// get a pointer to the value (floating-point number) number_float_t* get_impl_ptr(number_float_t*) noexcept { @@ -2472,8 +2683,8 @@ class basic_json @warning The pointer becomes invalid if the underlying JSON object changes. @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref - object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or @ref - number_float_t. + object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, + @ref number_unsigned_t, or @ref number_float_t. @return pointer to the internally stored JSON value if the requested pointer type @a PointerType fits to the JSON value; `nullptr` otherwise @@ -2523,8 +2734,8 @@ class basic_json state. @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref - object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or @ref - number_float_t. + object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, + @ref number_unsigned_t, or @ref number_float_t. @return pointer to the internally stored JSON value if the requested pointer type @a PointerType fits to the JSON value; `nullptr` otherwise @@ -3286,6 +3497,7 @@ class basic_json case value_t::boolean: case value_t::number_float: case value_t::number_integer: + case value_t::number_unsigned: case value_t::string: { if (not pos.m_it.primitive_iterator.is_begin()) @@ -3391,6 +3603,7 @@ class basic_json case value_t::boolean: case value_t::number_float: case value_t::number_integer: + case value_t::number_unsigned: case value_t::string: { if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end()) @@ -4080,6 +4293,12 @@ class basic_json break; } + case value_t::number_unsigned: + { + m_value.number_unsigned = 0; + break; + } + case value_t::number_float: { m_value.number_float = 0.0; @@ -4618,14 +4837,16 @@ class basic_json */ friend bool operator<(const value_t lhs, const value_t rhs) { - static constexpr std::array order = {{ + static constexpr std::array order = {{ 0, // null 3, // object 4, // array 5, // string 1, // boolean 2, // integer - 2 // float + 2, // float + 0, // filler for discarded (preserves existing value_t values) + 2 // unsigned } }; @@ -4701,6 +4922,10 @@ class basic_json { return lhs.m_value.number_integer == rhs.m_value.number_integer; } + case value_t::number_unsigned: + { + return lhs.m_value.number_unsigned == rhs.m_value.number_unsigned; + } case value_t::number_float: { return approx(lhs.m_value.number_float, rhs.m_value.number_float); @@ -4721,6 +4946,25 @@ class basic_json return approx(lhs.m_value.number_float, static_cast(rhs.m_value.number_integer)); } + else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float) + { + return approx(static_cast(lhs.m_value.number_unsigned), + rhs.m_value.number_float); + } + else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned) + { + return approx(lhs.m_value.number_float, + static_cast(rhs.m_value.number_unsigned)); + } + else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer) + { + return static_cast(lhs.m_value.number_unsigned) == rhs.m_value.number_integer; + } + else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned) + { + return lhs.m_value.number_integer == static_cast(rhs.m_value.number_unsigned); + } + return false; } @@ -4872,6 +5116,10 @@ class basic_json { return lhs.m_value.number_integer < rhs.m_value.number_integer; } + case value_t::number_unsigned: + { + return lhs.m_value.number_unsigned < rhs.m_value.number_unsigned; + } case value_t::number_float: { return lhs.m_value.number_float < rhs.m_value.number_float; @@ -4892,6 +5140,24 @@ class basic_json return lhs.m_value.number_float < static_cast(rhs.m_value.number_integer); } + else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float) + { + return static_cast(lhs.m_value.number_unsigned) < + rhs.m_value.number_float; + } + else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned) + { + return lhs.m_value.number_float < + static_cast(rhs.m_value.number_unsigned); + } + else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned) + { + return lhs.m_value.number_integer < static_cast(rhs.m_value.number_unsigned); + } + else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer) + { + return static_cast(lhs.m_value.number_unsigned) < rhs.m_value.number_integer; + } // We only reach this line if we cannot compare values. In that case, // we compare types. Note we have to call the operator explicitly, @@ -5455,6 +5721,12 @@ class basic_json return; } + case value_t::number_unsigned: + { + o << m_value.number_unsigned; + return; + } + case value_t::number_float: { // 15 digits of precision allows round-trip IEEE 754 @@ -6906,17 +7178,40 @@ class basic_json @throw std::range_error if passed value is out of range */ - long double get_number() const + void get_number(basic_json& result) const { - // conversion - typename string_t::value_type* endptr; + typename string_t::value_type* float_endptr, *endptr; assert(m_start != nullptr); - const auto float_val = std::strtold(reinterpret_cast(m_start), - &endptr); + + // Parse it as an integer + if(*reinterpret_cast(m_start) != '-') { + // Unsigned + result.m_value.number_unsigned = strtoull(reinterpret_cast(m_start),&endptr,10); + result.m_type = value_t::number_unsigned; + } + else { + // Signed + result.m_value.number_integer = strtoll(reinterpret_cast(m_start),&endptr,10); + result.m_type = value_t::number_integer; + } - // return float_val if the whole number was translated and NAN - // otherwise - return (reinterpret_cast(endptr) == m_cursor) ? float_val : NAN; + // Parse it as a double + const auto float_val = strtold(reinterpret_cast(m_start),&endptr); + long double int_part; + const auto frac_part = std::modf(float_val, &int_part); + + // Test if the double or integer is a better representation + if(!approx(frac_part, static_cast(0)) || + (result.m_type == value_t::number_unsigned && !approx(int_part, static_cast(result.m_value.number_unsigned))) || + (result.m_type == value_t::number_integer && !approx(int_part, static_cast(result.m_value.number_integer)))) { + result.m_value.number_float = float_val; + result.m_type = value_t::number_float; + } + + if(reinterpret_cast(endptr) != m_cursor) { + result.m_value.number_float = NAN; + result.m_type = value_t::number_float; + } } private: @@ -7146,11 +7441,12 @@ class basic_json case lexer::token_type::value_number: { - auto float_val = m_lexer.get_number(); + m_lexer.get_number(result); // NAN is returned if token could not be translated // completely - if (std::isnan(float_val)) + if (result.m_type == value_t::number_float && + std::isnan(result.m_value.number_float)) { throw std::invalid_argument(std::string("parse error - ") + m_lexer.get_token() + " is not a number"); @@ -7158,20 +7454,6 @@ class basic_json get_token(); - // check if conversion loses precision - const auto int_val = static_cast(float_val); - if (approx(float_val, static_cast(int_val))) - { - // we would not lose precision -> return int - result.m_type = value_t::number_integer; - result.m_value = int_val; - } - else - { - // we would lose precision -> return float - result.m_type = value_t::number_float; - result.m_value = static_cast(float_val); - } break; } diff --git a/test/unit.cpp b/test/unit.cpp index ebf3fb2a3..7ddb95dc8 100644 --- a/test/unit.cpp +++ b/test/unit.cpp @@ -78,6 +78,13 @@ TEST_CASE("constructors") CHECK(j.type() == t); } + SECTION("number_unsigned") + { + auto t = json::value_t::number_unsigned; + json j(t); + CHECK(j.type() == t); + } + SECTION("number_float") { auto t = json::value_t::number_float; @@ -115,7 +122,7 @@ TEST_CASE("constructors") SECTION("filled object") { - json::object_t o {{"a", json(1)}, {"b", json(2.2)}, {"c", json(false)}, {"d", json("string")}, {"e", json()}}; + json::object_t o {{"a", json(1)}, {"b", json(1u)}, {"c", json(2.2)}, {"d", json(false)}, {"e", json("string")}, {"f", json()}}; json j(o); CHECK(j.type() == json::value_t::object); } @@ -124,12 +131,12 @@ TEST_CASE("constructors") SECTION("create an object (implicit)") { // reference object - json::object_t o_reference {{"a", json(1)}, {"b", json(2.2)}, {"c", json(false)}, {"d", json("string")}, {"e", json()}}; + json::object_t o_reference {{"a", json(1)}, {"b", json(1u)}, {"c", json(2.2)}, {"d", json(false)}, {"e", json("string")}, {"f", json()}}; json j_reference(o_reference); SECTION("std::map") { - std::map o {{"a", json(1)}, {"b", json(2.2)}, {"c", json(false)}, {"d", json("string")}, {"e", json()}}; + std::map o {{"a", json(1)}, {"b", json(1u)}, {"c", json(2.2)}, {"d", json(false)}, {"e", json("string")}, {"f", json()}}; json j(o); CHECK(j.type() == json::value_t::object); CHECK(j == j_reference); @@ -137,7 +144,7 @@ TEST_CASE("constructors") SECTION("std::map") { - std::map o {{"a", json(1)}, {"b", json(2.2)}, {"c", json(false)}, {"d", json("string")}, {"e", json()}}; + std::map o {{"a", json(1)}, {"b", json(1u)}, {"c", json(2.2)}, {"d", json(false)}, {"e", json("string")}, {"f", json()}}; json j(o); CHECK(j.type() == json::value_t::object); CHECK(j == j_reference); @@ -145,7 +152,7 @@ TEST_CASE("constructors") SECTION("std::multimap") { - std::multimap o {{"a", json(1)}, {"b", json(2.2)}, {"c", json(false)}, {"d", json("string")}, {"e", json()}}; + std::multimap o {{"a", json(1)}, {"b", json(1u)}, {"c", json(2.2)}, {"d", json(false)}, {"e", json("string")}, {"f", json()}}; json j(o); CHECK(j.type() == json::value_t::object); CHECK(j == j_reference); @@ -153,7 +160,7 @@ TEST_CASE("constructors") SECTION("std::unordered_map") { - std::unordered_map o {{"a", json(1)}, {"b", json(2.2)}, {"c", json(false)}, {"d", json("string")}, {"e", json()}}; + std::unordered_map o {{"a", json(1)}, {"b", json(1u)}, {"c", json(2.2)}, {"d", json(false)}, {"e", json("string")}, {"f", json()}}; json j(o); CHECK(j.type() == json::value_t::object); CHECK(j == j_reference); @@ -161,7 +168,7 @@ TEST_CASE("constructors") SECTION("std::unordered_multimap") { - std::unordered_multimap o {{"a", json(1)}, {"b", json(2.2)}, {"c", json(false)}, {"d", json("string")}, {"e", json()}}; + std::unordered_multimap o {{"a", json(1)}, {"b", json(1u)}, {"c", json(2.2)}, {"d", json(false)}, {"e", json("string")}, {"f", json()}}; json j(o); CHECK(j.type() == json::value_t::object); CHECK(j == j_reference); @@ -169,7 +176,7 @@ TEST_CASE("constructors") SECTION("associative container literal") { - json j({{"a", json(1)}, {"b", json(2.2)}, {"c", json(false)}, {"d", json("string")}, {"e", json()}}); + json j({{"a", json(1)}, {"b", json(1u)}, {"c", json(2.2)}, {"d", json(false)}, {"e", json("string")}, {"f", json()}}); CHECK(j.type() == json::value_t::object); CHECK(j == j_reference); } @@ -186,7 +193,7 @@ TEST_CASE("constructors") SECTION("filled array") { - json::array_t a {json(1), json(2.2), json(false), json("string"), json()}; + json::array_t a {json(1), json(1u), json(2.2), json(false), json("string"), json()}; json j(a); CHECK(j.type() == json::value_t::array); } @@ -195,12 +202,12 @@ TEST_CASE("constructors") SECTION("create an array (implicit)") { // reference array - json::array_t a_reference {json(1), json(2.2), json(false), json("string"), json()}; + json::array_t a_reference {json(1), json(1u), json(2.2), json(false), json("string"), json()}; json j_reference(a_reference); SECTION("std::list") { - std::list a {json(1), json(2.2), json(false), json("string"), json()}; + std::list a {json(1), json(1u), json(2.2), json(false), json("string"), json()}; json j(a); CHECK(j.type() == json::value_t::array); CHECK(j == j_reference); @@ -208,7 +215,7 @@ TEST_CASE("constructors") SECTION("std::forward_list") { - std::forward_list a {json(1), json(2.2), json(false), json("string"), json()}; + std::forward_list a {json(1), json(1u), json(2.2), json(false), json("string"), json()}; json j(a); CHECK(j.type() == json::value_t::array); CHECK(j == j_reference); @@ -216,7 +223,7 @@ TEST_CASE("constructors") SECTION("std::array") { - std::array a {{json(1), json(2.2), json(false), json("string"), json()}}; + std::array a {{json(1), json(1u), json(2.2), json(false), json("string"), json()}}; json j(a); CHECK(j.type() == json::value_t::array); CHECK(j == j_reference); @@ -224,7 +231,7 @@ TEST_CASE("constructors") SECTION("std::vector") { - std::vector a {json(1), json(2.2), json(false), json("string"), json()}; + std::vector a {json(1), json(1u), json(2.2), json(false), json("string"), json()}; json j(a); CHECK(j.type() == json::value_t::array); CHECK(j == j_reference); @@ -232,7 +239,7 @@ TEST_CASE("constructors") SECTION("std::deque") { - std::deque a {json(1), json(2.2), json(false), json("string"), json()}; + std::deque a {json(1), json(1u), json(2.2), json(false), json("string"), json()}; json j(a); CHECK(j.type() == json::value_t::array); CHECK(j == j_reference); @@ -240,7 +247,7 @@ TEST_CASE("constructors") SECTION("std::set") { - std::set a {json(1), json(2.2), json(false), json("string"), json()}; + std::set a {json(1), json(1u), json(2.2), json(false), json("string"), json()}; json j(a); CHECK(j.type() == json::value_t::array); // we cannot really check for equality here @@ -248,7 +255,7 @@ TEST_CASE("constructors") SECTION("std::unordered_set") { - std::unordered_set a {json(1), json(2.2), json(false), json("string"), json()}; + std::unordered_set a {json(1), json(1u), json(2.2), json(false), json("string"), json()}; json j(a); CHECK(j.type() == json::value_t::array); // we cannot really check for equality here @@ -256,7 +263,7 @@ TEST_CASE("constructors") SECTION("sequence container literal") { - json j({json(1), json(2.2), json(false), json("string"), json()}); + json j({json(1), json(1u), json(2.2), json(false), json("string"), json()}); CHECK(j.type() == json::value_t::array); CHECK(j == j_reference); } @@ -358,9 +365,11 @@ TEST_CASE("constructors") SECTION("create an integer number (implicit)") { - // reference object + // reference objects json::number_integer_t n_reference = 42; json j_reference(n_reference); + json::number_unsigned_t n_unsigned_reference = 42; + json j_unsigned_reference(n_unsigned_reference); SECTION("short") { @@ -374,8 +383,8 @@ TEST_CASE("constructors") { unsigned short n = 42; json j(n); - CHECK(j.type() == json::value_t::number_integer); - CHECK(j == j_reference); + CHECK(j.type() == json::value_t::number_unsigned); + CHECK(j == j_unsigned_reference); } SECTION("int") @@ -390,8 +399,8 @@ TEST_CASE("constructors") { unsigned int n = 42; json j(n); - CHECK(j.type() == json::value_t::number_integer); - CHECK(j == j_reference); + CHECK(j.type() == json::value_t::number_unsigned); + CHECK(j == j_unsigned_reference); } SECTION("long") @@ -404,10 +413,10 @@ TEST_CASE("constructors") SECTION("unsigned long") { - short n = 42; + unsigned long n = 42; json j(n); - CHECK(j.type() == json::value_t::number_integer); - CHECK(j == j_reference); + CHECK(j.type() == json::value_t::number_unsigned); + CHECK(j == j_unsigned_reference); } SECTION("long long") @@ -422,8 +431,8 @@ TEST_CASE("constructors") { unsigned long long n = 42; json j(n); - CHECK(j.type() == json::value_t::number_integer); - CHECK(j == j_reference); + CHECK(j.type() == json::value_t::number_unsigned); + CHECK(j == j_unsigned_reference); } SECTION("int8_t") @@ -526,96 +535,96 @@ TEST_CASE("constructors") { uint8_t n = 42; json j(n); - CHECK(j.type() == json::value_t::number_integer); - CHECK(j == j_reference); + CHECK(j.type() == json::value_t::number_unsigned); + CHECK(j == j_unsigned_reference); } SECTION("uint16_t") { uint16_t n = 42; json j(n); - CHECK(j.type() == json::value_t::number_integer); - CHECK(j == j_reference); + CHECK(j.type() == json::value_t::number_unsigned); + CHECK(j == j_unsigned_reference); } SECTION("uint32_t") { uint32_t n = 42; json j(n); - CHECK(j.type() == json::value_t::number_integer); - CHECK(j == j_reference); + CHECK(j.type() == json::value_t::number_unsigned); + CHECK(j == j_unsigned_reference); } SECTION("uint64_t") { uint64_t n = 42; json j(n); - CHECK(j.type() == json::value_t::number_integer); - CHECK(j == j_reference); + CHECK(j.type() == json::value_t::number_unsigned); + CHECK(j == j_unsigned_reference); } SECTION("uint_fast8_t") { uint_fast8_t n = 42; json j(n); - CHECK(j.type() == json::value_t::number_integer); - CHECK(j == j_reference); + CHECK(j.type() == json::value_t::number_unsigned); + CHECK(j == j_unsigned_reference); } SECTION("uint_fast16_t") { uint_fast16_t n = 42; json j(n); - CHECK(j.type() == json::value_t::number_integer); - CHECK(j == j_reference); + CHECK(j.type() == json::value_t::number_unsigned); + CHECK(j == j_unsigned_reference); } SECTION("uint_fast32_t") { uint_fast32_t n = 42; json j(n); - CHECK(j.type() == json::value_t::number_integer); - CHECK(j == j_reference); + CHECK(j.type() == json::value_t::number_unsigned); + CHECK(j == j_unsigned_reference); } SECTION("uint_fast64_t") { uint_fast64_t n = 42; json j(n); - CHECK(j.type() == json::value_t::number_integer); - CHECK(j == j_reference); + CHECK(j.type() == json::value_t::number_unsigned); + CHECK(j == j_unsigned_reference); } SECTION("uint_least8_t") { uint_least8_t n = 42; json j(n); - CHECK(j.type() == json::value_t::number_integer); - CHECK(j == j_reference); + CHECK(j.type() == json::value_t::number_unsigned); + CHECK(j == j_unsigned_reference); } SECTION("uint_least16_t") { uint_least16_t n = 42; json j(n); - CHECK(j.type() == json::value_t::number_integer); - CHECK(j == j_reference); + CHECK(j.type() == json::value_t::number_unsigned); + CHECK(j == j_unsigned_reference); } SECTION("uint_least32_t") { uint_least32_t n = 42; json j(n); - CHECK(j.type() == json::value_t::number_integer); - CHECK(j == j_reference); + CHECK(j.type() == json::value_t::number_unsigned); + CHECK(j == j_unsigned_reference); } SECTION("uint_least64_t") { uint_least64_t n = 42; json j(n); - CHECK(j.type() == json::value_t::number_integer); - CHECK(j == j_reference); + CHECK(j.type() == json::value_t::number_unsigned); + CHECK(j == j_unsigned_reference); } SECTION("integer literal without suffix") @@ -628,8 +637,8 @@ TEST_CASE("constructors") SECTION("integer literal with u suffix") { json j(42u); - CHECK(j.type() == json::value_t::number_integer); - CHECK(j == j_reference); + CHECK(j.type() == json::value_t::number_unsigned); + CHECK(j == j_unsigned_reference); } SECTION("integer literal with l suffix") @@ -642,8 +651,8 @@ TEST_CASE("constructors") SECTION("integer literal with ul suffix") { json j(42ul); - CHECK(j.type() == json::value_t::number_integer); - CHECK(j == j_reference); + CHECK(j.type() == json::value_t::number_unsigned); + CHECK(j == j_unsigned_reference); } SECTION("integer literal with ll suffix") @@ -656,8 +665,8 @@ TEST_CASE("constructors") SECTION("integer literal with ull suffix") { json j(42ull); - CHECK(j.type() == json::value_t::number_integer); - CHECK(j == j_reference); + CHECK(j.type() == json::value_t::number_unsigned); + CHECK(j == j_unsigned_reference); } } @@ -830,6 +839,22 @@ TEST_CASE("constructors") } } + SECTION("number (unsigned)") + { + SECTION("explicit") + { + std::initializer_list l = {json(1u)}; + json j(l); + CHECK(j.type() == json::value_t::array); + } + + SECTION("implicit") + { + json j {1u}; + CHECK(j.type() == json::value_t::array); + } + } + SECTION("number (floating-point)") { SECTION("explicit") @@ -851,14 +876,14 @@ TEST_CASE("constructors") { SECTION("explicit") { - std::initializer_list l = {1, 42.23, true, nullptr, json::object_t(), json::array_t()}; + std::initializer_list l = {1, 1u, 42.23, true, nullptr, json::object_t(), json::array_t()}; json j(l); CHECK(j.type() == json::value_t::array); } SECTION("implicit") { - json j {1, 42.23, true, nullptr, json::object_t(), json::array_t()}; + json j {1, 1u, 42.23, true, nullptr, json::object_t(), json::array_t()}; CHECK(j.type() == json::value_t::array); } } @@ -867,13 +892,13 @@ TEST_CASE("constructors") { SECTION("object") { - json j { {"one", 1}, {"two", 2.2}, {"three", false} }; + json j { {"one", 1}, {"two", 1u}, {"three", 2.2}, {"four", false} }; CHECK(j.type() == json::value_t::object); } SECTION("array") { - json j { {"one", 1}, {"two", 2.2}, {"three", false}, 13 }; + json j { {"one", 1}, {"two", 1u}, {"three", 2.2}, {"four", false} , 13 }; CHECK(j.type() == json::value_t::array); } } @@ -888,14 +913,14 @@ TEST_CASE("constructors") SECTION("object") { - json j = json::object({ {"one", 1}, {"two", 2.2}, {"three", false} }); + json j = json::object({ {"one", 1}, {"two", 1u}, {"three", 2.2}, {"four", false} }); CHECK(j.type() == json::value_t::object); } SECTION("object with error") { - CHECK_THROWS_AS(json::object({ {"one", 1}, {"two", 2.2}, {"three", false}, 13 }), std::logic_error); - CHECK_THROWS_WITH(json::object({ {"one", 1}, {"two", 2.2}, {"three", false}, 13 }), + CHECK_THROWS_AS(json::object({ {"one", 1}, {"two", 1u}, {"three", 2.2}, {"four", false}, 13 }), std::logic_error); + CHECK_THROWS_WITH(json::object({ {"one", 1}, {"two", 1u}, {"three", 2.2}, {"four", false}, 13 }), "cannot create object from initializer list"); } @@ -907,7 +932,7 @@ TEST_CASE("constructors") SECTION("array") { - json j = json::array({ {"one", 1}, {"two", 2.2}, {"three", false} }); + json j = json::array({ {"one", 1}, {"two", 1u}, {"three", 2.2}, {"four", false} }); CHECK(j.type() == json::value_t::array); } } @@ -915,7 +940,7 @@ TEST_CASE("constructors") SECTION("create an array of n copies of a given value") { - json v = {1, "foo", 34.23, {1, 2, 3}, {{"A", 1}, {"B", 2}}}; + json v = {1, "foo", 34.23, {1, 2, 3}, {{"A", 1}, {"B", 2u}}}; json arr(3, v); CHECK(arr.size() == 3); for (auto& x : arr) @@ -931,12 +956,12 @@ TEST_CASE("constructors") SECTION("json(begin(), end())") { { - json jobject = {{"a", "a"}, {"b", 1}, {"c", 17}}; + json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}}; json j_new(jobject.begin(), jobject.end()); CHECK(j_new == jobject); } { - json jobject = {{"a", "a"}, {"b", 1}, {"c", 17}}; + json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}}; json j_new(jobject.cbegin(), jobject.cend()); CHECK(j_new == jobject); } @@ -945,12 +970,12 @@ TEST_CASE("constructors") SECTION("json(begin(), begin())") { { - json jobject = {{"a", "a"}, {"b", 1}, {"c", 17}}; + json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}}; json j_new(jobject.begin(), jobject.begin()); CHECK(j_new == json::object()); } { - json jobject = {{"a", "a"}, {"b", 1}, {"c", 17}}; + json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}}; json j_new(jobject.cbegin(), jobject.cbegin()); CHECK(j_new == json::object()); } @@ -958,24 +983,24 @@ TEST_CASE("constructors") SECTION("construct from subrange") { - json jobject = {{"a", "a"}, {"b", 1}, {"c", 17}, {"d", false}, {"e", true}}; + json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}, {"d", false}, {"e", true}}; json j_new(jobject.find("b"), jobject.find("e")); - CHECK(j_new == json({{"b", 1}, {"c", 17}, {"d", false}})); + CHECK(j_new == json({{"b", 1}, {"c", 17u}, {"d", false}})); } SECTION("incompatible iterators") { { - json jobject = {{"a", "a"}, {"b", 1}, {"c", 17}, {"d", false}, {"e", true}}; - json jobject2 = {{"a", "a"}, {"b", 1}, {"c", 17}}; + json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}, {"d", false}, {"e", true}}; + json jobject2 = {{"a", "a"}, {"b", 1}, {"c", 17u}}; CHECK_THROWS_AS(json(jobject.begin(), jobject2.end()), std::domain_error); CHECK_THROWS_AS(json(jobject2.begin(), jobject.end()), std::domain_error); CHECK_THROWS_WITH(json(jobject.begin(), jobject2.end()), "iterators are not compatible"); CHECK_THROWS_WITH(json(jobject2.begin(), jobject.end()), "iterators are not compatible"); } { - json jobject = {{"a", "a"}, {"b", 1}, {"c", 17}, {"d", false}, {"e", true}}; - json jobject2 = {{"a", "a"}, {"b", 1}, {"c", 17}}; + json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}, {"d", false}, {"e", true}}; + json jobject2 = {{"a", "a"}, {"b", 1}, {"c", 17u}}; CHECK_THROWS_AS(json(jobject.cbegin(), jobject2.cend()), std::domain_error); CHECK_THROWS_AS(json(jobject2.cbegin(), jobject.cend()), std::domain_error); CHECK_THROWS_WITH(json(jobject.cbegin(), jobject2.cend()), "iterators are not compatible"); @@ -1109,6 +1134,20 @@ TEST_CASE("constructors") } } + SECTION("number (unsigned)") + { + { + json j = 17u; + json j_new(j.begin(), j.end()); + CHECK(j == j_new); + } + { + json j = 17u; + json j_new(j.cbegin(), j.cend()); + CHECK(j == j_new); + } + } + SECTION("number (floating point)") { { @@ -1180,6 +1219,24 @@ TEST_CASE("constructors") } } + SECTION("number (integer)") + { + { + json j = 17u; + CHECK_THROWS_AS(json(j.end(), j.end()), std::out_of_range); + CHECK_THROWS_AS(json(j.begin(), j.begin()), std::out_of_range); + CHECK_THROWS_WITH(json(j.end(), j.end()), "iterators out of range"); + CHECK_THROWS_WITH(json(j.begin(), j.begin()), "iterators out of range"); + } + { + json j = 17u; + CHECK_THROWS_AS(json(j.cend(), j.cend()), std::out_of_range); + CHECK_THROWS_AS(json(j.cbegin(), j.cbegin()), std::out_of_range); + CHECK_THROWS_WITH(json(j.cend(), j.cend()), "iterators out of range"); + CHECK_THROWS_WITH(json(j.cbegin(), j.cbegin()), "iterators out of range"); + } + } + SECTION("number (floating point)") { { @@ -1248,6 +1305,13 @@ TEST_CASE("other constructors and destructor") CHECK(j == k); } + SECTION("number (unsigned)") + { + json j(42u); + json k(j); + CHECK(j == k); + } + SECTION("number (floating-point)") { json j(42.23); @@ -1258,7 +1322,7 @@ TEST_CASE("other constructors and destructor") SECTION("move constructor") { - json j {{"foo", "bar"}, {"baz", {1, 2, 3, 4}}, {"a", 42.23}, {"b", nullptr}}; + json j {{"foo", "bar"}, {"baz", {1, 2, 3, 4}}, {"a", 42u}, {"b", 42.23}, {"c", nullptr}}; CHECK(j.type() == json::value_t::object); json k(std::move(j)); CHECK(k.type() == json::value_t::object); @@ -1315,6 +1379,14 @@ TEST_CASE("other constructors and destructor") CHECK(j == k); } + SECTION("number (unsigned)") + { + json j(42u); + json k; + k = j; + CHECK(j == k); + } + SECTION("number (floating-point)") { json j(42.23); @@ -1334,7 +1406,7 @@ TEST_CASE("other constructors and destructor") SECTION("array") { - auto j = new json {"foo", 1, false, 23.42}; + auto j = new json {"foo", 1, 1u, false, 23.42}; delete j; } @@ -1357,6 +1429,7 @@ TEST_CASE("object inspection") CHECK(not j.is_boolean()); CHECK(not j.is_number()); CHECK(not j.is_number_integer()); + CHECK(not j.is_number_unsigned()); CHECK(not j.is_number_float()); CHECK(j.is_object()); CHECK(not j.is_array()); @@ -1368,11 +1441,12 @@ TEST_CASE("object inspection") SECTION("array") { - json j {"foo", 1, 42.23, false}; + json j {"foo", 1, 1u, 42.23, false}; CHECK(not j.is_null()); CHECK(not j.is_boolean()); CHECK(not j.is_number()); CHECK(not j.is_number_integer()); + CHECK(not j.is_number_unsigned()); CHECK(not j.is_number_float()); CHECK(not j.is_object()); CHECK(j.is_array()); @@ -1389,6 +1463,7 @@ TEST_CASE("object inspection") CHECK(not j.is_boolean()); CHECK(not j.is_number()); CHECK(not j.is_number_integer()); + CHECK(not j.is_number_unsigned()); CHECK(not j.is_number_float()); CHECK(not j.is_object()); CHECK(not j.is_array()); @@ -1405,6 +1480,7 @@ TEST_CASE("object inspection") CHECK(j.is_boolean()); CHECK(not j.is_number()); CHECK(not j.is_number_integer()); + CHECK(not j.is_number_unsigned()); CHECK(not j.is_number_float()); CHECK(not j.is_object()); CHECK(not j.is_array()); @@ -1421,6 +1497,7 @@ TEST_CASE("object inspection") CHECK(not j.is_boolean()); CHECK(not j.is_number()); CHECK(not j.is_number_integer()); + CHECK(not j.is_number_unsigned()); CHECK(not j.is_number_float()); CHECK(not j.is_object()); CHECK(not j.is_array()); @@ -1437,6 +1514,24 @@ TEST_CASE("object inspection") CHECK(not j.is_boolean()); CHECK(j.is_number()); CHECK(j.is_number_integer()); + CHECK(not j.is_number_unsigned()); + CHECK(not j.is_number_float()); + CHECK(not j.is_object()); + CHECK(not j.is_array()); + CHECK(not j.is_string()); + CHECK(not j.is_discarded()); + CHECK(j.is_primitive()); + CHECK(not j.is_structured()); + } + + SECTION("number (unsigned)") + { + json j(42u); + CHECK(not j.is_null()); + CHECK(not j.is_boolean()); + CHECK(j.is_number()); + CHECK(j.is_number_integer()); + CHECK(j.is_number_unsigned()); CHECK(not j.is_number_float()); CHECK(not j.is_object()); CHECK(not j.is_array()); @@ -1453,6 +1548,7 @@ TEST_CASE("object inspection") CHECK(not j.is_boolean()); CHECK(j.is_number()); CHECK(not j.is_number_integer()); + CHECK(not j.is_number_unsigned()); CHECK(j.is_number_float()); CHECK(not j.is_object()); CHECK(not j.is_array()); @@ -1469,6 +1565,7 @@ TEST_CASE("object inspection") CHECK(not j.is_boolean()); CHECK(not j.is_number()); CHECK(not j.is_number_integer()); + CHECK(not j.is_number_unsigned()); CHECK(not j.is_number_float()); CHECK(not j.is_object()); CHECK(not j.is_array()); @@ -1567,6 +1664,12 @@ TEST_CASE("object inspection") CHECK(j.type() == json::value_t::number_integer); } + SECTION("number (unsigned)") + { + json j = 23u; + CHECK(j.type() == json::value_t::number_unsigned); + } + SECTION("number (floating-point)") { json j = 42.23; @@ -1618,6 +1721,13 @@ TEST_CASE("object inspection") CHECK(t == j.type()); } + SECTION("number (unsigned)") + { + json j = 23u; + json::value_t t = j; + CHECK(t == j.type()); + } + SECTION("number (floating-point)") { json j = 42.23; @@ -1672,6 +1782,7 @@ TEST_CASE("value conversion") CHECK_THROWS_AS(json(json::value_t::string).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::boolean).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::number_integer).get(), std::logic_error); + CHECK_THROWS_AS(json(json::value_t::number_unsigned).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::number_float).get(), std::logic_error); CHECK_THROWS_WITH(json(json::value_t::null).get(), @@ -1684,6 +1795,8 @@ TEST_CASE("value conversion") "type must be object, but is boolean"); CHECK_THROWS_WITH(json(json::value_t::number_integer).get(), "type must be object, but is number"); + CHECK_THROWS_WITH(json(json::value_t::number_unsigned).get(), + "type must be object, but is number"); CHECK_THROWS_WITH(json(json::value_t::number_float).get(), "type must be object, but is number"); } @@ -1727,7 +1840,7 @@ TEST_CASE("value conversion") SECTION("get an array (explicit)") { - json::array_t a_reference {json(1), json(2.2), json(false), json("string"), json()}; + json::array_t a_reference {json(1), json(1u), json(2.2), json(false), json("string"), json()}; json j(a_reference); SECTION("json::array_t") @@ -1767,6 +1880,7 @@ TEST_CASE("value conversion") CHECK_THROWS_AS(json(json::value_t::string).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::boolean).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::number_integer).get(), std::logic_error); + CHECK_THROWS_AS(json(json::value_t::number_unsigned).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::number_float).get(), std::logic_error); CHECK_THROWS_WITH(json(json::value_t::null).get(), @@ -1779,6 +1893,8 @@ TEST_CASE("value conversion") "type must be array, but is boolean"); CHECK_THROWS_WITH(json(json::value_t::number_integer).get(), "type must be array, but is number"); + CHECK_THROWS_WITH(json(json::value_t::number_unsigned).get(), + "type must be array, but is number"); CHECK_THROWS_WITH(json(json::value_t::number_float).get(), "type must be array, but is number"); } @@ -1786,7 +1902,7 @@ TEST_CASE("value conversion") SECTION("get an array (implicit)") { - json::array_t a_reference {json(1), json(2.2), json(false), json("string"), json()}; + json::array_t a_reference {json(1), json(1u), json(2.2), json(false), json("string"), json()}; json j(a_reference); SECTION("json::array_t") @@ -1844,6 +1960,7 @@ TEST_CASE("value conversion") CHECK_THROWS_AS(json(json::value_t::array).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::boolean).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::number_integer).get(), std::logic_error); + CHECK_THROWS_AS(json(json::value_t::number_unsigned).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::number_float).get(), std::logic_error); CHECK_THROWS_WITH(json(json::value_t::null).get(), @@ -1856,6 +1973,8 @@ TEST_CASE("value conversion") "type must be string, but is boolean"); CHECK_THROWS_WITH(json(json::value_t::number_integer).get(), "type must be string, but is number"); + CHECK_THROWS_WITH(json(json::value_t::number_unsigned).get(), + "type must be string, but is number"); CHECK_THROWS_WITH(json(json::value_t::number_float).get(), "type must be string, but is number"); } @@ -1903,6 +2022,7 @@ TEST_CASE("value conversion") CHECK_THROWS_AS(json(json::value_t::array).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::string).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::number_integer).get(), std::logic_error); + CHECK_THROWS_AS(json(json::value_t::number_unsigned).get(), std::logic_error); CHECK_THROWS_AS(json(json::value_t::number_float).get(), std::logic_error); CHECK_THROWS_WITH(json(json::value_t::null).get(), @@ -1915,6 +2035,8 @@ TEST_CASE("value conversion") "type must be boolean, but is string"); CHECK_THROWS_WITH(json(json::value_t::number_integer).get(), "type must be boolean, but is number"); + CHECK_THROWS_WITH(json(json::value_t::number_unsigned).get(), + "type must be boolean, but is number"); CHECK_THROWS_WITH(json(json::value_t::number_float).get(), "type must be boolean, but is number"); } @@ -1942,6 +2064,8 @@ TEST_CASE("value conversion") { json::number_integer_t n_reference {42}; json j(n_reference); + json::number_unsigned_t n_unsigned_reference {42u}; + json j_unsigned(n_unsigned_reference); SECTION("number_integer_t") { @@ -1949,6 +2073,12 @@ TEST_CASE("value conversion") CHECK(json(n) == j); } + SECTION("number_unsigned_t") + { + json::number_unsigned_t n = j_unsigned.get(); + CHECK(json(n) == j_unsigned); + } + SECTION("short") { short n = j.get(); @@ -2161,6 +2291,7 @@ TEST_CASE("value conversion") "type must be number, but is boolean"); CHECK_NOTHROW(json(json::value_t::number_float).get()); + CHECK_NOTHROW(json(json::value_t::number_float).get()); } } @@ -2168,12 +2299,20 @@ TEST_CASE("value conversion") { json::number_integer_t n_reference {42}; json j(n_reference); + json::number_unsigned_t n_unsigned_reference {42u}; + json j_unsigned(n_unsigned_reference); SECTION("number_integer_t") { json::number_integer_t n = j.get(); CHECK(json(n) == j); } + + SECTION("number_unsigned_t") + { + json::number_unsigned_t n = j_unsigned.get(); + CHECK(json(n) == j_unsigned); + } SECTION("short") { @@ -2183,8 +2322,8 @@ TEST_CASE("value conversion") SECTION("unsigned short") { - unsigned short n = j; - CHECK(json(n) == j); + unsigned short n = j_unsigned; + CHECK(json(n) == j_unsigned); } SECTION("int") @@ -2195,8 +2334,8 @@ TEST_CASE("value conversion") SECTION("unsigned int") { - unsigned int n = j; - CHECK(json(n) == j); + unsigned int n = j_unsigned; + CHECK(json(n) == j_unsigned); } SECTION("long") @@ -2207,8 +2346,8 @@ TEST_CASE("value conversion") SECTION("unsigned long") { - unsigned long n = j; - CHECK(json(n) == j); + unsigned long n = j_unsigned; + CHECK(json(n) == j_unsigned); } SECTION("long long") @@ -2219,8 +2358,8 @@ TEST_CASE("value conversion") SECTION("unsigned long long") { - unsigned long long n = j; - CHECK(json(n) == j); + unsigned long long n = j_unsigned; + CHECK(json(n) == j_unsigned); } SECTION("int8_t") @@ -2297,74 +2436,74 @@ TEST_CASE("value conversion") SECTION("uint8_t") { - uint8_t n = j; - CHECK(json(n) == j); + uint8_t n = j_unsigned; + CHECK(json(n) == j_unsigned); } SECTION("uint16_t") { - uint16_t n = j; - CHECK(json(n) == j); + uint16_t n = j_unsigned; + CHECK(json(n) == j_unsigned); } SECTION("uint32_t") { - uint32_t n = j; - CHECK(json(n) == j); + uint32_t n = j_unsigned; + CHECK(json(n) == j_unsigned); } SECTION("uint64_t") { - uint64_t n = j; - CHECK(json(n) == j); + uint64_t n = j_unsigned; + CHECK(json(n) == j_unsigned); } SECTION("uint8_fast_t") { - uint_fast8_t n = j; - CHECK(json(n) == j); + uint_fast8_t n = j_unsigned; + CHECK(json(n) == j_unsigned); } SECTION("uint16_fast_t") { - uint_fast16_t n = j; - CHECK(json(n) == j); + uint_fast16_t n = j_unsigned; + CHECK(json(n) == j_unsigned); } SECTION("uint32_fast_t") { - uint_fast32_t n = j; - CHECK(json(n) == j); + uint_fast32_t n = j_unsigned; + CHECK(json(n) == j_unsigned); } SECTION("uint64_fast_t") { - uint_fast64_t n = j; - CHECK(json(n) == j); + uint_fast64_t n = j_unsigned; + CHECK(json(n) == j_unsigned); } SECTION("uint8_least_t") { - uint_least8_t n = j; - CHECK(json(n) == j); + uint_least8_t n = j_unsigned; + CHECK(json(n) == j_unsigned); } SECTION("uint16_least_t") { - uint_least16_t n = j; - CHECK(json(n) == j); + uint_least16_t n = j_unsigned; + CHECK(json(n) == j_unsigned); } SECTION("uint32_least_t") { - uint_least32_t n = j; - CHECK(json(n) == j); + uint_least32_t n = j_unsigned; + CHECK(json(n) == j_unsigned); } SECTION("uint64_least_t") { - uint_least64_t n = j; - CHECK(json(n) == j); + uint_least64_t n = j_unsigned; + CHECK(json(n) == j_unsigned); } } @@ -2411,6 +2550,7 @@ TEST_CASE("value conversion") "type must be number, but is boolean"); CHECK_NOTHROW(json(json::value_t::number_integer).get()); + CHECK_NOTHROW(json(json::value_t::number_unsigned).get()); } } @@ -2443,43 +2583,48 @@ TEST_CASE("value conversion") SECTION("object-like STL containers") { json j1 = {{"one", 1}, {"two", 2}, {"three", 3}}; - json j2 = {{"one", 1.1}, {"two", 2.2}, {"three", 3.3}}; - json j3 = {{"one", true}, {"two", false}, {"three", true}}; - json j4 = {{"one", "eins"}, {"two", "zwei"}, {"three", "drei"}}; + json j2 = {{"one", 1u}, {"two", 2u}, {"three", 3u}}; + json j3 = {{"one", 1.1}, {"two", 2.2}, {"three", 3.3}}; + json j4 = {{"one", true}, {"two", false}, {"three", true}}; + json j5 = {{"one", "eins"}, {"two", "zwei"}, {"three", "drei"}}; SECTION("std::map") { auto m1 = j1.get>(); - auto m2 = j2.get>(); - auto m3 = j3.get>(); - //auto m4 = j4.get>(); + auto m2 = j2.get>(); + auto m3 = j3.get>(); + auto m4 = j4.get>(); + //auto m5 = j5.get>(); } SECTION("std::unordered_map") { auto m1 = j1.get>(); - auto m2 = j2.get>(); - auto m3 = j3.get>(); - //auto m4 = j4.get>(); - //CHECK(m4["one"] == "eins"); + auto m2 = j2.get>(); + auto m3 = j3.get>(); + auto m4 = j4.get>(); + //auto m5 = j5.get>(); + //CHECK(m5["one"] == "eins"); } SECTION("std::multimap") { auto m1 = j1.get>(); - auto m2 = j2.get>(); - auto m3 = j3.get>(); - //auto m4 = j4.get>(); - //CHECK(m4["one"] == "eins"); + auto m2 = j2.get>(); + auto m3 = j3.get>(); + auto m4 = j4.get>(); + //auto m5 = j5.get>(); + //CHECK(m5["one"] == "eins"); } SECTION("std::unordered_multimap") { auto m1 = j1.get>(); - auto m2 = j2.get>(); - auto m3 = j3.get>(); - //auto m4 = j4.get>(); - //CHECK(m4["one"] == "eins"); + auto m2 = j2.get>(); + auto m3 = j3.get>(); + auto m4 = j4.get>(); + //auto m5 = j5.get>(); + //CHECK(m5["one"] == "eins"); } SECTION("exception in case of a non-object type") @@ -2492,56 +2637,63 @@ TEST_CASE("value conversion") SECTION("array-like STL containers") { json j1 = {1, 2, 3, 4}; - json j2 = {1.2, 2.3, 3.4, 4.5}; - json j3 = {true, false, true}; - json j4 = {"one", "two", "three"}; + json j2 = {1u, 2u, 3u, 4u}; + json j3 = {1.2, 2.3, 3.4, 4.5}; + json j4 = {true, false, true}; + json j5 = {"one", "two", "three"}; SECTION("std::list") { auto m1 = j1.get>(); - auto m2 = j2.get>(); - auto m3 = j3.get>(); - auto m4 = j4.get>(); + auto m2 = j2.get>(); + auto m3 = j3.get>(); + auto m4 = j4.get>(); + auto m5 = j5.get>(); } //SECTION("std::forward_list") //{ // auto m1 = j1.get>(); - // auto m2 = j2.get>(); - // auto m3 = j3.get>(); - // auto m4 = j4.get>(); + // auto m2 = j2.get>(); + // auto m3 = j3.get>(); + // auto m4 = j4.get>(); + // auto m5 = j5.get>(); //} SECTION("std::vector") { auto m1 = j1.get>(); - auto m2 = j2.get>(); - auto m3 = j3.get>(); - auto m4 = j4.get>(); + auto m2 = j2.get>(); + auto m3 = j3.get>(); + auto m4 = j4.get>(); + auto m5 = j5.get>(); } SECTION("std::deque") { auto m1 = j1.get>(); - auto m2 = j2.get>(); - auto m3 = j3.get>(); - auto m4 = j4.get>(); + auto m2 = j2.get>(); + auto m3 = j2.get>(); + auto m4 = j4.get>(); + auto m5 = j5.get>(); } SECTION("std::set") { auto m1 = j1.get>(); - auto m2 = j2.get>(); - auto m3 = j3.get>(); - auto m4 = j4.get>(); + auto m2 = j2.get>(); + auto m3 = j3.get>(); + auto m4 = j4.get>(); + auto m5 = j5.get>(); } SECTION("std::unordered_set") { auto m1 = j1.get>(); - auto m2 = j2.get>(); - auto m3 = j3.get>(); - auto m4 = j4.get>(); + auto m2 = j2.get>(); + auto m3 = j3.get>(); + auto m4 = j4.get>(); + auto m5 = j5.get>(); } SECTION("exception in case of a non-object type") @@ -2569,6 +2721,7 @@ TEST_CASE("pointer access") { "number", { {"integer", 42}, + {"unsigned", 42u}, {"floating-point", 17.23} } }, @@ -2601,6 +2754,7 @@ TEST_CASE("pointer access") CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); + CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); } @@ -2628,6 +2782,7 @@ TEST_CASE("pointer access") CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); + CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); } @@ -2655,6 +2810,7 @@ TEST_CASE("pointer access") CHECK(value.get_ptr() != nullptr); CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); + CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); } @@ -2682,6 +2838,7 @@ TEST_CASE("pointer access") CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() != nullptr); CHECK(value.get_ptr() == nullptr); + CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); } @@ -2709,6 +2866,35 @@ TEST_CASE("pointer access") CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() != nullptr); + CHECK(value.get_ptr() == nullptr); + CHECK(value.get_ptr() == nullptr); + } + + SECTION("pointer access to number_unsigned_t") + { + using test_type = json::number_unsigned_t; + json value = 23u; + + // check if pointers are returned correctly + test_type* p1 = value.get_ptr(); + CHECK(p1 == value.get_ptr()); + CHECK(*p1 == value.get()); + + const test_type* p2 = value.get_ptr(); + CHECK(p1 == value.get_ptr()); + CHECK(*p2 == value.get()); + + const test_type* const p3 = value.get_ptr(); + CHECK(p1 == value.get_ptr()); + CHECK(*p3 == value.get()); + + // check if null pointers are returned correctly + CHECK(value.get_ptr() == nullptr); + CHECK(value.get_ptr() == nullptr); + CHECK(value.get_ptr() == nullptr); + CHECK(value.get_ptr() == nullptr); + CHECK(value.get_ptr() != nullptr); + CHECK(value.get_ptr() != nullptr); CHECK(value.get_ptr() == nullptr); } @@ -2736,6 +2922,7 @@ TEST_CASE("pointer access") CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() == nullptr); + CHECK(value.get_ptr() == nullptr); CHECK(value.get_ptr() != nullptr); } } @@ -2744,7 +2931,7 @@ TEST_CASE("element access") { SECTION("array") { - json j = {1, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; + json j = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; const json j_const = j; SECTION("access specified element with bounds checking") @@ -2752,29 +2939,31 @@ TEST_CASE("element access") SECTION("access within bounds") { CHECK(j.at(0) == json(1)); - CHECK(j.at(1) == json(true)); - CHECK(j.at(2) == json(nullptr)); - CHECK(j.at(3) == json("string")); - CHECK(j.at(4) == json(42.23)); - CHECK(j.at(5) == json(json::object())); - CHECK(j.at(6) == json({1, 2, 3})); + CHECK(j.at(1) == json(1u)); + CHECK(j.at(2) == json(true)); + CHECK(j.at(3) == json(nullptr)); + CHECK(j.at(4) == json("string")); + CHECK(j.at(5) == json(42.23)); + CHECK(j.at(6) == json(json::object())); + CHECK(j.at(7) == json({1, 2, 3})); CHECK(j_const.at(0) == json(1)); - CHECK(j_const.at(1) == json(true)); - CHECK(j_const.at(2) == json(nullptr)); - CHECK(j_const.at(3) == json("string")); - CHECK(j_const.at(4) == json(42.23)); - CHECK(j_const.at(5) == json(json::object())); - CHECK(j_const.at(6) == json({1, 2, 3})); + CHECK(j_const.at(1) == json(1u)); + CHECK(j_const.at(2) == json(true)); + CHECK(j_const.at(3) == json(nullptr)); + CHECK(j_const.at(4) == json("string")); + CHECK(j_const.at(5) == json(42.23)); + CHECK(j_const.at(6) == json(json::object())); + CHECK(j_const.at(7) == json({1, 2, 3})); } SECTION("access outside bounds") { - CHECK_THROWS_AS(j.at(7), std::out_of_range); - CHECK_THROWS_AS(j_const.at(7), std::out_of_range); + CHECK_THROWS_AS(j.at(8), std::out_of_range); + CHECK_THROWS_AS(j_const.at(8), std::out_of_range); - CHECK_THROWS_WITH(j.at(7), "array index 7 is out of range"); - CHECK_THROWS_WITH(j_const.at(7), "array index 7 is out of range"); + CHECK_THROWS_WITH(j.at(8), "array index 8 is out of range"); + CHECK_THROWS_WITH(j_const.at(8), "array index 8 is out of range"); } SECTION("access on non-array type") @@ -2834,6 +3023,17 @@ TEST_CASE("element access") CHECK_THROWS_WITH(j_nonarray_const.at(0), "cannot use at() with number"); } + SECTION("number (unsigned)") + { + json j_nonarray(json::value_t::number_unsigned); + const json j_nonarray_const(j_nonarray); + CHECK_THROWS_AS(j_nonarray.at(0), std::domain_error); + CHECK_THROWS_AS(j_nonarray_const.at(0), std::domain_error); + + CHECK_THROWS_WITH(j_nonarray.at(0), "cannot use at() with number"); + CHECK_THROWS_WITH(j_nonarray_const.at(0), "cannot use at() with number"); + } + SECTION("number (floating-point)") { json j_nonarray(json::value_t::number_float); @@ -2860,20 +3060,22 @@ TEST_CASE("element access") SECTION("access within bounds") { CHECK(j[0] == json(1)); - CHECK(j[1] == json(true)); - CHECK(j[2] == json(nullptr)); - CHECK(j[3] == json("string")); - CHECK(j[4] == json(42.23)); - CHECK(j[5] == json(json::object())); - CHECK(j[6] == json({1, 2, 3})); + CHECK(j[1] == json(1u)); + CHECK(j[2] == json(true)); + CHECK(j[3] == json(nullptr)); + CHECK(j[4] == json("string")); + CHECK(j[5] == json(42.23)); + CHECK(j[6] == json(json::object())); + CHECK(j[7] == json({1, 2, 3})); CHECK(j_const[0] == json(1)); - CHECK(j_const[1] == json(true)); - CHECK(j_const[2] == json(nullptr)); - CHECK(j_const[3] == json("string")); - CHECK(j_const[4] == json(42.23)); - CHECK(j_const[5] == json(json::object())); - CHECK(j_const[6] == json({1, 2, 3})); + CHECK(j_const[1] == json(1u)); + CHECK(j_const[2] == json(true)); + CHECK(j_const[3] == json(nullptr)); + CHECK(j_const[4] == json("string")); + CHECK(j_const[5] == json(42.23)); + CHECK(j_const[6] == json(json::object())); + CHECK(j_const[7] == json({1, 2, 3})); } SECTION("access on non-array type") @@ -2937,6 +3139,16 @@ TEST_CASE("element access") CHECK_THROWS_WITH(j_nonarray_const[0], "cannot use operator[] with number"); } + SECTION("number (unsigned)") + { + json j_nonarray(json::value_t::number_unsigned); + const json j_nonarray_const(j_nonarray); + CHECK_THROWS_AS(j_nonarray[0], std::domain_error); + CHECK_THROWS_AS(j_nonarray_const[0], std::domain_error); + CHECK_THROWS_WITH(j_nonarray[0], "cannot use operator[] with number"); + CHECK_THROWS_WITH(j_nonarray_const[0], "cannot use operator[] with number"); + } + SECTION("number (floating-point)") { json j_nonarray(json::value_t::number_float); @@ -2954,44 +3166,49 @@ TEST_CASE("element access") SECTION("remove element by index") { { - json jarray = {1, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; + json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; jarray.erase(0); - CHECK(jarray == json({true, nullptr, "string", 42.23, json::object(), {1, 2, 3}})); + CHECK(jarray == json({1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}})); } { - json jarray = {1, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; + json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; jarray.erase(1); - CHECK(jarray == json({1, nullptr, "string", 42.23, json::object(), {1, 2, 3}})); + CHECK(jarray == json({1, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}})); } { - json jarray = {1, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; + json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; jarray.erase(2); - CHECK(jarray == json({1, true, "string", 42.23, json::object(), {1, 2, 3}})); + CHECK(jarray == json({1, 1u, nullptr, "string", 42.23, json::object(), {1, 2, 3}})); } { - json jarray = {1, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; + json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; jarray.erase(3); - CHECK(jarray == json({1, true, nullptr, 42.23, json::object(), {1, 2, 3}})); + CHECK(jarray == json({1, 1u, true, "string", 42.23, json::object(), {1, 2, 3}})); } { - json jarray = {1, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; + json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; jarray.erase(4); - CHECK(jarray == json({1, true, nullptr, "string", json::object(), {1, 2, 3}})); + CHECK(jarray == json({1, 1u, true, nullptr, 42.23, json::object(), {1, 2, 3}})); } { - json jarray = {1, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; + json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; jarray.erase(5); - CHECK(jarray == json({1, true, nullptr, "string", 42.23, {1, 2, 3}})); + CHECK(jarray == json({1, 1u, true, nullptr, "string", json::object(), {1, 2, 3}})); } { - json jarray = {1, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; + json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; jarray.erase(6); - CHECK(jarray == json({1, true, nullptr, "string", 42.23, json::object()})); + CHECK(jarray == json({1, 1u, true, nullptr, "string", 42.23, {1, 2, 3}})); } { - json jarray = {1, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; - CHECK_THROWS_AS(jarray.erase(7), std::out_of_range); - CHECK_THROWS_WITH(jarray.erase(7), "index out of range"); + json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; + jarray.erase(7); + CHECK(jarray == json({1, 1u, true, nullptr, "string", 42.23, json::object()})); + } + { + json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; + CHECK_THROWS_AS(jarray.erase(8), std::out_of_range); + CHECK_THROWS_WITH(jarray.erase(8), "index out of range"); } } @@ -3000,29 +3217,29 @@ TEST_CASE("element access") SECTION("erase(begin())") { { - json jarray = {1, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; + json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; json::iterator it2 = jarray.erase(jarray.begin()); - CHECK(jarray == json({true, nullptr, "string", 42.23, json::object(), {1, 2, 3}})); - CHECK(*it2 == json(true)); + CHECK(jarray == json({1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}})); + CHECK(*it2 == json(1u)); } { - json jarray = {1, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; + json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; json::const_iterator it2 = jarray.erase(jarray.cbegin()); - CHECK(jarray == json({true, nullptr, "string", 42.23, json::object(), {1, 2, 3}})); - CHECK(*it2 == json(true)); + CHECK(jarray == json({1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}})); + CHECK(*it2 == json(1u)); } } SECTION("erase(begin(), end())") { { - json jarray = {1, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; + json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; json::iterator it2 = jarray.erase(jarray.begin(), jarray.end()); CHECK(jarray == json::array()); CHECK(it2 == jarray.end()); } { - json jarray = {1, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; + json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; json::const_iterator it2 = jarray.erase(jarray.cbegin(), jarray.cend()); CHECK(jarray == json::array()); CHECK(it2 == jarray.cend()); @@ -3032,15 +3249,15 @@ TEST_CASE("element access") SECTION("erase(begin(), begin())") { { - json jarray = {1, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; + json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; json::iterator it2 = jarray.erase(jarray.begin(), jarray.begin()); - CHECK(jarray == json({1, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}})); + CHECK(jarray == json({1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}})); CHECK(*it2 == json(1)); } { - json jarray = {1, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; + json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; json::const_iterator it2 = jarray.erase(jarray.cbegin(), jarray.cbegin()); - CHECK(jarray == json({1, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}})); + CHECK(jarray == json({1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}})); CHECK(*it2 == json(1)); } } @@ -3048,17 +3265,17 @@ TEST_CASE("element access") SECTION("erase at offset") { { - json jarray = {1, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; - json::iterator it = jarray.begin() + 3; + json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; + json::iterator it = jarray.begin() + 4; json::iterator it2 = jarray.erase(it); - CHECK(jarray == json({1, true, nullptr, 42.23, json::object(), {1, 2, 3}})); + CHECK(jarray == json({1, 1u, true, nullptr, 42.23, json::object(), {1, 2, 3}})); CHECK(*it2 == json(42.23)); } { - json jarray = {1, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; - json::const_iterator it = jarray.cbegin() + 3; + json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; + json::const_iterator it = jarray.cbegin() + 4; json::const_iterator it2 = jarray.erase(it); - CHECK(jarray == json({1, true, nullptr, 42.23, json::object(), {1, 2, 3}})); + CHECK(jarray == json({1, 1u, true, nullptr, 42.23, json::object(), {1, 2, 3}})); CHECK(*it2 == json(42.23)); } } @@ -3066,15 +3283,15 @@ TEST_CASE("element access") SECTION("erase subrange") { { - json jarray = {1, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; - json::iterator it2 = jarray.erase(jarray.begin() + 2, jarray.begin() + 5); - CHECK(jarray == json({1, true, json::object(), {1, 2, 3}})); + json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; + json::iterator it2 = jarray.erase(jarray.begin() + 3, jarray.begin() + 6); + CHECK(jarray == json({1, 1u, true, json::object(), {1, 2, 3}})); CHECK(*it2 == json::object()); } { - json jarray = {1, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; - json::const_iterator it2 = jarray.erase(jarray.cbegin() + 2, jarray.cbegin() + 5); - CHECK(jarray == json({1, true, json::object(), {1, 2, 3}})); + json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; + json::const_iterator it2 = jarray.erase(jarray.cbegin() + 3, jarray.cbegin() + 6); + CHECK(jarray == json({1, 1u, true, json::object(), {1, 2, 3}})); CHECK(*it2 == json::object()); } } @@ -3082,7 +3299,7 @@ TEST_CASE("element access") SECTION("different arrays") { { - json jarray = {1, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; + json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; json jarray2 = {"foo", "bar"}; CHECK_THROWS_AS(jarray.erase(jarray2.begin()), std::domain_error); CHECK_THROWS_AS(jarray.erase(jarray.begin(), jarray2.end()), std::domain_error); @@ -3098,7 +3315,7 @@ TEST_CASE("element access") "iterators do not fit current value"); } { - json jarray = {1, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; + json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; json jarray2 = {"foo", "bar"}; CHECK_THROWS_AS(jarray.erase(jarray2.cbegin()), std::domain_error); CHECK_THROWS_AS(jarray.erase(jarray.cbegin(), jarray2.cend()), std::domain_error); @@ -3153,6 +3370,13 @@ TEST_CASE("element access") CHECK_THROWS_WITH(j_nonobject.erase(0), "cannot use erase() with number"); } + SECTION("number (unsigned)") + { + json j_nonobject(json::value_t::number_unsigned); + CHECK_THROWS_AS(j_nonobject.erase(0), std::domain_error); + CHECK_THROWS_WITH(j_nonobject.erase(0), "cannot use erase() with number"); + } + SECTION("number (floating-point)") { json j_nonobject(json::value_t::number_float); @@ -3165,7 +3389,7 @@ TEST_CASE("element access") SECTION("object") { - json j = {{"integer", 1}, {"floating", 42.23}, {"null", nullptr}, {"string", "hello world"}, {"boolean", true}, {"object", json::object()}, {"array", {1, 2, 3}}}; + json j = {{"integer", 1}, {"unsigned", 1u}, {"floating", 42.23}, {"null", nullptr}, {"string", "hello world"}, {"boolean", true}, {"object", json::object()}, {"array", {1, 2, 3}}}; const json j_const = j; SECTION("access specified element with bounds checking") @@ -3173,6 +3397,7 @@ TEST_CASE("element access") SECTION("access within bounds") { CHECK(j.at("integer") == json(1)); + CHECK(j.at("unsigned") == json(1u)); CHECK(j.at("boolean") == json(true)); CHECK(j.at("null") == json(nullptr)); CHECK(j.at("string") == json("hello world")); @@ -3181,6 +3406,7 @@ TEST_CASE("element access") CHECK(j.at("array") == json({1, 2, 3})); CHECK(j_const.at("integer") == json(1)); + CHECK(j_const.at("unsigned") == json(1u)); CHECK(j_const.at("boolean") == json(true)); CHECK(j_const.at("null") == json(nullptr)); CHECK(j_const.at("string") == json("hello world")); @@ -3248,7 +3474,17 @@ TEST_CASE("element access") CHECK_THROWS_WITH(j_nonobject.at("foo"), "cannot use at() with number"); CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "cannot use at() with number"); } - + + SECTION("number (unsigned)") + { + json j_nonobject(json::value_t::number_unsigned); + const json j_nonobject_const(j_nonobject); + CHECK_THROWS_AS(j_nonobject.at("foo"), std::domain_error); + CHECK_THROWS_AS(j_nonobject_const.at("foo"), std::domain_error); + CHECK_THROWS_WITH(j_nonobject.at("foo"), "cannot use at() with number"); + CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "cannot use at() with number"); + } + SECTION("number (floating-point)") { json j_nonobject(json::value_t::number_float); @@ -3267,6 +3503,8 @@ TEST_CASE("element access") { CHECK(j.value("integer", 2) == 1); CHECK(j.value("integer", 1.0) == Approx(1)); + CHECK(j.value("unsigned", 2) == 1u); + CHECK(j.value("unsigned", 1.0) == Approx(1u)); CHECK(j.value("null", json(1)) == json()); CHECK(j.value("boolean", false) == true); CHECK(j.value("string", "bar") == "hello world"); @@ -3278,6 +3516,8 @@ TEST_CASE("element access") CHECK(j_const.value("integer", 2) == 1); CHECK(j_const.value("integer", 1.0) == Approx(1)); + CHECK(j_const.value("unsigned", 2) == 1u); + CHECK(j_const.value("unsigned", 1.0) == Approx(1u)); CHECK(j_const.value("boolean", false) == true); CHECK(j_const.value("string", "bar") == "hello world"); CHECK(j_const.value("string", std::string("bar")) == "hello world"); @@ -3290,6 +3530,7 @@ TEST_CASE("element access") SECTION("access non-existing value") { CHECK(j.value("_", 2) == 2); + CHECK(j.value("_", 2u) == 2u); CHECK(j.value("_", false) == false); CHECK(j.value("_", "bar") == "bar"); CHECK(j.value("_", 12.34) == Approx(12.34)); @@ -3297,6 +3538,7 @@ TEST_CASE("element access") CHECK(j.value("_", json({10, 100})) == json({10, 100})); CHECK(j_const.value("_", 2) == 2); + CHECK(j_const.value("_", 2u) == 2u); CHECK(j_const.value("_", false) == false); CHECK(j_const.value("_", "bar") == "bar"); CHECK(j_const.value("_", 12.34) == Approx(12.34)); @@ -3356,6 +3598,16 @@ TEST_CASE("element access") CHECK_THROWS_WITH(j_nonobject_const.value("foo", 1), "cannot use value() with number"); } + SECTION("number (unsigned)") + { + json j_nonobject(json::value_t::number_unsigned); + const json j_nonobject_const(j_nonobject); + CHECK_THROWS_AS(j_nonobject.value("foo", 1), std::domain_error); + CHECK_THROWS_AS(j_nonobject_const.value("foo", 1), std::domain_error); + CHECK_THROWS_WITH(j_nonobject.value("foo", 1), "cannot use value() with number"); + CHECK_THROWS_WITH(j_nonobject_const.value("foo", 1), "cannot use value() with number"); + } + SECTION("number (floating-point)") { json j_nonobject(json::value_t::number_float); @@ -3373,9 +3625,9 @@ TEST_CASE("element access") // "array" is the smallest key CHECK(j.front() == json({1, 2, 3})); CHECK(j_const.front() == json({1, 2, 3})); - // "string" is the largest key - CHECK(j.back() == json("hello world")); - CHECK(j_const.back() == json("hello world")); + // "unsigned" is the largest key + CHECK(j.back() == json(1u)); + CHECK(j_const.back() == json(1u)); } SECTION("access specified element") @@ -3385,6 +3637,9 @@ TEST_CASE("element access") CHECK(j["integer"] == json(1)); CHECK(j[json::object_t::key_type("integer")] == j["integer"]); + CHECK(j["unsigned"] == json(1u)); + CHECK(j[json::object_t::key_type("unsigned")] == j["unsigned"]); + CHECK(j["boolean"] == json(true)); CHECK(j[json::object_t::key_type("boolean")] == j["boolean"]); @@ -3504,6 +3759,22 @@ TEST_CASE("element access") "cannot use operator[] with number"); } + SECTION("number (unsigned)") + { + json j_nonobject(json::value_t::number_unsigned); + const json j_const_nonobject(j_nonobject); + CHECK_THROWS_AS(j_nonobject["foo"], std::domain_error); + CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], std::domain_error); + CHECK_THROWS_AS(j_const_nonobject["foo"], std::domain_error); + CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error); + CHECK_THROWS_WITH(j_nonobject["foo"], "cannot use operator[] with number"); + CHECK_THROWS_WITH(j_nonobject[json::object_t::key_type("foo")], + "cannot use operator[] with number"); + CHECK_THROWS_WITH(j_const_nonobject["foo"], "cannot use operator[] with number"); + CHECK_THROWS_WITH(j_const_nonobject[json::object_t::key_type("foo")], + "cannot use operator[] with number"); + } + SECTION("number (floating-point)") { json j_nonobject(json::value_t::number_float); @@ -3531,6 +3802,11 @@ TEST_CASE("element access") CHECK(j.find("integer") == j.end()); CHECK(j.erase("integer") == 0); + CHECK(j.find("unsigned") != j.end()); + CHECK(j.erase("unsigned") == 1); + CHECK(j.find("unsigned") == j.end()); + CHECK(j.erase("unsigned") == 0); + CHECK(j.find("boolean") != j.end()); CHECK(j.erase("boolean") == 1); CHECK(j.find("boolean") == j.end()); @@ -3567,15 +3843,15 @@ TEST_CASE("element access") SECTION("erase(begin())") { { - json jobject = {{"a", "a"}, {"b", 1}, {"c", 17}}; + json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}}; json::iterator it2 = jobject.erase(jobject.begin()); - CHECK(jobject == json({{"b", 1}, {"c", 17}})); + CHECK(jobject == json({{"b", 1}, {"c", 17u}})); CHECK(*it2 == json(1)); } { - json jobject = {{"a", "a"}, {"b", 1}, {"c", 17}}; + json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}}; json::const_iterator it2 = jobject.erase(jobject.cbegin()); - CHECK(jobject == json({{"b", 1}, {"c", 17}})); + CHECK(jobject == json({{"b", 1}, {"c", 17u}})); CHECK(*it2 == json(1)); } } @@ -3583,13 +3859,13 @@ TEST_CASE("element access") SECTION("erase(begin(), end())") { { - json jobject = {{"a", "a"}, {"b", 1}, {"c", 17}}; + json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}}; json::iterator it2 = jobject.erase(jobject.begin(), jobject.end()); CHECK(jobject == json::object()); CHECK(it2 == jobject.end()); } { - json jobject = {{"a", "a"}, {"b", 1}, {"c", 17}}; + json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}}; json::const_iterator it2 = jobject.erase(jobject.cbegin(), jobject.cend()); CHECK(jobject == json::object()); CHECK(it2 == jobject.cend()); @@ -3599,15 +3875,15 @@ TEST_CASE("element access") SECTION("erase(begin(), begin())") { { - json jobject = {{"a", "a"}, {"b", 1}, {"c", 17}}; + json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}}; json::iterator it2 = jobject.erase(jobject.begin(), jobject.begin()); - CHECK(jobject == json({{"a", "a"}, {"b", 1}, {"c", 17}})); + CHECK(jobject == json({{"a", "a"}, {"b", 1}, {"c", 17u}})); CHECK(*it2 == json("a")); } { - json jobject = {{"a", "a"}, {"b", 1}, {"c", 17}}; + json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}}; json::const_iterator it2 = jobject.erase(jobject.cbegin(), jobject.cbegin()); - CHECK(jobject == json({{"a", "a"}, {"b", 1}, {"c", 17}})); + CHECK(jobject == json({{"a", "a"}, {"b", 1}, {"c", 17u}})); CHECK(*it2 == json("a")); } } @@ -3615,17 +3891,17 @@ TEST_CASE("element access") SECTION("erase at offset") { { - json jobject = {{"a", "a"}, {"b", 1}, {"c", 17}}; + json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}}; json::iterator it = jobject.find("b"); json::iterator it2 = jobject.erase(it); - CHECK(jobject == json({{"a", "a"}, {"c", 17}})); + CHECK(jobject == json({{"a", "a"}, {"c", 17u}})); CHECK(*it2 == json(17)); } { - json jobject = {{"a", "a"}, {"b", 1}, {"c", 17}}; + json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}}; json::const_iterator it = jobject.find("b"); json::const_iterator it2 = jobject.erase(it); - CHECK(jobject == json({{"a", "a"}, {"c", 17}})); + CHECK(jobject == json({{"a", "a"}, {"c", 17u}})); CHECK(*it2 == json(17)); } } @@ -3633,13 +3909,13 @@ TEST_CASE("element access") SECTION("erase subrange") { { - json jobject = {{"a", "a"}, {"b", 1}, {"c", 17}, {"d", false}, {"e", true}}; + json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}, {"d", false}, {"e", true}}; json::iterator it2 = jobject.erase(jobject.find("b"), jobject.find("e")); CHECK(jobject == json({{"a", "a"}, {"e", true}})); CHECK(*it2 == json(true)); } { - json jobject = {{"a", "a"}, {"b", 1}, {"c", 17}, {"d", false}, {"e", true}}; + json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}, {"d", false}, {"e", true}}; json::const_iterator it2 = jobject.erase(jobject.find("b"), jobject.find("e")); CHECK(jobject == json({{"a", "a"}, {"e", true}})); CHECK(*it2 == json(true)); @@ -3649,8 +3925,8 @@ TEST_CASE("element access") SECTION("different objects") { { - json jobject = {{"a", "a"}, {"b", 1}, {"c", 17}, {"d", false}, {"e", true}}; - json jobject2 = {{"a", "a"}, {"b", 1}, {"c", 17}}; + json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}, {"d", false}, {"e", true}}; + json jobject2 = {{"a", "a"}, {"b", 1}, {"c", 17u}}; CHECK_THROWS_AS(jobject.erase(jobject2.begin()), std::domain_error); CHECK_THROWS_AS(jobject.erase(jobject.begin(), jobject2.end()), std::domain_error); CHECK_THROWS_AS(jobject.erase(jobject2.begin(), jobject.end()), std::domain_error); @@ -3664,8 +3940,8 @@ TEST_CASE("element access") "iterators do not fit current value"); } { - json jobject = {{"a", "a"}, {"b", 1}, {"c", 17}, {"d", false}, {"e", true}}; - json jobject2 = {{"a", "a"}, {"b", 1}, {"c", 17}}; + json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}, {"d", false}, {"e", true}}; + json jobject2 = {{"a", "a"}, {"b", 1}, {"c", 17u}}; CHECK_THROWS_AS(jobject.erase(jobject2.cbegin()), std::domain_error); CHECK_THROWS_AS(jobject.erase(jobject.cbegin(), jobject2.cend()), std::domain_error); CHECK_THROWS_AS(jobject.erase(jobject2.cbegin(), jobject.cend()), std::domain_error); @@ -3732,7 +4008,7 @@ TEST_CASE("element access") SECTION("existing element") { for (auto key : - {"integer", "floating", "null", "string", "boolean", "object", "array" + {"integer", "unsigned", "floating", "null", "string", "boolean", "object", "array" }) { CHECK(j.find(key) != j.end()); @@ -3798,6 +4074,14 @@ TEST_CASE("element access") CHECK(j_nonarray_const.find("foo") == j_nonarray_const.end()); } + SECTION("number (unsigned)") + { + json j_nonarray(json::value_t::number_unsigned); + const json j_nonarray_const(j_nonarray); + CHECK(j_nonarray.find("foo") == j_nonarray.end()); + CHECK(j_nonarray_const.find("foo") == j_nonarray_const.end()); + } + SECTION("number (floating-point)") { json j_nonarray(json::value_t::number_float); @@ -3813,7 +4097,7 @@ TEST_CASE("element access") SECTION("existing element") { for (auto key : - {"integer", "floating", "null", "string", "boolean", "object", "array" + {"integer", "unsigned", "floating", "null", "string", "boolean", "object", "array" }) { CHECK(j.count(key) == 1); @@ -3877,6 +4161,14 @@ TEST_CASE("element access") CHECK(j_nonobject_const.count("foo") == 0); } + SECTION("number (unsigned)") + { + json j_nonobject(json::value_t::number_unsigned); + const json j_nonobject_const(j_nonobject); + CHECK(j_nonobject.count("foo") == 0); + CHECK(j_nonobject_const.count("foo") == 0); + } + SECTION("number (floating-point)") { json j_nonobject(json::value_t::number_float); @@ -3952,6 +4244,20 @@ TEST_CASE("element access") } } + SECTION("number (unsigned)") + { + { + json j = 17u; + CHECK(j.front() == j); + CHECK(j.back() == j); + } + { + const json j = 17u; + CHECK(j.front() == j); + CHECK(j.back() == j); + } + } + SECTION("number (floating point)") { { @@ -4031,6 +4337,22 @@ TEST_CASE("element access") } } + SECTION("number (unsigned)") + { + { + json j = 17u; + json::iterator it = j.erase(j.begin()); + CHECK(j.type() == json::value_t::null); + CHECK(it == j.end()); + } + { + json j = 17u; + json::const_iterator it = j.erase(j.cbegin()); + CHECK(j.type() == json::value_t::null); + CHECK(it == j.end()); + } + } + SECTION("number (floating point)") { { @@ -4092,6 +4414,20 @@ TEST_CASE("element access") } } + SECTION("number (unsigned)") + { + { + json j = 17u; + CHECK_THROWS_AS(j.erase(j.end()), std::out_of_range); + CHECK_THROWS_WITH(j.erase(j.end()), "iterator out of range"); + } + { + json j = 17u; + CHECK_THROWS_AS(j.erase(j.cend()), std::out_of_range); + CHECK_THROWS_WITH(j.erase(j.cend()), "iterator out of range"); + } + } + SECTION("number (floating point)") { { @@ -4171,6 +4507,22 @@ TEST_CASE("element access") } } + SECTION("number (unsigned)") + { + { + json j = 17u; + json::iterator it = j.erase(j.begin(), j.end()); + CHECK(j.type() == json::value_t::null); + CHECK(it == j.end()); + } + { + json j = 17u; + json::const_iterator it = j.erase(j.cbegin(), j.cend()); + CHECK(j.type() == json::value_t::null); + CHECK(it == j.end()); + } + } + SECTION("number (floating point)") { { @@ -4244,6 +4596,24 @@ TEST_CASE("element access") } } + SECTION("number (unsigned)") + { + { + json j = 17u; + CHECK_THROWS_AS(j.erase(j.end(), j.end()), std::out_of_range); + CHECK_THROWS_AS(j.erase(j.begin(), j.begin()), std::out_of_range); + CHECK_THROWS_WITH(j.erase(j.end(), j.end()), "iterators out of range"); + CHECK_THROWS_WITH(j.erase(j.begin(), j.begin()), "iterators out of range"); + } + { + json j = 17u; + CHECK_THROWS_AS(j.erase(j.cend(), j.cend()), std::out_of_range); + CHECK_THROWS_AS(j.erase(j.cbegin(), j.cbegin()), std::out_of_range); + CHECK_THROWS_WITH(j.erase(j.cend(), j.cend()), "iterators out of range"); + CHECK_THROWS_WITH(j.erase(j.cbegin(), j.cbegin()), "iterators out of range"); + } + } + SECTION("number (floating point)") { { @@ -5260,6 +5630,210 @@ TEST_CASE("iterators") } } + SECTION("number (unsigned)") + { + json j = 23u; + json j_const(j); + + SECTION("json + begin/end") + { + json::iterator it = j.begin(); + CHECK(it != j.end()); + CHECK(*it == j); + + it++; + CHECK(it != j.begin()); + CHECK(it == j.end()); + + it--; + CHECK(it == j.begin()); + CHECK(it != j.end()); + CHECK(*it == j); + + ++it; + CHECK(it != j.begin()); + CHECK(it == j.end()); + + --it; + CHECK(it == j.begin()); + CHECK(it != j.end()); + CHECK(*it == j); + } + + SECTION("const json + begin/end") + { + json::const_iterator it = j_const.begin(); + CHECK(it != j_const.end()); + CHECK(*it == j_const); + + it++; + CHECK(it != j_const.begin()); + CHECK(it == j_const.end()); + + it--; + CHECK(it == j_const.begin()); + CHECK(it != j_const.end()); + CHECK(*it == j_const); + + ++it; + CHECK(it != j_const.begin()); + CHECK(it == j_const.end()); + + --it; + CHECK(it == j_const.begin()); + CHECK(it != j_const.end()); + CHECK(*it == j_const); + } + + SECTION("json + cbegin/cend") + { + json::const_iterator it = j.cbegin(); + CHECK(it != j.cend()); + CHECK(*it == j); + + it++; + CHECK(it != j.cbegin()); + CHECK(it == j.cend()); + + it--; + CHECK(it == j.cbegin()); + CHECK(it != j.cend()); + CHECK(*it == j); + + ++it; + CHECK(it != j.cbegin()); + CHECK(it == j.cend()); + + --it; + CHECK(it == j.cbegin()); + CHECK(it != j.cend()); + CHECK(*it == j); + } + + SECTION("const json + cbegin/cend") + { + json::const_iterator it = j_const.cbegin(); + CHECK(it != j_const.cend()); + CHECK(*it == j_const); + + it++; + CHECK(it != j_const.cbegin()); + CHECK(it == j_const.cend()); + + it--; + CHECK(it == j_const.cbegin()); + CHECK(it != j_const.cend()); + CHECK(*it == j_const); + + ++it; + CHECK(it != j_const.cbegin()); + CHECK(it == j_const.cend()); + + --it; + CHECK(it == j_const.cbegin()); + CHECK(it != j_const.cend()); + CHECK(*it == j_const); + } + + SECTION("json + rbegin/rend") + { + json::reverse_iterator it = j.rbegin(); + CHECK(it != j.rend()); + CHECK(*it == j); + + it++; + CHECK(it != j.rbegin()); + CHECK(it == j.rend()); + + it--; + CHECK(it == j.rbegin()); + CHECK(it != j.rend()); + CHECK(*it == j); + + ++it; + CHECK(it != j.rbegin()); + CHECK(it == j.rend()); + + --it; + CHECK(it == j.rbegin()); + CHECK(it != j.rend()); + CHECK(*it == j); + } + + SECTION("json + crbegin/crend") + { + json::const_reverse_iterator it = j.crbegin(); + CHECK(it != j.crend()); + CHECK(*it == j); + + it++; + CHECK(it != j.crbegin()); + CHECK(it == j.crend()); + + it--; + CHECK(it == j.crbegin()); + CHECK(it != j.crend()); + CHECK(*it == j); + + ++it; + CHECK(it != j.crbegin()); + CHECK(it == j.crend()); + + --it; + CHECK(it == j.crbegin()); + CHECK(it != j.crend()); + CHECK(*it == j); + } + + SECTION("const json + crbegin/crend") + { + json::const_reverse_iterator it = j_const.crbegin(); + CHECK(it != j_const.crend()); + CHECK(*it == j_const); + + it++; + CHECK(it != j_const.crbegin()); + CHECK(it == j_const.crend()); + + it--; + CHECK(it == j_const.crbegin()); + CHECK(it != j_const.crend()); + CHECK(*it == j_const); + + ++it; + CHECK(it != j_const.crbegin()); + CHECK(it == j_const.crend()); + + --it; + CHECK(it == j_const.crbegin()); + CHECK(it != j_const.crend()); + CHECK(*it == j_const); + } + + SECTION("key/value") + { + auto it = j.begin(); + auto cit = j_const.cbegin(); + CHECK_THROWS_AS(it.key(), std::domain_error); + CHECK_THROWS_WITH(it.key(), "cannot use key() for non-object iterators"); + CHECK(it.value() == json(23)); + CHECK_THROWS_AS(cit.key(), std::domain_error); + CHECK_THROWS_WITH(cit.key(), "cannot use key() for non-object iterators"); + CHECK(cit.value() == json(23)); + + auto rit = j.rend(); + auto crit = j.crend(); + CHECK_THROWS_AS(rit.key(), std::domain_error); + CHECK_THROWS_AS(rit.value(), std::out_of_range); + CHECK_THROWS_AS(crit.key(), std::domain_error); + CHECK_THROWS_AS(crit.value(), std::out_of_range); + CHECK_THROWS_WITH(rit.key(), "cannot use key() for non-object iterators"); + CHECK_THROWS_WITH(rit.value(), "cannot get value"); + CHECK_THROWS_WITH(crit.key(), "cannot use key() for non-object iterators"); + CHECK_THROWS_WITH(crit.value(), "cannot get value"); + } + } + SECTION("number (float)") { json j = 23.42; @@ -5543,7 +6117,7 @@ TEST_CASE("iterators") SECTION("iterator comparisons") { - json j_values = {nullptr, true, 42, 23.23, {{"one", 1}, {"two", 2}}, {1, 2, 3, 4, 5}, "Hello, world"}; + json j_values = {nullptr, true, 42, 42u, 23.23, {{"one", 1}, {"two", 2}}, {1, 2, 3, 4, 5}, "Hello, world"}; for (json& j : j_values) { @@ -5962,7 +6536,7 @@ TEST_CASE("iterators") SECTION("reverse iterator comparisons") { - json j_values = {nullptr, true, 42, 23.23, {{"one", 1}, {"two", 2}}, {1, 2, 3, 4, 5}, "Hello, world"}; + json j_values = {nullptr, true, 42, 42u, 23.23, {{"one", 1}, {"two", 2}}, {1, 2, 3, 4, 5}, "Hello, world"}; for (json& j : j_values) { @@ -6516,6 +7090,24 @@ TEST_CASE("capacity") } } + SECTION("number (unsigned)") + { + json j = 23u; + json j_const(j); + + SECTION("result of empty") + { + CHECK(j.empty() == false); + CHECK(j_const.empty() == false); + } + + SECTION("definition of empty") + { + CHECK(j.begin() != j.end()); + CHECK(j_const.begin() != j_const.end()); + } + } + SECTION("number (float)") { json j = 23.42; @@ -6701,6 +7293,26 @@ TEST_CASE("capacity") } } + SECTION("number (unsigned)") + { + json j = 23u; + json j_const(j); + + SECTION("result of size") + { + CHECK(j.size() == 1); + CHECK(j_const.size() == 1); + } + + SECTION("definition of size") + { + CHECK(std::distance(j.begin(), j.end()) == j.size()); + CHECK(std::distance(j_const.begin(), j_const.end()) == j_const.size()); + CHECK(std::distance(j.rbegin(), j.rend()) == j.size()); + CHECK(std::distance(j_const.crbegin(), j_const.crend()) == j_const.size()); + } + } + SECTION("number (float)") { json j = 23.42; @@ -6834,6 +7446,18 @@ TEST_CASE("capacity") } } + SECTION("number (unsigned)") + { + json j = 23u; + json j_const(j); + + SECTION("result of max_size") + { + CHECK(j.max_size() == 1); + CHECK(j_const.max_size() == 1); + } + } + SECTION("number (float)") { json j = 23.42; @@ -6930,6 +7554,14 @@ TEST_CASE("modifiers") CHECK(j == json(json::value_t::number_integer)); } + SECTION("number (unsigned)") + { + json j = 23u; + + j.clear(); + CHECK(j == json(json::value_t::number_integer)); + } + SECTION("number (float)") { json j = 23.42; @@ -7470,6 +8102,7 @@ TEST_CASE("lexicographical comparison operators") json::value_t::null, json::value_t::boolean, json::value_t::number_integer, + json::value_t::number_unsigned, json::value_t::number_float, json::value_t::object, json::value_t::array, @@ -7480,13 +8113,14 @@ TEST_CASE("lexicographical comparison operators") { std::vector> expected = { - {false, true, true, true, true, true, true}, - {false, false, true, true, true, true, true}, - {false, false, false, false, true, true, true}, - {false, false, false, false, true, true, true}, - {false, false, false, false, false, true, true}, - {false, false, false, false, false, false, true}, - {false, false, false, false, false, false, false} + {false, true, true, true, true, true, true, true}, + {false, false, true, true, true, true, true, true}, + {false, false, false, false, false, true, true, true}, + {false, false, false, false, false, true, true, true}, + {false, false, false, false, false, true, true, true}, + {false, false, false, false, false, false, true, true}, + {false, false, false, false, false, false, false, true}, + {false, false, false, false, false, false, false, false} }; for (size_t i = 0; i < j_types.size(); ++i) @@ -7508,6 +8142,7 @@ TEST_CASE("lexicographical comparison operators") { nullptr, nullptr, 17, 42, + 8u, 13u, 3.14159, 23.42, "foo", "bar", true, false, @@ -7519,26 +8154,30 @@ TEST_CASE("lexicographical comparison operators") { std::vector> expected = { - {true, true, false, false, false, false, false, false, false, false, false, false, false, false}, - {true, true, false, false, false, false, false, false, false, false, false, false, false, false}, - {false, false, true, false, false, false, false, false, false, false, false, false, false, false}, - {false, false, false, true, false, false, false, false, false, false, false, false, false, false}, - {false, false, false, false, true, false, false, false, false, false, false, false, false, false}, - {false, false, false, false, false, true, false, false, false, false, false, false, false, false}, - {false, false, false, false, false, false, true, false, false, false, false, false, false, false}, - {false, false, false, false, false, false, false, true, false, false, false, false, false, false}, - {false, false, false, false, false, false, false, false, true, false, false, false, false, false}, - {false, false, false, false, false, false, false, false, false, true, false, false, false, false}, - {false, false, false, false, false, false, false, false, false, false, true, false, false, false}, - {false, false, false, false, false, false, false, false, false, false, false, true, false, false}, - {false, false, false, false, false, false, false, false, false, false, false, false, true, false}, - {false, false, false, false, false, false, false, false, false, false, false, false, false, true} + {true, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false}, + {true, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false}, + {false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false}, + {false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false}, + {false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false}, + {false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false}, + {false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false}, + {false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false}, + {false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false}, + {false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false}, + {false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false}, + {false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false}, + {false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false}, + {false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false}, + {false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false}, + {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true} }; for (size_t i = 0; i < j_values.size(); ++i) { for (size_t j = 0; j < j_values.size(); ++j) { + CAPTURE(i); + CAPTURE(j); // check precomputed values CHECK( (j_values[i] == j_values[j]) == expected[i][j] ); } @@ -7565,6 +8204,8 @@ TEST_CASE("lexicographical comparison operators") { for (size_t j = 0; j < j_values.size(); ++j) { + CAPTURE(i); + CAPTURE(j); // check definition CHECK( (j_values[i] != j_values[j]) == not(j_values[i] == j_values[j]) ); } @@ -7582,26 +8223,30 @@ TEST_CASE("lexicographical comparison operators") { std::vector> expected = { - {false, false, true, true, true, true, true, true, true, true, true, true, true, true}, - {false, false, true, true, true, true, true, true, true, true, true, true, true, true}, - {false, false, false, true, false, true, true, true, false, false, true, true, true, true}, - {false, false, false, false, false, false, true, true, false, false, true, true, true, true}, - {false, false, true, true, false, true, true, true, false, false, true, true, true, true}, - {false, false, false, true, false, false, true, true, false, false, true, true, true, true}, - {false, false, false, false, false, false, false, false, false, false, false, false, false, false}, - {false, false, false, false, false, false, true, false, false, false, false, false, false, false}, - {false, false, true, true, true, true, true, true, false, false, true, true, true, true}, - {false, false, true, true, true, true, true, true, true, false, true, true, true, true}, - {false, false, false, false, false, false, true, true, false, false, false, true, false, false}, - {false, false, false, false, false, false, true, true, false, false, false, false, false, false}, - {false, false, false, false, false, false, true, true, false, false, true, true, false, false}, - {false, false, false, false, false, false, true, true, false, false, true, true, true, false} + {false, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true}, + {false, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true}, + {false, false, false, true, false, false, false, true, true, true, false, false, true, true, true, true}, + {false, false, false, false, false, false, false, false, true, true, false, false, true, true, true, true}, + {false, false, true, true, false, true, false, true, true, true, false, false, true, true, true, true}, + {false, false, true, true, false, false, false, true, true, true, false, false, true, true, true, true}, + {false, false, true, true, true, true, false, true, true, true, false, false, true, true, true, true}, + {false, false, false, true, false, false, false, false, true, true, false, false, true, true, true, true}, + {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false}, + {false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false}, + {false, false, true, true, true, true, true, true, true, true, false, false, true, true, true, true}, + {false, false, true, true, true, true, true, true, true, true, true, false, true, true, true, true}, + {false, false, false, false, false, false, false, false, true, true, false, false, false, true, false, false}, + {false, false, false, false, false, false, false, false, true, true, false, false, false, false, false, false}, + {false, false, false, false, false, false, false, false, true, true, false, false, true, true, false, false}, + {false, false, false, false, false, false, false, false, true, true, false, false, true, true, true, false} }; for (size_t i = 0; i < j_values.size(); ++i) { for (size_t j = 0; j < j_values.size(); ++j) { + CAPTURE(i); + CAPTURE(j); // check precomputed values CHECK( (j_values[i] < j_values[j]) == expected[i][j] ); } @@ -7611,6 +8256,7 @@ TEST_CASE("lexicographical comparison operators") json j_discarded(json::value_t::discarded); for (size_t i = 0; i < j_values.size(); ++i) { + CAPTURE(i); CHECK( (j_values[i] < j_discarded) == false); CHECK( (j_discarded < j_values[i]) == false); CHECK( (j_discarded < j_discarded) == false); @@ -7623,6 +8269,8 @@ TEST_CASE("lexicographical comparison operators") { for (size_t j = 0; j < j_values.size(); ++j) { + CAPTURE(i); + CAPTURE(j); // check definition CHECK( (j_values[i] <= j_values[j]) == not(j_values[j] < j_values[i]) ); } @@ -7635,6 +8283,8 @@ TEST_CASE("lexicographical comparison operators") { for (size_t j = 0; j < j_values.size(); ++j) { + CAPTURE(i); + CAPTURE(j); // check definition CHECK( (j_values[i] > j_values[j]) == (j_values[j] < j_values[i]) ); } @@ -7647,6 +8297,8 @@ TEST_CASE("lexicographical comparison operators") { for (size_t j = 0; j < j_values.size(); ++j) { + CAPTURE(i); + CAPTURE(j); // check definition CHECK( (j_values[i] >= j_values[j]) == not(j_values[i] < j_values[j]) ); } @@ -8818,6 +9470,23 @@ TEST_CASE("parser class") // (2**53)-1 CHECK(json::parser("9007199254740991").parse().get() == 9007199254740991); } + + SECTION("over the edge cases") // issue #178 - Integer conversion to unsigned (incorrect handling of 64 bit integers) + { + // While RFC7159, Section 6 specifies a preference for support + // for ranges in range of IEEE 754-2008 binary64 (double precision) + // this does not accommodate 64 bit integers without loss of accuracy. + // As 64 bit integers are now widely used in software, it is desirable + // to expand support to to the full 64 bit (signed and unsigned) range + // i.e. -(2**63) -> (2**64)-1. + + // -(2**63) ** Note: compilers see negative literals as negated positive numbers (hence the -1)) + CHECK(json::parser("-9223372036854775808").parse().get() == -9223372036854775807-1); + // (2**63)-1 + CHECK(json::parser("9223372036854775807").parse().get() == 9223372036854775807); + // (2**64)-1 + CHECK(json::parser("18446744073709551615").parse().get() == 18446744073709551615u); + } } SECTION("floating-point")