From b429a82a1a1860b46da1a942381468b3e081c452 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Fri, 27 Jun 2014 13:55:45 +0800 Subject: [PATCH 01/19] Update readme.md Added a paragraph about the unicode features --- readme.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/readme.md b/readme.md index 9bf6a16..bebeee7 100644 --- a/readme.md +++ b/readme.md @@ -16,6 +16,8 @@ Rapidjson is a JSON parser and generator for C++. It was inspired by [rapidxml]( * Rapidjson is memory friendly. Each JSON value occupies exactly 16/20 bytes for most 32/64-bit machines (excluding text string). By default it uses a fast memory allocator, and the parser allocates memory compactly during parsing. +* Rapidjson is Unicode friendly. It supports UTF-8, UTF-16, UTF-32 (LE & BE), and their detection, validataton and transcoding internally. For example, you can read a UTF-8 file and let rapidjson transcode the JSON strings into UTF-16 into DOM. It also supports surrogates and "\u0000" (null character). + For the full features please refer to the user guide. JSON(JavaScript Object Notation) is a light-weight data exchange format. Rapidjson should be in fully compliance with RFC4627/ECMA-404. More information about JSON can be obtained at From fbf29dfc524d3aaaf42f3d9ef6a6a21286ec931c Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Fri, 27 Jun 2014 14:02:20 +0800 Subject: [PATCH 02/19] Update readme.md minor mistake --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index bebeee7..894fb44 100644 --- a/readme.md +++ b/readme.md @@ -16,7 +16,7 @@ Rapidjson is a JSON parser and generator for C++. It was inspired by [rapidxml]( * Rapidjson is memory friendly. Each JSON value occupies exactly 16/20 bytes for most 32/64-bit machines (excluding text string). By default it uses a fast memory allocator, and the parser allocates memory compactly during parsing. -* Rapidjson is Unicode friendly. It supports UTF-8, UTF-16, UTF-32 (LE & BE), and their detection, validataton and transcoding internally. For example, you can read a UTF-8 file and let rapidjson transcode the JSON strings into UTF-16 into DOM. It also supports surrogates and "\u0000" (null character). +* Rapidjson is Unicode friendly. It supports UTF-8, UTF-16, UTF-32 (LE & BE), and their detection, validataton and transcoding internally. For example, you can read a UTF-8 file and let rapidjson transcode the JSON strings into UTF-16 in the DOM. It also supports surrogates and "\u0000" (null character). For the full features please refer to the user guide. From be01d3d7cca6a0c3614778ff87e5eca4ab8fe89e Mon Sep 17 00:00:00 2001 From: "Philipp A. Hartmann" Date: Fri, 27 Jun 2014 10:26:37 +0200 Subject: [PATCH 03/19] fix build on travis-ci.org Some early returns were missing after the removal of longjmp in #22. This has led to segfaults on Linux (confirmed locally). --- include/rapidjson/reader.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h index 4a184c0..8b58c5a 100644 --- a/include/rapidjson/reader.h +++ b/include/rapidjson/reader.h @@ -243,12 +243,16 @@ public: case '[': ParseArray(is, handler); break; default: RAPIDJSON_PARSE_ERROR_NORETURN("Expect either an object or array at root", is.Tell()); } + if (HasParseError()) + goto out; + SkipWhitespace(is); if (is.Peek() != '\0') RAPIDJSON_PARSE_ERROR_NORETURN("Nothing should follow the root object or array.", is.Tell()); } + out: stack_.Clear(); return !HasParseError(); } @@ -414,6 +418,8 @@ private: if (parseFlags & kParseInsituFlag) { Ch *head = s.PutBegin(); ParseStringToStream(s, s); + if (HasParseError()) + return; size_t length = s.PutEnd(head) - 1; RAPIDJSON_ASSERT(length <= 0xFFFFFFFF); handler.String((typename TargetEncoding::Ch*)head, SizeType(length), false); @@ -421,6 +427,8 @@ private: else { StackStream stackStream(stack_); ParseStringToStream(s, stackStream); + if (HasParseError()) + return; handler.String(stack_.template Pop(stackStream.length_), stackStream.length_ - 1, true); } is = s; // Restore is From 0277ebdc3ca39b40e76fb1b9e6ad3b554a192a73 Mon Sep 17 00:00:00 2001 From: "Philipp A. Hartmann" Date: Fri, 27 Jun 2014 10:27:35 +0200 Subject: [PATCH 04/19] document.h: avoid casting away const Another instance of casting away constness via C-style cast has been missed (introduced by #20). --- include/rapidjson/document.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index 40a0442..3f21062 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -202,7 +202,7 @@ public: */ template GenericValue& CopyFrom(const GenericValue& rhs, Allocator& allocator) { - RAPIDJSON_ASSERT((void*)this != (void*)&rhs); + RAPIDJSON_ASSERT((void*)this != (void const*)&rhs); this->~GenericValue(); new (this) GenericValue(rhs,allocator); return *this; From cd144c3cfdc568278700484a4083a7b084d47dee Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Sat, 28 Jun 2014 19:44:11 +0800 Subject: [PATCH 05/19] Added a simple example and a diagram showing the process. --- build/premake4.lua | 5 +++ doc/diagram/makefile | 8 +++++ doc/diagram/simpledom.dot | 54 ++++++++++++++++++++++++++++++++ doc/diagram/simpledom.png | Bin 0 -> 23116 bytes example/simpledom/simpledom.cpp | 28 +++++++++++++++++ readme.md | 43 ++++++++++++++++++++++++- 6 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 doc/diagram/makefile create mode 100644 doc/diagram/simpledom.dot create mode 100644 doc/diagram/simpledom.png create mode 100644 example/simpledom/simpledom.cpp diff --git a/build/premake4.lua b/build/premake4.lua index b4fdf8d..28a7138 100644 --- a/build/premake4.lua +++ b/build/premake4.lua @@ -176,3 +176,8 @@ solution "example" kind "ConsoleApp" files "../example/serialize/*" setTargetObjDir("../bin") + + project "simpledom" + kind "ConsoleApp" + files "../example/simpledom/*" + setTargetObjDir("../bin") diff --git a/doc/diagram/makefile b/doc/diagram/makefile new file mode 100644 index 0000000..4699438 --- /dev/null +++ b/doc/diagram/makefile @@ -0,0 +1,8 @@ +%.pdf: %.dot + dot $< -Tpdf -o $@ + +%.png: %.dot + dot $< -Tpng -o $@ + +DOTFILES = $(basename $(wildcard *.dot)) +all: $(addsuffix .png, $(DOTFILES)) #$(addsuffix .pdf, $(DOTFILES)) diff --git a/doc/diagram/simpledom.dot b/doc/diagram/simpledom.dot new file mode 100644 index 0000000..1e9edb5 --- /dev/null +++ b/doc/diagram/simpledom.dot @@ -0,0 +1,54 @@ +digraph { + compound=true + fontname="Inconsolata, Consolas" + fontsize=10 + margin="0,0" + ranksep=0.2 + penwidth=0.5 + + node [fontname="Inconsolata, Consolas", fontsize=10, penwidth=0.5] + edge [fontname="Inconsolata, Consolas", fontsize=10, arrowhead=normal] + + { + node [shape=record, fontsize="8", margin="0.04", height=0.2, color=gray] + srcjson [label="\{|p|r|o|j|e|c|t|\"|:|\"|r|a|p|i|d|j|s|o|n|\"|,|\"|s|t|a|r|s|\"|:|1|0|\}"] + dstjson [label="\{|p|r|o|j|e|c|t|\"|:|\"|r|a|p|i|d|j|s|o|n|\"|,|\"|s|t|a|r|s|\"|:|1|1|\}"] + } + + { + node [shape="box", style="filled", fillcolor="gray95"] + Document2 [label="(Modified) Document"] + Writer + } + + subgraph cluster1 { + margin="10,10" + labeljust="left" + label = "Document" + style=filled + fillcolor=gray95 + node [shape=Mrecord, style=filled, colorscheme=spectral7] + + root [label="{object|}", fillcolor=3] + + { + project [label="{string|\"project\"}", fillcolor=5] + rapidjson [label="{string|\"rapidjson\"}", fillcolor=5] + stars [label="{string|\"stars\"}", fillcolor=5] + ten [label="{number|10}", fillcolor=6] + } + + edge [arrowhead=vee] + root -> { project, stars } + + edge [arrowhead="none"] + project -> rapidjson + stars -> ten + } + + srcjson -> root [label=" Parse()", lhead="cluster1"] + + ten -> Document2 [label=" Increase \"stars\"", ltail="cluster1" ] + Document2 -> Writer [label=" Traverse DOM by Accept()"] + Writer -> dstjson [label=" Output to StringBuffer"] +} \ No newline at end of file diff --git a/doc/diagram/simpledom.png b/doc/diagram/simpledom.png new file mode 100644 index 0000000000000000000000000000000000000000..dd9e9aef916abd5d580795a5df9fdd83a65d2181 GIT binary patch literal 23116 zcmd43by!tjw>G?0KuWs1TS`D0flY~0lG34ccPmIq2}mei(%miHAV_yeZMqx2xqY7J zocH_AdEawA*Y*DK@wSJT0a1#^?mNU(T zla=0DCFa)?SstOGp(AC+GRfCkh-G2N8^iIsS-jrY@87)((bCd-pZxpFf81QI_xtQ! z(~sSL56e%B?wUct!NDd0%b))1K`O^CIy(BHn3x!{pFzHd2`x9b3Jm8JI~^T#b>!{F z*J!QqQ&+g%vme#Z;bBZ>W@f=* zZQM;f1p+qB586V9QcG3#`BR1IXEnAjFlSI z@59%xc&9}5Jwrp%va-lGH#cA6;(q*2qQ7^_-cQQD1~*(>xD{Qa_vo7`-R6^KI+9p6i;E6lL87{||iAqQ?^Xn^oF&!FOP+vSVIa$+(7Q+fddoj@0hx3e^8=9@6W!TbJ{OB=NS7+yz za1PUFBTdbOgs3RxwMMn32~_phRi`YmFS%%GCBa8V-G@p`IS)^^e#Z`JsV(MP6y@t# z_iQyo0vjn`M(R#qai3k+WVMLGKXO`IKUOfKufnC7#%UGF2Wdg>W_E->Opg^Y}fI?4*+wVJ{j zOnffmB?aItW3GLH491HD=zwkdkHV_?+i=;_l+OewkPH54LRZMzu3{N@K0507fe-IZpe8<%>a=0|YGV4>0deexSD1goi1 z@to#2ISQTC*0U!tQe50j4KYcrQGDu_yDQeY`S~*MYnS9}*!A7hOH0|*me1f3e!TkT z_vkUk=A4E;{RZQ}cV09wViS2K@Y&)%$EODUd(pD*D7kPR$azu)>z@;g2}CFMv!1Os zoUOJd5_HPdGuFJOkZg(-`SoU=t1dqxSmtH?Gwty>7;%(yHs4I=mx^YqCHeMn81ncDHYX=ecYctg1~_^oix=T zMsaD54ihjRoSgz6Nym!L_`e?fG}nJ>NJ}Ff9UYyJ6sDy?&d$yR&so{okswo3n<=p; z|LNkEy)nu7A-1-*JT`N+I*DZ4MX3LBn1N&3Iyzwy41R@#%+y!UAf_svP6oQdOJkL5tv*mf?I=j0iu@EjUFU@zV zfC~e@85soycu(0^uT*QYv$ON!gFb!wIy;L^Osut)@_oL+)p#I*D|UhiGtwzjsK{r>Sfo449(8mFwR?5Y_`Q%>cld6t8QttBjuRchRg z5k@9Z-na2pi6s`^5(%Fb@=}Q;TZ8Mqw4Gh)l>ogM3z$T(`z*s?Z*2y^Akop$rFow3 zZO+z|bUD5p)^Hh!K7;v?nIDtUl)Lr1sA#-^j^^zU-eyRJVv&&KW6QoQU`l{|0PEe$ z%ggTe%6Vt8g;GyX@8Iw-&qZ{pYu zB;4_3J}xC?~(N7G4k*K!*02xOvOwWH0qSEubExQr~;Eq2QfufRs*{1j?Z z2j(O<>EOWbRRZS&A0Hn(d;5|4)cANpf~Rj0z=IogqJkBWJL~7?XSddef4bKHPICAQ zwdBFD?_I@cS&j89GrH@8|3Ef*KQjEoFUuM4|y zNhs8$Dw?W>M(c_@@^)uRq-a;ql|usWM}gcyYLk%rXQU4iTSK!q~en z9|JKd*_~0cvcVDs&NpfYZWJ^$(fHtL{^tXCutfR?iS(br*t7@N`z`Xi5epGy0)9zJ zWO@BmG&Gz^U$ApkS$5{?a35okl}>$dSRWwHlc%D|xCcWo{mgy^O2%*Z!dOdH6%P*; z5m;WIh!{1sc+=$C&U6KA?VXrZ&B-Kcz(e_X_Rc6;nXyRxK|-+f${3;PN=x7tA}%9n zz_Itqh>Y2IKE7CMe6TDMkwT9d36I%_VbSYXx6Z(+2#biMtK=cbk)o35jw_sd%p4pXI8BGhzPHrp)&l_nAvfN7p;61* zZwEYcsmG~Bcy;u#lqw584i3(k^?u8Jv$U9XkzUi=oQ-%s(1>1HatSKoeur=V_WK>jez|amQ3HXCmYhJnb=g*6DB`PK+WZ+`eY6g=8aIvwmm6-6{ zZZ66uoWn?;V{C10!TJ-OFDoa(Ck!u-*1%N~@sQx)fyj-dFW*HslCYu--G)$<1$yTk zC4jdnZ?pUV-NA^_`2m!78srRir!X~PuM4cs&Q6v1H}qhLz)q5(+u%}KQv(k@%8h_u zdGB(vsVF;DhaXAtK0Tn@(QN$H$NJ*4Qf!1g`GV1=9f_pdQw{943>%}_b@Nbt5Y+0SI5l`di6IOS>ijDbqq&=8WNUw!M@NQq_(p9IVyxTg(xyKg^Z z`^~4$Pc6Loa%$Abx<)2~pU*4@5S*8KZ+pO_9JDU*-6pR43sM8$J2eSr zD&Sveug((hgC_MH{4K2+D~8GImV-yS1aJD^nJixaPUBifa_!9T>68YZ+5!iDyZg}} z6pX#_?%5J|Iqv&`G#_cw?XkK~T6UqtfN?e#axbYup>) z)GZ@hy&WpH!<1dY+%Wv@z{lWyvhU!@15T>n7g!B^zUpL534Gl@O(bZDrouiqN@ROh zzW*zC+sGf288OoB!7QH?F%J^tkqSr0rmHT-6zRkk-WP{ev1Z3LNK;tn ziPE0O49-ek*7SjmqZqUI-V&Kb7c(#M^tH8Y2AI5M7he=icV9N1Xd z`LJTidN@wFztXm56@HjcqCr?)&1bgQhqy76{LGAuCSS`9myd>4R$gB6dgHVuzPBe& zXiWU4tAXcKWm0&Wt7q=4ccU=ROr^l5XZCs$b?@ZgW3WF@1w)E((VXVGJ5J13itj?t zkR};~!I0=5T!_|=5`}$pw#{|2H6aV*?&ESA4&rjMm?WYsnFsp})I{7(GpGldJxMGa z!}y_f0L!I&~(hM6e% zYpKBbWrg_1kuDmV?QUQ*2idJS=6Bxv(M6qHn)fKmgI;F- zY)H(jlH}RuJVkA^y`p!y6__gC_5S8_MlefVQ@{A#-1){fg_h?jE-sGu!6drWEoESe zGx52h)8q>vDC0@xg;KeLR9VW$NA%|QHk-Y31tFaBV{Ok}^k8aSiodUo@Mq`#h3LY- z{4n&_(1GgxEOyB_KYxF0LPAFH)DF=DB8*Ui!aoj6@LMBI8(EwMpit>nT%!;GKJ240 zG>rxZ%cA}pE>AurBy4GK{xK1kd&Ahfo{3meca``TP=Zfj^&`V3OG0aVYO>iStEB@O zUg|!?*21Egpaz?+mLdPYbBF=?Ok6zzh=1YMx%B5xn2ft3yxGqQuY+YD!%zOowa1<7 zQ<2jRv_j!)B<967kA!zY@al$~nQ%{5H;_%lTOC>G`Yi|${@J~&v)v%cmW8kN=vsnD z+JYYEc0|YE#X*Toq7sq*zQbbw5*5gfIt{Vt09C*J0p-7J(h>?hUXZOP-cTyZx z;;C5$&W|D2SGgJ`DP!4KQHbEtxT7^5W41=&)?LJC?B*5)i$?sK4$Wfs4`xG$8|Lfe zGDuWn40r$nh18ZO8s``X2M1s3@o369;g2#_Z7sylG()}RG$<-?b{O-pgHEUOPac4Q z0)pAFKm$>)zlma^1UW>x3jvQrNBx;*UHZ;%%Te@WOiaw!8t4PagSffHu{dp)O*L`6 z38v5QzSfgf;7DOp%G`cd-XC0BCZic81x=yw3kuTQ#F%}O$yu4p1|bbsDB~p}vaS!F z|Kj%u4DzOI_Ml)kB5-F&ZEdZ=mZ`qcWaMzEy9Vm#P^mn5?r(24Y>cly>vOrQBQ!P% z$?IZZYw-g|hFe}$)md04zcgXN^l*a$I=Th$Ebjb<^J7lOPT#1DMDnqw>fo4kG+8dk73n=oKtU?lLoV?ad}{pow}NrX1(6YA+|E6L`Al%{#xSeO)4 zT2m3AJwG#wkM;uZW5J|Nrq*vHyV4qesws#cIT=}MyL{7QgT0kYJ4eTuN@<#M1uz%y z--EDS+#kvKS6b`Z%-(!M5QT`xQq`nh`*&VTy4*cq3SqYoDI%U3m&f6yYx?)ml>~5S zHiQxt_9-y1t+n+*e>_KgJ>FQ6HX#=m*HnWm2cPu}9awd${=kfSp&)j1*qz6JxC_qQJ?KXzU2S6l)%kb(aYe^%Gvj7RW1(TAJ zGK^A;LNP@+3heXw4}k5O7{JEza^K`&w6(WqvuBfm0N!e*62*0Iu63@?5k8+55HLd_ z){D*LVmAkmGBPuj3)G+H_2(&7ydNxe*?ns@U5=>lds_uJrC5+%L@T|2&#*p}94Z&X zu-r+g|Fu4eL&x+a@s2=pGQF*zHVlL1kpxdwb=;ohv&#VIX{6i4?p03DWVuZQ_A85k`Oi zF0)&ffIq%&y%TuQWB@x6uxb={h}~Z*-dwCks>Dk|)q}x;M@SKN_j`;M4LhpJ0IZge&lkOL0V0=MYCT`? z%x}Mf0LEn*#I);uVW#8xYIY6|5_Wc+P-V8sJAm3`g18Z#37Yi`ZtHLu=Rw*W$8IPg z2aT{W8Kut!wV=xmla#r1rV>-B^R_yfhzDMQdJ)UyT{opK1fq~E_-=3XpE1d=-PxM) zdk!|XPbzuPAPjO&<1TcR0`8Pz-3A&qHgtGi0OEI^nVp@xE1i+@{*d5&cv5GANhzv& zFD4?QdwZWQ8PwL*g|t0c5>!-FgqQuT10bFw1sWV6PksFD+c(%+jm`W+$j#mLzDle# zl;ATMsUCKn+O#`gIsWM~PU{&S$j_f2 zA3b={L`W|rL<->c=y7RiToC-bhf>8b#j%u>ls*(_lw^RhgnR&CO2KeDzHfL&1`XtejSaiU*$%T-(-jEuArLUH?n{iV5oQ6dPqu2ibqIT5bq1JPPgO1 z=Yv`)%1|jOL$KUx0enHgp@+UyB0>kpd^4rP;S2WE5e*f!@XU??`x_EK&xn=Zzkgqs z7=hxK)~sC^9{yx!XNS}K$_ZerS|*$iKK%UoVy?xPGAb&{&e<99U{XYvo16PfOibpX zjxt_UQc@vyUvO|f+}lAx;KW+<3Qr2z4+6U7v^9z-c7O9Mj!o;Ksi`Rn3lD{mkPreQ z;xc?Kjpe;DG&Ozf>FIg8oIgq-<`V{%j;sSPOjk14ovGq? zJD_T8Y^2K{;?dF7Ewh^DrekCT9#9;jv?t2W$H&*Wh=Oe%4(2f!ZbJ)>29}m+;#lAZ zUR?+y;YIbMlGRDy628AV4vviMUTE?hskYWe_Dl0=s;;i)cR$MNz{iQohA+De;1)7- zbCJP$czTOL#{U8M!nVP|*RaunABw4>7i;nQrSAtxYU}D+hlVf^5fLx8a#FL{fgvKm z4H3-9Dr~#}U{qpvM4;wC;2Kg|HZ?V60Dw8*7{maKg}PLNDe_0I44U;s@8zp;j4j=@=Pe~ib$$kq9#q@eB(NiV@y>dp#=>XPCqungAAsh(xoy@9(!)LRnHHP`fm+wZ8@CH zp}Yj`D7_NEfM`T9gP8uTs4Y%t3S99{35|u-n6_3(+&G-zv}wHhNL6n%5r$|sQ<*pR zZmZ*M^~*zx51Ro2z5Rw~W|dyJ-Wf+6dVL zv${LUy|vc+x_XRWt#77AKYs5icHP};o&GCKQQb@XfOA`Fn%`h%<&p#(Nm5HvLIYAU zUdT}P3w|=hAou=mw4C$k;1X5`3S5vEzbs$-+Zf@Q;q=yFp z96NXXu1Je}+WrBl&8Uo~DNdTijHaG!Hz#Ud4Yp6fMQNDBn8nJO%=a0t@C!=*xK0Uu11Tv^{eDr z^5y<@2@qWOQ28iQs%A=Ql!u?*huGm$7 z?XiEDX2`Oj+jDVnMGj*>!QonKg%9=n44Qu7TZY~_DDMOC^->)h%L&2-H6z_k9?WQt zIh}3oQXzG}jqLBNe$)?w-|3H=16}*45A2jJPLA!AS8k?XIWPKO4}G=dn9Xr&d2#QI ze4?MjwKzz6KHl$YC7^ETEBQKQoD@4Xh}3%yMpS-VXir)vyb;`TUL5&oaeuNv3|kF2 zfmeHAeKWB&M|zxEl6vnfaIm!%a_Z0Zg?5c;l`M~T3c;$i-A7>E(f9FZ^UoQ%#Jn^E ztnr_++Hb9pTg~#KgvPamm+;-~x9_YE2h04a=L*(&j1Cr{xiixM6kuz z+s%Dj{%K15k03}*dqvJI(E=&9yTym0!#YUURpQ{2->pR@Yf`IhXdlZ6@sG1~_&>&c z#VxA*8UO(dt~(o&Ze^~PF=6w~Z{7@OZ3dkse_!c-w87)Dtda94KBWxdH8EsAu7b;P z)Wxgz*Kn?J{F%}I1i#15m)tim3 z23Pu3n;}{r^YuU*k<{)S`7^Uh#rp&2rV@ma@j%`nyTdcWscK7{8CULk-8bZ9yGlw2 zQzonN?>5gW)~)}H=W&5$Fp3M~bb5w0#)^3iZK-58F`y*4K;re>!l`GsHA_G2`NPTYafVFK`gieOFyqdz*i@ zneIPEkEKN(h|4W7JnfNWYcbc(ztFGUz*=<_#y*YgpPZeoEC9f3YfBcsJ=t1x3 zoOu~Z!Vl;F90 znJa0yjH9v-XOEfjZInaPD4(Q$s_3?={?$Fir*%fo22Ox?F*Tqo|2RH-+ zzAVyKBLxNni7mmSHo@Ilte76t?)J<|qTZ z&IVmnH^Y7QqOaOp?UXdKB4SGW8Q;qRW$CHCnhu;-fkNi84X`{mH2M~X~ zbLq5Dl~tuMhbt;3ydl^b4)rQuzOVTck9krG_LpHKiw!e%?-egK>fSjLT*Z>UNw=Hu zAlKvU*ZFW*vxq5YICZlYxj9!v?{Q*Nbn4NNc#QnGSw7D$5fW?b>Ams0 z>oC>U;Libv)e+ce8pL!&_up<5suHf z3`>UO+;te_f=i>9I(Yc_r0*IF;>#g7&T8F#yqQ(7 z(H|-zt$Vt?B)h-GyyiDGlELRzj{IIuc4`iw2w;)*bqLEzxJsGk%I+E!rmKi1m{SNkZwgpl##InRl(szZd@#S#qq-364 zzIM?lx)HUQXExHnO~ZTk&m|@V?V< z&F{#Vgzo@IRx&l%eYkMJEKMv=*fr+^e4t86d~Wc)!N^e!?+mN9EhYO&`+(dm_GSyl z5PO7lqN2VKUvk^^eyo^zd@wp=a0b&$U4&jqD=W66w2R_BD5Nx@ukI;g%m=;gwM)-7%^0wN|M2VoHFwAt5^H`-}6J zAX{8nSqW3Zj~bUC*B>qikp!;W7C0<#fcP$SzWT>7{GPb5_0Zt}xd4DuH?svZa zmiY1%LB_Y%`m2Ei6d&vt73L!uh*zf`kL|Tj#5xQ=H!;x1=lGOc(7~SPTAv(-Q`^XM z!!Lu}6@(VXR$}rRs;Xfi?lu_lLk5`k-CjW{*v|uAeaw)+ePhPno zWVU2Ui#jfdyn}NQ%dOf1Y${N70Jza{$q76f;!DQ9?c~BEAlblCvsBU44BO<0Xr2D? zjDdO3RT0;EJZm@JnURokSQL5fnljTeeh;MYsc^m3L|kOxXPh0Y!hmBfZ_z&{E@ry7hLZAuVC8 zuxYZ;#nBxb^ekCeN3JO}L&6h%^ByU%MdaboP*)3Li-0EV3^(-ST##av{VBE0f>L@! z2DNk}Ztz0Wb;3Iz(0*=`Ng%FDj9}7Nb&w8^jj4icP&`}Zn^!X^)Wb931R+=Uw^bJJ zjxHgfto3t#o*b050-BmGMc+-4y{fx~=S(1Kp`mHxk3XK7nQ0pz#~&8E7X}E``>$Ni zt#%Ts3gwOWS?MJG3kwwFLN3tm2=YO0eUOyAA4vEp>V1_4GUoT+et-Ywa6RATNeJMR zj#9(+Fi}42-bcd%)DJ;97Xcz%^YbA;KmQV7u)rZyh7LOkgeCAjU+WP@RX};Swkfy} zgk#uRcpw9X=gH?T*iokd3}wl7v33W3_ExdCx82>{9Y;d~`UChngr$*883;&UedK$R zCDI`WliB@HljMt-1Y}4_ZVef|rvfS}DqZoX;8%c#my0JOBaFiI3JSTPR|cBY?!6719I>09Uhp6*CWc^wq&Zy+X6W~Ohs zkZpdc5d3s{Rth=+un6RPA*d37zd~5kVPBK5`kQp26QSUABinfN!6(hX=suJnN4@B+ zFm+tdXApecQZA5BIDnymUuFeyA_5?j5Q3Cf7s-69ZX;zio&WD?C_(qgNK}yXUtnzH zemPb!4gg&tj2$>yTp;g;fciC&uv;l8P{$!XA^EgEm?*D{g#8V9pI-`LX{O4O-)Zv; z{9<%W%;83=@5{dz&%yVnMkjhk-GCY|6$ghR9Fc~CXyRaUUfO*qWDTTxD=1}9^)T=Z zH%SEYt4m8C!1RK$ENB`&J!AnAt-}-4e@lW8sIsc>%+ub~#@abKNQi)s+3bfmH$C;e#noZ~ZYB|A z65YimEq-r`Bu-$HIPKEzX@;xnZhHcZdGaygIhTlT7fW0!96Ie0y4`m4rw=^N+=%zX zQ*-Zl^y)l8v24QjZRGvk5iP7b*Z(~Sk9Y$_v9{KueL;Ca1Bx&F^o8D@v58Kz-&&$? zn}1l4+hw)}=b?AM);)CM13Y(G=|t1SuOgej=J{!A8T7L?%C@18UvRp;sf=}wv?0UR zmjm)MWOXZn&zMb*{D3bI6Z1=LTYl&M=kCdC++UYZZNrGJs>jwg2Np&soJs046eKm= zn#M37Us4>N7&At;&PoQ-{?uRCPVIRMSO?t1%6MfKr#TnCi_%N0!FLCg}D`0dyJlVaMA1SN>Qf||M3N0 zR{%nv0~kkAFpePr5g5?td@_Ia@R=wHBz}V|o4t3XX?+sqSmQ+e;>cW9zJbYEz=H4% zhtW(M<}X*6{N`AT|JYi>tDHM>_@4>Y2aj}K#SULFmP>;m)CoY!t&OE}ZniJAFPy9y zoCVaS((Sr3VoPY)sUP+-`oz?e-JD(92G3RF_?u#UaJ1eQV{EUheugwm_Myj`^>B87 zw8WRjvJ;RX)BqhMfHKJFN=D>Yt({{fLwmRK2Q@op$ zqnLcvyc;qh;YClbf==4OxmxyR(5d&l8;q#mr2Y^t6LB^3!p2LUIy0-=?nQsRFgle0 z42+85B0w&%TYHH9eP(gTvA;7d@3sv5DK{Y&RRz34=H=bBx7n`~>=|b>HfLsDKY*4n z3~znR?%zoC-n*1v&)lfBDXpmCy`FpbdWTag+I@G&dc;xZ`GCIB-KnC9e*hu-8@pf4&pq`x6{poO7TgQh87VcV2KcUFwSZ!h@W+gLL_6yxi)w+j zzN(L`pJ4<`9dgG-z8T+v^@SOEzryQ6a1NwGR*8QIxuBK0cYN@b5}n(K{>ORB5q;t9 z(X)!dbFHx)H|DgU>Gha~_=g@#6}bT8@bAe7#FJK3G&K8_F=eN%g*Gcky{4}LAmN9H z{UF}w_vL#tzYc!?M+9#L5<=c9_rDpykNSO(7xY!d@4l(m2a!I)Rmty!{q^u`*qTr^ zSwU$FvjG20y5l+0#pQ-EL+bYCNT%6Ty66tsNrV1i2gaK(-#l_jMg}t-a9xepOca>|P`^g#3p=ceI;ueMw#S&eDV=es%0vxv`uugG+)RxLz=6 zS?*XW>3?==zmu>vDW?1yY*R==UKfu~C=8kn9zy;Z$JfRZhUZo2wSzc+%o@b<v+3PwH`rKqzkZ`D@-!T`^a37-0r>RaE)HF@2Ixj~Cb{d=5^4{n>EsYMvFv@h(2 zT_kJ279Fm>DB8TKj}$kaYj$`XGpW#VFx_rvvY}jbeM&iwsoz-h_Ez(|w(;{qu^Oc0 zE0-6eDXXwG8C;*h$yEzhc6q2xZp$M}Rp~G9|MtniM?cpM>OX*xPCT9G?)QdQz&-PNvdlwO$x+UWC)=sHKbD$0 zdJWF^O*4HS9qS3s{ntdoY%woS-CN!-pV5M_tu3aV&2?)tf|0 zU!P#=PhMM)>so6%A`{yBezb02Fem@=D!p?Nw$vBP%0PO5wAP>dd(25=^MrhaRO8Jk zsH_OkkN4Kc741FuIBbBeWfHa&9BW?X|Lz#i0#C&NVhma)zU#36FZ5A-iBg-{b*^5s zzYtqEo{+5=IKGxO(M93>tJprb{vNpXnHDTs4+X=>xjCJf@Di0g1O0v{A?+Z9CtY_5 z`&?!1c*34Xs@py#too7@Rc!Dve$GDkqNeq}A*pHjK(D7R${!dyk<(}a-;VCitNObT z3mhP8P=?XSQv4@Ql6)1O%893}EuE0da*1}LAC&ugHC>4x4*j^*Bt7kwD_gv2S+!%? z%RWB)Jpsx-2mMW%n|Fa{8|Pzm-RBIe*&g0bdiQ`38XOw>Oj!*|!2Asml!!Om1AG#$ z?g+@{T#<|!PdY)msS*zujUyl&Kpz8>3*a?55FZ2=B7rFGf2z7Kj|-ZVUZ1PV-khW4 z_2(Wc+@(as*Pn53k!_h4w@wUAWI1Z)pFEp97-jVarR*LS5N`biLE!T}2V-8kR@Z=k z4izo*)t%f!-(#DQVt=7T7aTM-RZTi)6sWqtrviXzWYt0U{tpLP8~|Qg2=@g5SYq^Y ztzHk1vO<IiC#kaiYgF5)w-vIPOT&NUzEz~&G z5Z;w3z$8XQC#SDVRIP^qirgeMX)0voL_Om}6*(sOGXx_I2#8=c!6ueHZZ2ycQ4AC@OX+ z;-e=CH(QG5EORZI%vKfE9)Nm_^IpzVK;ZK04qzZ{Ve$2CVr|slQ#I69S+Q^YwMYv2 za&IacjT4zz!BgeeDDkhJqB9U(O1Ce1JK`L-2Q91XIn`CC-_6^xa*#xAcP;&<_vD%R z&f^G&ThNK-uu<&gNUZV05g`DK5SK|^2X6L>Y5bAz=|W##D?i_zc%4Xd9?@sA zO1g5l`xpW_k9$I2u)J*j`=3*f&S!Fk3Ecxx1=)m-SVvI~#0)M_Q zSw75Uv~zuS3m%*q{@}OQm>p%3#0;q$XGK9uV|j=W{1i%uQxyWp5-1@Q>O6Z}z@<@4 z9BwS5GJacG_5b#$;gYZPZIVCWcK>!R?!;Q`NR|E>Y|oI&$Z0^Puq)4XDO|sKWns!M zvVj1(Slx6#IoY*2BT?9W-CFC~o#?IiH#kG8sHl*f9P+k1sx^Pq7ld}p39xJs5fmKU zeEDDTnX`LQ`nnU8qIZf`v8r`M_BubKrgsNlb741EU8oj))L^_nOD z1amBjd7EpBIn)@3QwUbZ4#`en?`GT~X`r;%BkD>RFq|d8RZa7HmQURO{gYCcBM%;% z@t&O^7t~aInvEOXlRfLJQ$^J`$QewZRS3n8ut-TmL8yCieZ4(b1Jn*NKO)*TxFo5O z*ISmx+NI3PB}Fti-ci3Fr1mPe$dc=Nu6mN6%9*BtCFr{M_BJMbsiPNns#XliyZem0 z-^=0rw}zN;+ZO|;-HgR6ObiTZ9i6180-AC&IPFs!)bKFxYr3eZ&$7m{iC*`<>;F&C zhG|=Yz5Lnk0KqFrnq_=(skcGo9NDFAov}@wKppt2#Fdje1Eh;zMjEeR+daL7;h`Hg ziQYDEc6gcVtS$kBqztN0nUS`+ex?DM*VDGhi7j(GjvV^6WOCXu%9?4{Pc90j48^gd zs~LdGCireo~wL$&1cgKz_Owj7A zZf(V2%#iIHIeRY%o?SphuL^3cnn#C(7aQe^cGv5V;9a}yjtH`c7*>~__my6cc#x2q(ZbH6(R<_r(J){!=c2AgTuo1sVZ9H;gr6O zJEFLijzgybnhZekQi)ep0ENP`(|+rN;&I}8y~@X1%#&H{y=J3tikBBd z&we(jn_AsEB(hC{EP`u~u^L+~O;?D+tIkCT!>fhTk-;00FqZWZA26m!FpGo7;+yHiheUV8=;dNzltrTQY8ZhW@g=3snq_kidsGF`L9T*Rfz zCtPq)ccjtr4X}P>c4r-feKQW{5H%LJw;vjV+-tqpFp5+AI@-7E+_EQGFD!OlLN!4K z>-XG{mRHiI?MEnpY?d}hQthq=>`mtDo{ZD#O}}ZIo<;%5xxa>x?aAIaAz(|Z#G8Bp ze5BQ$5n6uFJM=w~+Q=KmBThW#oS=m;5(QQr^grG+(ZhPE8+LiyyiE>A{A)Xz{tF zEAHTYZZr1GtG%vDp zawBGuk&!`E$ZIn%uL3@OdVz&N$G~855*ilv2}lf4P?&4Z)62PjkB*M5g3DhEvh%qL zaImn_4s!>+0D)(sP|MEMwZu*_Msz#7eo{j#S=B!T3MDZ6(-XDQ6GdC)VIw65g9O{# z+XLTfWMPpHlIU@3@aGC3v_X~eIsqXlKUHHCFq2++T^yt{ea^UY2e$$q+X?^yrNA9w zVdz|JY=vze<>lp2eSQ6Ku8Q*VvD=r!IlBqwJ!lKPFJ}9HwweQC?QF@yM zHNlq-CqV?Y9b=iQVSI%2IqKx{{+GVGBggV$`^)V?fc#QaT2vTq52UYUp650|*%5Ck zFDEAs$a3|r`w`9F*A`*A;|W*!;2Q*3zh~x8Dvf*O*@$Lv!?ip;G;+iWC+27C!7nH6DF6NA**Z%Djs5%iuoQbpar&dj|vz%V6dpA3#RX z(cNu1&cVPSJzr7?2v8XysRuO;;aDJ$1)8!<_v3Z9t?c+xgVu*dU1J(*#}8g;YH9{- zRI8qnpnr?ZWdj&r`P*y`%850Vl@A{v;4?s57DoIG33TG^DIf;5#je<=ZNp1o8rqpbN2HEceKC3#=m`D_GovMv{(L2Uf#$&u!YeJG-r)3ER$YKx8 zmIDwfv!TM{`%8I6#cn{jg3}^T7b5?1w!ZV2KU^xoeFlD_fD#knjI!#i*u-qp3NTba zC5lN+jRXX&6+oa_n_<^)E<8MK@;nFj%0>onar*e^NaFfzx4>Hu{5w*tEA&hi3jG0) zUnqeg;MV|kK}qF20F{lq!nllqT8{EPEIAi&%r%-fTtbI zCJi)O!otD;ht4XS1JWlrO#+Bp=<~yZ!-C=C;J^dKwk3^6s8-h2s$&IBwi zZ1^lN0jbnDKeIZXR2aFCdK+kV>Tk1snKF@p*7Qi&`w9=Tw7D4!L_K50y4ov!!9B8n z?~n&{sKYK&+n<1X1n6#XZWz(4;6lLS#nws!@O5TsDHafK5s7#JHVYPbL{J#kN&>Re zw%%TppZci{tDBol_F!b7H>yT70&u~U#dtowGcf@@Jv|~IngDDiXe?XvD*&mDfvOuI z>#F!ZEL>4!fVA}(tTb?f_XQC1fx5I>=>K)^^}o~F|H~DIn|Xsb1rTq+-wW^`-chR- z>>I^oE;pA+r`cM=$`ve(G@o{m{hdbm>7S!0Q2HtnWX=@^-R{?8empv0jg`SnIl-MRc&jDeAa$B zIXOeOC+SK|K#v)iEgvtDt+F+y0mM;&LC0^m^q~{!>oe0KSs)AR1=zk;F0g+ZDyp=$ z>Z~j};1HAe?K5<=|7y3S>Y9jwR2^0gWMuK%8s!`58EfNJ8ZN=PCe6QoDTOyZ7$1KK zF*G#106k{4Di{J}Li?qkA5ksy%s3P!B>X%|mEfZy#JDcY|>#w%FAAq-Y3`~i^~3O_?$)_&h<f_ROZ z;*i3Cf2hTvyz>qF&7oi~PQGHo`;6)<9?Pa*@5J2J*2a^fQ5{)rJu{RiUxa_VRwDm& zWQOkGGt#;1CeJU;pf6+QXq0 z`!WD%2K7st!IUICGmThqBz<)5g{2k&+yR?viC&W(Y>YYi$_g$rquKnY$jo^bc)IZo zsjnhpZFoTbs;2#JSnl;}DR8?}3fw3F!;fTRTeV7$&vv1(7?k0F>R5dK3{0ry$!~SF zk|sgN^#M3iate2nV+AG6pFx1MHD(H|Q1<0ZKcEx*_RN%r{n{INii6#nMX)NC04bK_ z_GRi=et$@U+9~OC8!|v>9v^1*Ua?fG`U>uVT>z@Z2;h*I z@K6DfGac0YVAY^)0OMrz39_n;TTcGi2T&QXY#u+HDBfkTe{rV`3o!oFk4FWTFiV56 zOeC+MfH6^`9|`!u89+;~5^rn|xamNZx+g$gZjdbKEb-#S2W49a23J5G?yj|8g*!JQ z#bEk!J78JTO}*dd#~C{AAo1?^xSU(5*C8ByW49B z1PD|^Sj*VR1)V@lm|=nPkK_=VRiKd9Ag=>-j?`rpua1q2|I40Cj zpFSbwvr_UUCngR7uR%azEq?`A`X*Hf;!NiyKbYK`;4$3Gm!oD4KDUAr5)w-r8$o~^ z8(#h8%NLfGIEm@2Y=?^jLl6{b%%ns|`^7LS0y@2HlNER?z!czI*PXsn14Rp(0{YK1 zFGby&PVOyHLG8$Nm||zXLE{#!`47i6N6QTkaCsms^6TQb-`q4iodk;Y;E0I0tg}%) zuS1~EfIyN2o%2Vlf&3aszp22R1&r$o3Rr@wmOY8EY|daCGe7)dKGk`A76Qa>3e=e>n=G&wfb>iN4!d z-RXpx?}E-OK&6WY0goW`Lm@dI@P23c!Z!dBco?qo1uMb%J0llYnNIR#iGH^qA{tN1 z#>Pg@X#)LrMn)53taT=ACVxg6zbP=f`X4VKX=)R(1A_K0pow7dCSP7&o@()JapCw5 zi3;v{7)~ajLMGslr9ND=DMJncvFN`d)mrf83e>-^d1-ELhLxP}Ow-<7ZI=K;fyb`A zSDhUl!C;#v08uP>t4IfU-9^#*BP#G(n7nHsqBQ6I!Cq4LXS;7gYU@4~yahy+B^E@; z76HR0R?X3Z@YbZ^3UuJo#!5I?S>?k*LPjiJ9p2Zt`f^#1-&1z$2Z{BLAt!eE*%;Pi zH#*c3$8-`ME(ZMm${J1@6OP77KRrM|Flf|U&Y4VT5T+CSA`ESsDk?FSs3O!hhF&^2 z@vY7Zjs2URU&=fLVS*K6sfz(E>ZsP{irOA;QzAb>HXIi=jzx2FPUepnzW zfUZFx5cmUF0=H?9}fCe5k|IOE38exynJ+GlAHZ4kFy?Zl~*K>x;K&gvg?)!(PA>%US;> zG8U##{BzxAY+R$HxySXgGTG^KjLGCjuC4?}^lgY{RbPLR1C+VOVZ7}=k{w&Yt$>D>)k$; zo);-EwN8(Si1>OPl2cu+4ru<-blyP0oS&B`$HFeW(OJ%RdUCS4(iuwJ%Q(ME9NN7q z$Ddo8yaYjsYysldBJ;j+^I#puPReKV9c|#`b;_} z7q>pAXJ^t?ygWR)U|D51v+FhHj*KW18{;7(&>X*~GY5N_gUW?e3X{wp+B})R1`7at_>OLuR=j6%~%X2V)>4YfCTE zoU?H?xm9ASr1P<}`z6b5QzOK!LHDg18mXM&osg6iCai$AQTFLro+roTuoMqR(3H5M zZ?EW)5*E-TJ(Ux5KQf7UCeGc})#bF@7LYp(u_x&-A0=5Qrlgz%uV)zhqRC05>grkp z_cdT5-_s0^F9~;|K)TTaBs{h9To=M|v$T_B?=jHA!@_clie5*LEi4qr#Swt%ct_JY?ze*Q;W#`Z0#?>d z@kUuW3cU8oxY+S{{WZXDCut*v%iD+__E3Gsg$$X7jR0-Y$?>olqt1Tw_1G8yDB5n^Re-3Vdif=L1woC(4J$Qp-tp-4-7a8}Qbn zNuWe1#ved_QLU5&=|R)3wo-O>cAh(f!7Qw&%ikeBd-&xku&yKNH-H?Ro;*6L!pqBB z@PoQ#}tFV&O@LN{RI*iHNlI!sY>%0;2jBgx5mra zzz!GQhQLGxZ|2hMaclZ;*)`VW)qN0>fMijfS2~fY&$_r zh}s1qM+!`MqxH_)baE~CcMV{5B(8=*OnzNP>zG2Q#B^%y#0LilBQE#zT^HPQ?k-j_ zt12u12;$3)j*Wf2y1qXBC5gEvh)=a|zlQKa1;pFgV6Z?wtk>tv5^>VYm})loo!7$5 ztjC$3af4e}uq3@ij9lg|GD0*Uy4db#ePrn4;^SlzWf z-BnSMB4_|vQ6v^5KtPvOI)Xwd5er2@Atr9V5sh5QTK3JbiwrSutbQd2j@- ze(AT3jY9>aOKI!qjAx+{BK0Ui_FThhEOr!1ZMvXEa6A~v@Z-E$$5$wUImsTWAeAxQ z0VdWnyEh?QT5f_Uh;P7yWL`)ot+bXBM-m^-E9hbEF+_%?cePPQORWIe)@DiE-p?@Y3YqF&)q_I}xvFYhiIKRtHU<&Z`Bc6+6S}>Z16PZDVy%jl+;q^Ty+C&_%hqC%{K)e(h>j zM1+ixS7#)e2UhRjUmx8(PVxA;ux=udSqhhoRpH)HJq`~Vcp~4hPjcVVxt8v<>Y}23 zPL$*}xmyB(SD{nc@x(zQt=w;jl_e?DvKSZ`NKl3Pxdb&~32|LhCx@d=i-9-FIrVWk zDHGiwc!KdxyEX5);8zf`vBGRgiS2mX=TYbhPq5nErm#DbnEaT9F(R#_y*=r4fsVS! zaAE2gzz~c=Je0|S620ShWZF=vRNLFHAa&Wn;}tJ1h5^uN^&GGMXLmK>@%kN@^o~Wf_cu*^ zU?It~Jr{Rjy@7ZN1C>8gT6KxzRLy zZS*>YY`=m{Lf(b7JGlH=C3(MEBu5@$d^m{VYGr9@@_EaO$fLoGKE;cCEp8Q_0}@H6 ze)L93`$IlHmw~lu76v?h{CL+G*~Um(o)P>xHJ0t=r1g&QV84?dkigxhU?$tQZF>tW z3Mqgb5P9TD?oJ`lGStzo@j312IWmJV?zo!wp?_|^lgmv@@KN8W?F)=4zb=Y~L>)Z1 zS#KX;p(w~e{&jo&T;DYtD3QiwYLAS(xd01o8@w;DKsYQEzUi*Kqy7ydIPc-Z7r?WS zxW5RLJjmyHr=_PK^sVBWqJY0@E&3hN)AKS=zMbIyEmWW|w-)hwdb}V^f6v8PKdJ`7 z6VrXK*Q}6D5C$_`A#Iv8UE8!vbL29?rH1!PdcAH7#(HgvHp`FZ#=sR#P6PXsOp8Oz z8dL^YIzuarU7dYdW|iGk-Cw(5%K&G5AQBN*MjnOfx*9^rIIn~-W|2swypj@IiiZHw z@bD^{_3HJ{!KcOR8X6XEbqzWSNE)X_CkYafULeSm-~q!9t2-O`!JiW|v`WRT+U2`n zrlhl6Ji+L<1wc33IyjX%m5vCGhvws}JeXVTu~==otG|DRGI{u+T=Od9!(iUcYptxT ze%!k^j_c~|oS&1ElWeidxNHA%r>jH6#EykTM-U>+f)e1ulgAOI*XjOhz`Gfbs z1L5EqW*FrM4rT^UiZ8HL3SlgFr3=^)(R)7{-^4+_6Sy?9f0bd>fnOnC^=Gwcv z^B~B^1IQz=X zivezXnRZ|Oe|+{4rz{5Jj8rN`Jsn&>3J1Wr+&ksqL03k;z~x5#OblMnZx`RTZ}6j%s~T1qx+z)@3dGoP5Pc+rUhQHovB#=XooIQ~Fl-;^ z<4dfjaN$$wwZ(lksQV*&_r|7t+}%wm9$rv~A*d#?&(golrm-d~<`q-EWX=l=cx^o# zk}@ZR?mSGS9YmoL$q$6{H$;w)TnZu5dD$IQWnl*Q(hhhMiETj!8Ch;>sV`m}brF+c zC+q2@5;Jej-_~#_Xd2J~oeU_&R`<<}7X4#|?CL4AyW_;%%c{NP6qfkeGsC`;mT9p< zd__`m(?E22_I*4mv`N2~Y1q{hRBMKcFn$gzS}#>NwR@=e!+=7(O$EDwYt6@*4~Z$Q zwdmn4oSP-NNtfDfQv9^nJbeYTw4<%MSG&FPMpVB}fX@0a{7wMX0~bjH+GR5?h zs?-euLvPh02htdr_Go|S+UU4#GuqDwUdIA*BShT z@>0j$=&dIF1aaK8qILx0T&GKwFV)=qQBiXG+2lVWse-9iy}ysK?rt<2pjktAJ}!xu aHdIAOUahMiQGuuoVfM4NNzt)$zy1q&&@7n% literal 0 HcmV?d00001 diff --git a/example/simpledom/simpledom.cpp b/example/simpledom/simpledom.cpp new file mode 100644 index 0000000..bdcf6c8 --- /dev/null +++ b/example/simpledom/simpledom.cpp @@ -0,0 +1,28 @@ +// JSON simple example +// This example does not handle errors. + +#include "rapidjson/document.h" +#include "rapidjson/writer.h" +#include "rapidjson/stringbuffer.h" +#include + +using namespace rapidjson; + +int main() { + // 1. Parse a JSON string into DOM. + const char* json = "{\"project\":\"rapidjson\",\"stars\":10}"; + Document d; + d.Parse<0>(json); + + // 2. Modify it by DOM. + d["stars"].SetInt(d["stars"].GetInt() + 1); + + // 3. Stringify the DOM + StringBuffer buffer; + Writer writer(buffer); + d.Accept(writer); + + // Output {"project":"rapidjson","stars":10} + std::cout << buffer.GetString() << std::endl; + return 0; +} diff --git a/readme.md b/readme.md index 894fb44..18d8b95 100644 --- a/readme.md +++ b/readme.md @@ -41,9 +41,50 @@ Rapidjson is a header-only C++ library. Just copy the `rapidjson/include/rapidjs To build the tests and examples: -1. Obtain [premake4] (http://industriousone.com/premake/download). +1. Obtain [premake4](http://industriousone.com/premake/download). 2. Copy premake4 executable to rapidjson/build (or system path) 3. Run `rapidjson/build/premake.bat` on Windows, `rapidjson/build/premake.sh` on Linux or other platforms 4. On Windows, build the solution at `rapidjson/build/vs2008/` or `/vs2010/` 5. On other platforms, run GNU make at `rapidjson/build/gmake/` (e.g., `make -f test.make config=release32`, `make -f example.make config=debug32`) 6. On success, the executable are generated at `rapidjson/bin` + +## Usage at a glance + +This simple example parses a JSON string into a document (DOM), make a simple modification of the DOM, and finally stringify the DOM to a JSON string. + +```cpp +// example/simpledom/simpledom.cpp +#include "rapidjson/document.h" +#include "rapidjson/writer.h" +#include "rapidjson/stringbuffer.h" +#include + +using namespace rapidjson; + +int main() { + // 1. Parse a JSON string into DOM. + const char* json = "{\"project\":\"rapidjson\",\"stars\":10}"; + Document d; + d.Parse<0>(json); + + // 2. Modify it by DOM. + d["stars"].SetInt(d["stars"].GetInt() + 1); + + // 3. Stringify the DOM + StringBuffer buffer; + Writer writer(buffer); + d.Accept(writer); + + // Output {"project":"rapidjson","stars":10} + std::cout << buffer.GetString() << std::endl; + return 0; +} +``` + +Note that this exmample did not handle potential errors. + +The following diagram shows the process. + +[simpledom](doc/diagram/simpledom.png) + +More [examples](example/) are avaliable. From 331c4cf500abe49dc4eb15b8eece1dff8b0408a3 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Sat, 28 Jun 2014 19:47:11 +0800 Subject: [PATCH 06/19] Update readme.md Fixes image path --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 18d8b95..e5abb27 100644 --- a/readme.md +++ b/readme.md @@ -85,6 +85,6 @@ Note that this exmample did not handle potential errors. The following diagram shows the process. -[simpledom](doc/diagram/simpledom.png) +![simpledom](doc/diagram/simpledom.png?raw=true) More [examples](example/) are avaliable. From 8a959c3898773d0c6dceb84eaf71e47b45d0c6d0 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Sat, 28 Jun 2014 20:37:22 +0800 Subject: [PATCH 07/19] Fixes comment mistakes --- example/simpledom/simpledom.cpp | 2 +- readme.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/example/simpledom/simpledom.cpp b/example/simpledom/simpledom.cpp index bdcf6c8..56be032 100644 --- a/example/simpledom/simpledom.cpp +++ b/example/simpledom/simpledom.cpp @@ -22,7 +22,7 @@ int main() { Writer writer(buffer); d.Accept(writer); - // Output {"project":"rapidjson","stars":10} + // Output {"project":"rapidjson","stars":11} std::cout << buffer.GetString() << std::endl; return 0; } diff --git a/readme.md b/readme.md index e5abb27..00c83af 100644 --- a/readme.md +++ b/readme.md @@ -75,7 +75,7 @@ int main() { Writer writer(buffer); d.Accept(writer); - // Output {"project":"rapidjson","stars":10} + // Output {"project":"rapidjson","stars":11} std::cout << buffer.GetString() << std::endl; return 0; } From 6f306755d5b7503d2fb6fb88aecbcc5534babdf7 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Sun, 29 Jun 2014 14:18:33 +0800 Subject: [PATCH 08/19] Minor adjustment to simpledom example Showing the type Value and preventing member lookup twice. --- example/simpledom/simpledom.cpp | 3 ++- readme.md | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/example/simpledom/simpledom.cpp b/example/simpledom/simpledom.cpp index 56be032..de2dc66 100644 --- a/example/simpledom/simpledom.cpp +++ b/example/simpledom/simpledom.cpp @@ -15,7 +15,8 @@ int main() { d.Parse<0>(json); // 2. Modify it by DOM. - d["stars"].SetInt(d["stars"].GetInt() + 1); + Value& s = d["stars"]; + s.SetInt(s.GetInt() + 1); // 3. Stringify the DOM StringBuffer buffer; diff --git a/readme.md b/readme.md index 00c83af..e07321b 100644 --- a/readme.md +++ b/readme.md @@ -68,7 +68,8 @@ int main() { d.Parse<0>(json); // 2. Modify it by DOM. - d["stars"].SetInt(d["stars"].GetInt() + 1); + Value& s = d["stars"]; + s.SetInt(s.GetInt() + 1); // 3. Stringify the DOM StringBuffer buffer; From 1d14748bc9e180ef6a94bd137e025e7617354f99 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Sun, 29 Jun 2014 15:03:38 +0800 Subject: [PATCH 09/19] Added overloaded functions for default parseFlags Can write d.Parse(...) instead of d.Parse<0>(...) Hope to reduce strangeness and confusion for beginner. --- example/condense/condense.cpp | 2 +- example/simpledom/simpledom.cpp | 2 +- example/tutorial/tutorial.cpp | 4 ++-- include/rapidjson/document.h | 13 +++++++++++++ include/rapidjson/reader.h | 5 +++++ readme.md | 2 +- test/perftest/rapidjsontest.cpp | 14 +++++++------- test/unittest/documenttest.cpp | 4 ++-- test/unittest/jsoncheckertest.cpp | 4 ++-- 9 files changed, 34 insertions(+), 16 deletions(-) diff --git a/example/condense/condense.cpp b/example/condense/condense.cpp index 8f1da83..93da389 100644 --- a/example/condense/condense.cpp +++ b/example/condense/condense.cpp @@ -22,7 +22,7 @@ int main(int, char*[]) { Writer writer(os); // JSON reader parse from the input stream and let writer generate the output. - if (!reader.Parse<0>(is, writer)) { + if (!reader.Parse(is, writer)) { fprintf(stderr, "\nError(%u): %s\n", (unsigned)reader.GetErrorOffset(), reader.GetParseError()); return 1; } diff --git a/example/simpledom/simpledom.cpp b/example/simpledom/simpledom.cpp index de2dc66..a2c9121 100644 --- a/example/simpledom/simpledom.cpp +++ b/example/simpledom/simpledom.cpp @@ -12,7 +12,7 @@ int main() { // 1. Parse a JSON string into DOM. const char* json = "{\"project\":\"rapidjson\",\"stars\":10}"; Document d; - d.Parse<0>(json); + d.Parse(json); // 2. Modify it by DOM. Value& s = d["stars"]; diff --git a/example/tutorial/tutorial.cpp b/example/tutorial/tutorial.cpp index a765e01..592543e 100644 --- a/example/tutorial/tutorial.cpp +++ b/example/tutorial/tutorial.cpp @@ -19,14 +19,14 @@ int main(int, char*[]) { #if 0 // "normal" parsing, decode strings to new buffers. Can use other input stream via ParseStream(). - if (document.Parse<0>(json).HasParseError()) + if (document.Parse(json).HasParseError()) return 1; #else // In-situ parsing, decode strings directly in the source string. Source must be string. { char buffer[sizeof(json)]; memcpy(buffer, json, sizeof(json)); - if (document.ParseInsitu<0>(buffer).HasParseError()) + if (document.ParseInsitu(buffer).HasParseError()) return 1; } #endif diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index 3f21062..32f71de 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -818,6 +818,11 @@ public: return ParseStream(is); } + template + GenericDocument& ParseStream(InputStream& is) { + return ParseStream<0, Encoding, InputStream>(is); + } + //! Parse JSON text from a mutable string. /*! \tparam parseFlags Combination of ParseFlag. \param str Mutable zero-terminated string to be parsed. @@ -834,6 +839,10 @@ public: return ParseInsitu(str); } + GenericDocument& ParseInsitu(Ch* str) { + return ParseInsitu<0, Encoding>(str); + } + //! Parse JSON text from a read-only string. /*! \tparam parseFlags Combination of ParseFlag (must not contain kParseInsituFlag). \param str Read-only zero-terminated string to be parsed. @@ -850,6 +859,10 @@ public: return Parse(str); } + GenericDocument& Parse(const Ch* str) { + return Parse<0>(str); + } + //! Whether a parse error was occured in the last parsing. bool HasParseError() const { return parseError_ != 0; } diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h index 8b58c5a..4028c19 100644 --- a/include/rapidjson/reader.h +++ b/include/rapidjson/reader.h @@ -257,6 +257,11 @@ public: return !HasParseError(); } + template + bool Parse(InputStream& is, Handler& handler) { + return Parse<0>(is, handler); + } + bool HasParseError() const { return parseError_ != 0; } const char* GetParseError() const { return parseError_; } size_t GetErrorOffset() const { return errorOffset_; } diff --git a/readme.md b/readme.md index e07321b..58802a2 100644 --- a/readme.md +++ b/readme.md @@ -65,7 +65,7 @@ int main() { // 1. Parse a JSON string into DOM. const char* json = "{\"project\":\"rapidjson\",\"stars\":10}"; Document d; - d.Parse<0>(json); + d.Parse(json); // 2. Modify it by DOM. Value& s = d["stars"]; diff --git a/test/perftest/rapidjsontest.cpp b/test/perftest/rapidjsontest.cpp index 15e5912..db54d9b 100644 --- a/test/perftest/rapidjsontest.cpp +++ b/test/perftest/rapidjsontest.cpp @@ -28,7 +28,7 @@ public: temp_ = (char *)malloc(length_ + 1); // Parse as a document - EXPECT_FALSE(doc_.Parse<0>(json_).IsNull()); + EXPECT_FALSE(doc_.Parse(json_).IsNull()); } virtual void TearDown() { @@ -66,7 +66,7 @@ TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler)) { StringStream s(json_); BaseReaderHandler<> h; Reader reader; - EXPECT_TRUE(reader.Parse<0>(s, h)); + EXPECT_TRUE(reader.Parse(s, h)); } } @@ -88,7 +88,7 @@ TEST_F(RapidJson, SIMD_SUFFIX(DoucmentParseInsitu_MemoryPoolAllocator)) { //MemoryPoolAllocator<> allocator(userBuffer, userBufferSize); //Document doc(&allocator); Document doc; - doc.ParseInsitu<0>(temp_); + doc.ParseInsitu(temp_); ASSERT_TRUE(doc.IsObject()); //if (i == 0) { // size_t size = doc.GetAllocator().Size(); @@ -110,7 +110,7 @@ TEST_F(RapidJson, SIMD_SUFFIX(DoucmentParse_MemoryPoolAllocator)) { //MemoryPoolAllocator<> allocator(userBuffer, userBufferSize); //Document doc(&allocator); Document doc; - doc.Parse<0>(json_); + doc.Parse(json_); ASSERT_TRUE(doc.IsObject()); //if (i == 0) { // size_t size = doc.GetAllocator().Size(); @@ -128,7 +128,7 @@ TEST_F(RapidJson, SIMD_SUFFIX(DoucmentParse_CrtAllocator)) { for (size_t i = 0; i < kTrialCount; i++) { memcpy(temp_, json_, length_ + 1); GenericDocument, CrtAllocator> doc; - doc.Parse<0>(temp_); + doc.Parse(temp_); ASSERT_TRUE(doc.IsObject()); } } @@ -234,7 +234,7 @@ TEST_F(RapidJson, internal_Pow10) { TEST_F(RapidJson, SIMD_SUFFIX(Whitespace)) { for (size_t i = 0; i < kTrialCount; i++) { Document doc; - ASSERT_TRUE(doc.Parse<0>(whitespace_).IsArray()); + ASSERT_TRUE(doc.Parse(whitespace_).IsArray()); } } @@ -279,7 +279,7 @@ TEST_F(RapidJson, SIMD_SUFFIX(ReaderParse_DummyHandler_FileReadStream)) { FileReadStream s(fp, buffer, sizeof(buffer)); BaseReaderHandler<> h; Reader reader; - reader.Parse<0>(s, h); + reader.Parse(s, h); fclose(fp); } } diff --git a/test/unittest/documenttest.cpp b/test/unittest/documenttest.cpp index 82fc67d..e33ac0e 100644 --- a/test/unittest/documenttest.cpp +++ b/test/unittest/documenttest.cpp @@ -8,7 +8,7 @@ using namespace rapidjson; TEST(Document, Parse) { Document doc; - doc.Parse<0>(" { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } "); + doc.Parse(" { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } "); EXPECT_TRUE(doc.IsObject()); @@ -59,7 +59,7 @@ struct OutputStringStream : public std::ostringstream { TEST(Document, AcceptWriter) { Document doc; - doc.Parse<0>(" { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } "); + doc.Parse(" { \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3, 4] } "); OutputStringStream os; Writer writer(os); diff --git a/test/unittest/jsoncheckertest.cpp b/test/unittest/jsoncheckertest.cpp index 5c53865..7033856 100644 --- a/test/unittest/jsoncheckertest.cpp +++ b/test/unittest/jsoncheckertest.cpp @@ -42,7 +42,7 @@ TEST(JsonChecker, Reader) { } GenericDocument, CrtAllocator> document; // Use Crt allocator to check exception-safety (no memory leak) - if (!document.Parse<0>((const char*)json).HasParseError()) + if (!document.Parse((const char*)json).HasParseError()) FAIL(); //printf("%s(%u):%s\n", filename, (unsigned)document.GetErrorOffset(), document.GetParseError()); free(json); @@ -63,7 +63,7 @@ TEST(JsonChecker, Reader) { } GenericDocument, CrtAllocator> document; // Use Crt allocator to check exception-safety (no memory leak) - document.Parse<0>((const char*)json); + document.Parse((const char*)json); EXPECT_TRUE(!document.HasParseError()); free(json); } From a75c8f9b3ac3b1b9f9df9c6b5bd9c44ecaf2c3c2 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Sun, 29 Jun 2014 16:03:33 +0800 Subject: [PATCH 10/19] Create features.md --- doc/features.md | 61 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 doc/features.md diff --git a/doc/features.md b/doc/features.md new file mode 100644 index 0000000..af89602 --- /dev/null +++ b/doc/features.md @@ -0,0 +1,61 @@ +# RapidJSON Features + +## General + +* Cross-platform + * Compiler: tested Visual Studio, gcc, clang + * Architecture: x86, x64, ARM + * Operating systems: Windows, Mac OS X, Linux, iOS, Android +* Easy installation + * Header files only library. Just copy the headers to your project. +* Self-contained, minimal dependence + * No STL, BOOST, etc. + * Only included ``, ``, ``, ``, ``, ``. +* High performance + * Use template and inline functions to reduce function call overheads. + * Optional SSE2/SSE4.1 support. + +## Standard compliance + +* RapidJSON should be fully RFC4627/ECMA-404 compliance. +* Support unicode surrogate. +* Support null character (`"\u0000"`) +** For example, `["Hello\u0000World"]` can be parsed and handled gracefully. + +## API style + +* SAX (Simple API for XML) style API + * Similar to [SAX](http://en.wikipedia.org/wiki/Simple_API_for_XML), RapidJSON provides a event sequential access parser API (`GenericReader`). It also provides a generator API (`GenericWriter`) which consumes the same set of events. +* DOM (Document Object Model) style API + * Similar to [DOM](http://en.wikipedia.org/wiki/Document_Object_Model) for HTML/XML, RapidJSON can parse JSON into a DOM representation (`GenericDocument`), for easy manipulation, and finally stringify back to JSON if needed. + * The DOM style API (`GenericDocument`) is actually implemented with SAX style API (`GenericReader`). SAX is faster but sometimes DOM is easier. Users can pick their choices according to scenarios. + +## Unicode + +* Support UTF-8, UTF-16, UTF-32 encodings, including little endian and big endian. + * These encodings are used in input/output streams and in-memory representation. +* Support transcoding between encodings internally. + * For example, you can read a UTF-8 file and let RapidJSON transcode the JSON strings into UTF-16 in the DOM. +* Support encoding validation internally. + * For example, you can read a UTF-8 file, and let RapidJSON check whether all JSON strings are valid UTF-8 byte sequence. +* Support custom encodings. + +## Stream + +* Support `GenericStringBuffer` for storing the output JSON as string. +* Support `FileReadStream`/`FileWriteStream` for input/output `FILE` object. +* Support custom streams. + +## JSON formatting + +* Support PrettyWriter for adding newlines and indentations. + +## Memory + +* Minimize memory overheads for DOM. + * Each JSON value occupies exactly 16/20 bytes for most 32/64-bit machines (excluding text string). +* Support fast default allocator. + * A stack-based allocator (allocate sequentially, prohibit to free individual allocations, suitable for parsing). + * User can provide a pre-allocated buffer. (Possible to parse a number of JSONs without any CRT allocation) +* Standard CRT(C-runtime) allocator. +* Support custom allocators. From 3ef2a6bbce62faeb155d96bf68d2e147a7de4c19 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Sun, 29 Jun 2014 16:25:08 +0800 Subject: [PATCH 11/19] Update features.md --- doc/features.md | 53 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/doc/features.md b/doc/features.md index af89602..09f6f62 100644 --- a/doc/features.md +++ b/doc/features.md @@ -3,14 +3,15 @@ ## General * Cross-platform - * Compiler: tested Visual Studio, gcc, clang - * Architecture: x86, x64, ARM - * Operating systems: Windows, Mac OS X, Linux, iOS, Android + * Compilers: Visual Studio, gcc, clang, etc. + * Architectures: x86, x64, ARM, etc. + * Operating systems: Windows, Mac OS X, Linux, iOS, Android, etc. * Easy installation * Header files only library. Just copy the headers to your project. -* Self-contained, minimal dependence +* Self-contained, minimal dependences * No STL, BOOST, etc. - * Only included ``, ``, ``, ``, ``, ``. + * Only included ``, ``, ``, ``, ``, ``. * +* Without C++ exception, RTTI * High performance * Use template and inline functions to reduce function call overheads. * Optional SSE2/SSE4.1 support. @@ -20,15 +21,7 @@ * RapidJSON should be fully RFC4627/ECMA-404 compliance. * Support unicode surrogate. * Support null character (`"\u0000"`) -** For example, `["Hello\u0000World"]` can be parsed and handled gracefully. - -## API style - -* SAX (Simple API for XML) style API - * Similar to [SAX](http://en.wikipedia.org/wiki/Simple_API_for_XML), RapidJSON provides a event sequential access parser API (`GenericReader`). It also provides a generator API (`GenericWriter`) which consumes the same set of events. -* DOM (Document Object Model) style API - * Similar to [DOM](http://en.wikipedia.org/wiki/Document_Object_Model) for HTML/XML, RapidJSON can parse JSON into a DOM representation (`GenericDocument`), for easy manipulation, and finally stringify back to JSON if needed. - * The DOM style API (`GenericDocument`) is actually implemented with SAX style API (`GenericReader`). SAX is faster but sometimes DOM is easier. Users can pick their choices according to scenarios. + * For example, `["Hello\u0000World"]` can be parsed and handled gracefully. There is API for getting/setting lengths of string. ## Unicode @@ -38,18 +31,42 @@ * For example, you can read a UTF-8 file and let RapidJSON transcode the JSON strings into UTF-16 in the DOM. * Support encoding validation internally. * For example, you can read a UTF-8 file, and let RapidJSON check whether all JSON strings are valid UTF-8 byte sequence. +* Support custom character types. + * By default the character types are `char` for UTF8, `wchar_t` for UTF16, `uint32_t` for UTF32. * Support custom encodings. +## API styles + +* SAX (Simple API for XML) style API + * Similar to [SAX](http://en.wikipedia.org/wiki/Simple_API_for_XML), RapidJSON provides a event sequential access parser API (`GenericReader`). It also provides a generator API (`GenericWriter`) which consumes the same set of events. +* DOM (Document Object Model) style API + * Similar to [DOM](http://en.wikipedia.org/wiki/Document_Object_Model) for HTML/XML, RapidJSON can parse JSON into a DOM representation (`GenericDocument`), for easy manipulation, and finally stringify back to JSON if needed. + * The DOM style API (`GenericDocument`) is actually implemented with SAX style API (`GenericReader`). SAX is faster but sometimes DOM is easier. Users can pick their choices according to scenarios. + +## DOM (Document) + +* Support insitu parsing. + * Parse JSON string values in-place at the source JSON, and then the DOM points to addresses of those strings. + * Faster than convention parsing: no allocation for strings, no copy (if string does not contain escapes), cache-friendly. +* Support 32-bit/64-bit signed/unsigned integer and `double` for JSON number type. + * RapidJSON checks range of numerical values for conversions. + +## SAX (Reader) + +* Support comprehensive error code if parsing failed. +* Support localizable error message. + +## SAX (Writer) + +* Support PrettyWriter for adding newlines and indentations. +* Support custom precision for floating point values. + ## Stream * Support `GenericStringBuffer` for storing the output JSON as string. * Support `FileReadStream`/`FileWriteStream` for input/output `FILE` object. * Support custom streams. -## JSON formatting - -* Support PrettyWriter for adding newlines and indentations. - ## Memory * Minimize memory overheads for DOM. From 21b8d22575e782fe14475d97edf3429d41166d17 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Sun, 29 Jun 2014 16:30:55 +0800 Subject: [PATCH 12/19] Update readme.md --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index e07321b..56e99f0 100644 --- a/readme.md +++ b/readme.md @@ -18,7 +18,7 @@ Rapidjson is a JSON parser and generator for C++. It was inspired by [rapidxml]( * Rapidjson is Unicode friendly. It supports UTF-8, UTF-16, UTF-32 (LE & BE), and their detection, validataton and transcoding internally. For example, you can read a UTF-8 file and let rapidjson transcode the JSON strings into UTF-16 in the DOM. It also supports surrogates and "\u0000" (null character). -For the full features please refer to the user guide. +More features can be read [here](doc/features.md). JSON(JavaScript Object Notation) is a light-weight data exchange format. Rapidjson should be in fully compliance with RFC4627/ECMA-404. More information about JSON can be obtained at * [Introducing JSON](http://json.org/) From 718e9fe9d9595ab8258f218310c5e3329e1cf638 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Sun, 29 Jun 2014 16:34:53 +0800 Subject: [PATCH 13/19] Update features.md --- doc/features.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/features.md b/doc/features.md index 09f6f62..d8e2b1a 100644 --- a/doc/features.md +++ b/doc/features.md @@ -27,6 +27,7 @@ * Support UTF-8, UTF-16, UTF-32 encodings, including little endian and big endian. * These encodings are used in input/output streams and in-memory representation. +* Support Automatic detection of encodings in input stream. * Support transcoding between encodings internally. * For example, you can read a UTF-8 file and let RapidJSON transcode the JSON strings into UTF-16 in the DOM. * Support encoding validation internally. From 0f478f96ccb704ad48905495785a031c76734a34 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Sun, 29 Jun 2014 16:35:16 +0800 Subject: [PATCH 14/19] Update features.md --- doc/features.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/features.md b/doc/features.md index d8e2b1a..7a52030 100644 --- a/doc/features.md +++ b/doc/features.md @@ -27,7 +27,7 @@ * Support UTF-8, UTF-16, UTF-32 encodings, including little endian and big endian. * These encodings are used in input/output streams and in-memory representation. -* Support Automatic detection of encodings in input stream. +* Support automatic detection of encodings in input stream. * Support transcoding between encodings internally. * For example, you can read a UTF-8 file and let RapidJSON transcode the JSON strings into UTF-16 in the DOM. * Support encoding validation internally. @@ -75,5 +75,5 @@ * Support fast default allocator. * A stack-based allocator (allocate sequentially, prohibit to free individual allocations, suitable for parsing). * User can provide a pre-allocated buffer. (Possible to parse a number of JSONs without any CRT allocation) -* Standard CRT(C-runtime) allocator. +* Support standard CRT(C-runtime) allocator. * Support custom allocators. From 8bdf58a7256e326456b03a62a2af38c16d25280e Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Sun, 29 Jun 2014 16:42:11 +0800 Subject: [PATCH 15/19] Let travis to build perftest and example, and run perftest. --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index efa96e5..c911843 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,6 +21,8 @@ before_script: - cd "${TRAVIS_BUILD_DIR}" script: - - make -C build/gmake -f test.make unittest + - make -C build/gmake -f test.make + - make -C build/gmake -f example.make - cd bin - ./unittest_${config_suffix} + - ./perftest_${config_suffix} From 6f7d6642ef5b1307752bf9c7537f040dc744132f Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Sun, 29 Jun 2014 16:50:26 +0800 Subject: [PATCH 16/19] Turn off -Weverything for Travis. --- build/premake4.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/premake4.lua b/build/premake4.lua index 28a7138..05650d8 100644 --- a/build/premake4.lua +++ b/build/premake4.lua @@ -149,8 +149,8 @@ solution "example" configuration "vs*" defines { "_CRT_SECURE_NO_WARNINGS" } - configuration "gmake" - buildoptions "-Weverything" +-- configuration "gmake" +-- buildoptions "-Weverything" project "condense" kind "ConsoleApp" From bcf7cee788866dd9cc72fa883af39c62fe2876be Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Sun, 29 Jun 2014 20:59:01 +0800 Subject: [PATCH 17/19] Add stream copying optimization switch depending stream type. An unit test is added --- include/rapidjson/filereadstream.h | 5 +++ include/rapidjson/rapidjson.h | 28 +++++++++++++++++ include/rapidjson/reader.h | 8 ++--- test/unittest/readertest.cpp | 50 +++++++++++++++++++++++++++++- 4 files changed, 86 insertions(+), 5 deletions(-) diff --git a/include/rapidjson/filereadstream.h b/include/rapidjson/filereadstream.h index 4d42d38..29ab393 100644 --- a/include/rapidjson/filereadstream.h +++ b/include/rapidjson/filereadstream.h @@ -69,6 +69,11 @@ private: bool eof_; }; +template<> +struct StreamTraits { + typedef FileReadStream StreamCopyType; // Enable stream copy optimization. +}; + } // namespace rapidjson #endif // RAPIDJSON_FILESTREAM_H_ diff --git a/include/rapidjson/rapidjson.h b/include/rapidjson/rapidjson.h index fd31aef..be3d7fa 100644 --- a/include/rapidjson/rapidjson.h +++ b/include/rapidjson/rapidjson.h @@ -193,6 +193,24 @@ concept Stream { \endcode */ +//! Provides additional information for stream. +/*! + By using traits pattern, this type provides a default configuration for stream. + For custom stream, this type can be specialized for other configuration. + See TEST(Reader, CustomStringStream) in readertest.cpp for example. +*/ +template +struct StreamTraits { + //! Whether to make local copy of stream for optimization during parsing. + /*! + If it is defined as Stream&, it will not make a local copy. + If it is defined as Stream, it will make a local copy for optimization. + By default, for safety, streams do not use local copy optimization, i.e. it is defined as Stream&. + Stream that can be copied fast should specialize this, like StreamTraits. + */ + typedef Stream& StreamCopyType; +}; + //! Put N copies of a character to a stream. template inline void PutN(Stream& stream, Ch c, size_t n) { @@ -225,6 +243,11 @@ struct GenericStringStream { const Ch* head_; //!< Original head of the string. }; +template +struct StreamTraits> { + typedef GenericStringStream StreamCopyType; // Enable stream copy optimization. +}; + typedef GenericStringStream > StringStream; /////////////////////////////////////////////////////////////////////////////// @@ -256,6 +279,11 @@ struct GenericInsituStringStream { Ch* head_; }; +template +struct StreamTraits> { + typedef GenericInsituStringStream StreamCopyType; // Enable stream copy optimization. +}; + typedef GenericInsituStringStream > InsituStringStream; /////////////////////////////////////////////////////////////////////////////// diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h index 4028c19..1df5cf8 100644 --- a/include/rapidjson/reader.h +++ b/include/rapidjson/reader.h @@ -109,7 +109,7 @@ struct BaseReaderHandler { */ template void SkipWhitespace(InputStream& is) { - InputStream s = is; // Use a local copy for optimization + StreamTraits::StreamCopyType s = is; // Use a local copy for optimization while (s.Peek() == ' ' || s.Peek() == '\n' || s.Peek() == '\r' || s.Peek() == '\t') s.Take(); is = s; @@ -378,7 +378,7 @@ private: // Helper function to parse four hexidecimal digits in \uXXXX in ParseString(). template unsigned ParseHex4(InputStream& is) { - InputStream s = is; // Use a local copy for optimization + StreamTraits::StreamCopyType s = is; // Use a local copy for optimization unsigned codepoint = 0; for (int i = 0; i < 4; i++) { Ch c = s.Take(); @@ -419,7 +419,7 @@ private: // Parse string and generate String event. Different code paths for kParseInsituFlag. template void ParseString(InputStream& is, Handler& handler) { - InputStream s = is; // Local copy for optimization + StreamTraits::StreamCopyType s = is; // Local copy for optimization if (parseFlags & kParseInsituFlag) { Ch *head = s.PutBegin(); ParseStringToStream(s, s); @@ -499,7 +499,7 @@ private: template void ParseNumber(InputStream& is, Handler& handler) { - InputStream s = is; // Local copy for optimization + StreamTraits::StreamCopyType s = is; // Local copy for optimization // Parse minus bool minus = false; if (s.Peek() == '-') { diff --git a/test/unittest/readertest.cpp b/test/unittest/readertest.cpp index 1fa33f1..5cf937e 100644 --- a/test/unittest/readertest.cpp +++ b/test/unittest/readertest.cpp @@ -592,4 +592,52 @@ TEST(Reader, SkipWhitespace) { SkipWhitespace(ss); EXPECT_EQ(expected[i], ss.Take()); } -} \ No newline at end of file +} + +// Test implementing a stream without copy stream optimization. +// Clone from GenericStringStream except that copy constructor is disabled. +template +class CustomStringStream { +public: + typedef typename Encoding::Ch Ch; + + CustomStringStream(const Ch *src) : src_(src), head_(src) {} + + Ch Peek() const { return *src_; } + Ch Take() { return *src_++; } + size_t Tell() const { return static_cast(src_ - head_); } + + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + void Put(Ch) { RAPIDJSON_ASSERT(false); } + void Flush() { RAPIDJSON_ASSERT(false); } + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } + +private: + // Not support copy constructor. + CustomStringStream(const CustomStringStream&); + + const Ch* src_; //!< Current read position. + const Ch* head_; //!< Original head of the string. +}; + +// If the following code is compiled, it should generate compilation error as predicted. +// Because CustomStringStream<> is not copyable via making copy constructor private. +#if 0 +namespace rapidjson { + +template +struct StreamTraits> { + typedef CustomStringStream StreamCopyType; +}; + +} // namespace rapdijson +#endif + +TEST(Reader, CustomStringStream) { + const char* json = "{ \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] } "; + CustomStringStream> s(json); + ParseObjectHandler h; + Reader reader; + reader.ParseObject<0>(s, h); + EXPECT_EQ(20u, h.step_); +} From 789761ae1b52b6a8da55dd5b394c47f0850d3203 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Sun, 29 Jun 2014 21:18:31 +0800 Subject: [PATCH 18/19] Fixes compilation error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ‘>>’ should be ‘> >’ within a nested template argument list --- include/rapidjson/rapidjson.h | 4 ++-- test/unittest/readertest.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/rapidjson/rapidjson.h b/include/rapidjson/rapidjson.h index be3d7fa..29fe0ee 100644 --- a/include/rapidjson/rapidjson.h +++ b/include/rapidjson/rapidjson.h @@ -244,7 +244,7 @@ struct GenericStringStream { }; template -struct StreamTraits> { +struct StreamTraits > { typedef GenericStringStream StreamCopyType; // Enable stream copy optimization. }; @@ -280,7 +280,7 @@ struct GenericInsituStringStream { }; template -struct StreamTraits> { +struct StreamTraits > { typedef GenericInsituStringStream StreamCopyType; // Enable stream copy optimization. }; diff --git a/test/unittest/readertest.cpp b/test/unittest/readertest.cpp index 5cf937e..bc4e49d 100644 --- a/test/unittest/readertest.cpp +++ b/test/unittest/readertest.cpp @@ -626,7 +626,7 @@ private: namespace rapidjson { template -struct StreamTraits> { +struct StreamTraits > { typedef CustomStringStream StreamCopyType; }; @@ -635,7 +635,7 @@ struct StreamTraits> { TEST(Reader, CustomStringStream) { const char* json = "{ \"hello\" : \"world\", \"t\" : true , \"f\" : false, \"n\": null, \"i\":123, \"pi\": 3.1416, \"a\":[1, 2, 3] } "; - CustomStringStream> s(json); + CustomStringStream > s(json); ParseObjectHandler h; Reader reader; reader.ParseObject<0>(s, h); From 8e76a9dcce9128f30059fa4fc842e5c7c5e4b463 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Sun, 29 Jun 2014 21:24:15 +0800 Subject: [PATCH 19/19] Fixes compilation error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit need ‘typename’ before ‘rapidjson::StreamTraits::StreamCopyType --- include/rapidjson/reader.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h index 1df5cf8..c772840 100644 --- a/include/rapidjson/reader.h +++ b/include/rapidjson/reader.h @@ -109,7 +109,7 @@ struct BaseReaderHandler { */ template void SkipWhitespace(InputStream& is) { - StreamTraits::StreamCopyType s = is; // Use a local copy for optimization + typename StreamTraits::StreamCopyType s = is; // Use a local copy for optimization while (s.Peek() == ' ' || s.Peek() == '\n' || s.Peek() == '\r' || s.Peek() == '\t') s.Take(); is = s; @@ -378,7 +378,7 @@ private: // Helper function to parse four hexidecimal digits in \uXXXX in ParseString(). template unsigned ParseHex4(InputStream& is) { - StreamTraits::StreamCopyType s = is; // Use a local copy for optimization + typename StreamTraits::StreamCopyType s = is; // Use a local copy for optimization unsigned codepoint = 0; for (int i = 0; i < 4; i++) { Ch c = s.Take(); @@ -419,7 +419,7 @@ private: // Parse string and generate String event. Different code paths for kParseInsituFlag. template void ParseString(InputStream& is, Handler& handler) { - StreamTraits::StreamCopyType s = is; // Local copy for optimization + typename StreamTraits::StreamCopyType s = is; // Local copy for optimization if (parseFlags & kParseInsituFlag) { Ch *head = s.PutBegin(); ParseStringToStream(s, s); @@ -499,7 +499,7 @@ private: template void ParseNumber(InputStream& is, Handler& handler) { - StreamTraits::StreamCopyType s = is; // Local copy for optimization + typename StreamTraits::StreamCopyType s = is; // Local copy for optimization // Parse minus bool minus = false; if (s.Peek() == '-') {