@@ -53,8 +53,6 @@ namespace detail {
5353 bool escape_all_non_ascii, bool escape_solidus,
5454 Sink& sink)
5555 {
56- std::basic_string<CharT> buffer;
57- bool contains_quote{false };
5856 std::size_t count = 0 ;
5957 const CharT* begin = s;
6058 const CharT* end = s + length;
@@ -64,46 +62,45 @@ namespace detail {
6462 switch (c)
6563 {
6664 case ' \\ ' :
67- buffer .push_back (' \\ ' );
68- buffer .push_back (' \\ ' );
65+ sink .push_back (' \\ ' );
66+ sink .push_back (' \\ ' );
6967 count += 2 ;
7068 break ;
7169 case ' "' :
72- contains_quote = true ;
73- buffer.push_back (' \\ ' );
74- buffer.push_back (' \" ' );
70+ sink.push_back (' \\ ' );
71+ sink.push_back (' \" ' );
7572 count += 2 ;
7673 break ;
7774 case ' \b ' :
78- buffer .push_back (' \\ ' );
79- buffer .push_back (' b' );
75+ sink .push_back (' \\ ' );
76+ sink .push_back (' b' );
8077 count += 2 ;
8178 break ;
8279 case ' \f ' :
83- buffer .push_back (' \\ ' );
84- buffer .push_back (' f' );
80+ sink .push_back (' \\ ' );
81+ sink .push_back (' f' );
8582 count += 2 ;
8683 break ;
8784 case ' \n ' :
88- buffer .push_back (' \\ ' );
89- buffer .push_back (' n' );
85+ sink .push_back (' \\ ' );
86+ sink .push_back (' n' );
9087 count += 2 ;
9188 break ;
9289 case ' \r ' :
93- buffer .push_back (' \\ ' );
94- buffer .push_back (' r' );
90+ sink .push_back (' \\ ' );
91+ sink .push_back (' r' );
9592 count += 2 ;
9693 break ;
9794 case ' \t ' :
98- buffer .push_back (' \\ ' );
99- buffer .push_back (' t' );
95+ sink .push_back (' \\ ' );
96+ sink .push_back (' t' );
10097 count += 2 ;
10198 break ;
10299 default :
103100 if (escape_solidus && c == ' /' )
104101 {
105- buffer .push_back (' \\ ' );
106- buffer .push_back (' /' );
102+ sink .push_back (' \\ ' );
103+ sink .push_back (' /' );
107104 count += 2 ;
108105 }
109106 else if (is_control_character (c) || escape_all_non_ascii)
@@ -124,55 +121,45 @@ namespace detail {
124121 uint32_t first = (cp >> 10 ) + 0xD800 ;
125122 uint32_t second = ((cp & 0x03FF ) + 0xDC00 );
126123
127- buffer .push_back (' \\ ' );
128- buffer .push_back (' u' );
129- buffer .push_back (jsoncons::to_hex_character (first >> 12 & 0x000F ));
130- buffer .push_back (jsoncons::to_hex_character (first >> 8 & 0x000F ));
131- buffer .push_back (jsoncons::to_hex_character (first >> 4 & 0x000F ));
132- buffer .push_back (jsoncons::to_hex_character (first & 0x000F ));
133- buffer .push_back (' \\ ' );
134- buffer .push_back (' u' );
135- buffer .push_back (jsoncons::to_hex_character (second >> 12 & 0x000F ));
136- buffer .push_back (jsoncons::to_hex_character (second >> 8 & 0x000F ));
137- buffer .push_back (jsoncons::to_hex_character (second >> 4 & 0x000F ));
138- buffer .push_back (jsoncons::to_hex_character (second & 0x000F ));
124+ sink .push_back (' \\ ' );
125+ sink .push_back (' u' );
126+ sink .push_back (jsoncons::to_hex_character (first >> 12 & 0x000F ));
127+ sink .push_back (jsoncons::to_hex_character (first >> 8 & 0x000F ));
128+ sink .push_back (jsoncons::to_hex_character (first >> 4 & 0x000F ));
129+ sink .push_back (jsoncons::to_hex_character (first & 0x000F ));
130+ sink .push_back (' \\ ' );
131+ sink .push_back (' u' );
132+ sink .push_back (jsoncons::to_hex_character (second >> 12 & 0x000F ));
133+ sink .push_back (jsoncons::to_hex_character (second >> 8 & 0x000F ));
134+ sink .push_back (jsoncons::to_hex_character (second >> 4 & 0x000F ));
135+ sink .push_back (jsoncons::to_hex_character (second & 0x000F ));
139136 count += 12 ;
140137 }
141138 else
142139 {
143- buffer .push_back (' \\ ' );
144- buffer .push_back (' u' );
145- buffer .push_back (jsoncons::to_hex_character (cp >> 12 & 0x000F ));
146- buffer .push_back (jsoncons::to_hex_character (cp >> 8 & 0x000F ));
147- buffer .push_back (jsoncons::to_hex_character (cp >> 4 & 0x000F ));
148- buffer .push_back (jsoncons::to_hex_character (cp & 0x000F ));
140+ sink .push_back (' \\ ' );
141+ sink .push_back (' u' );
142+ sink .push_back (jsoncons::to_hex_character (cp >> 12 & 0x000F ));
143+ sink .push_back (jsoncons::to_hex_character (cp >> 8 & 0x000F ));
144+ sink .push_back (jsoncons::to_hex_character (cp >> 4 & 0x000F ));
145+ sink .push_back (jsoncons::to_hex_character (cp & 0x000F ));
149146 count += 6 ;
150147 }
151148 }
152149 else
153150 {
154- buffer .push_back (c);
151+ sink .push_back (c);
155152 ++count;
156153 }
157154 }
158155 else
159156 {
160- buffer .push_back (c);
157+ sink .push_back (c);
161158 ++count;
162159 }
163160 break ;
164161 }
165162 }
166- if (contains_quote)
167- {
168- sink.push_back (' \" ' );
169- sink.append (buffer.data (), buffer.size ());
170- sink.push_back (' \" ' );
171- }
172- else
173- {
174- sink.append (buffer.data (), buffer.size ());
175- }
176163 }
177164
178165 inline
@@ -212,20 +199,20 @@ namespace detail {
212199 template <typename CharT,typename Sink=jsoncons::stream_sink<CharT>,typename Allocator=std::allocator<char >>
213200 class basic_toon_encoder final : public basic_json_visitor<CharT>
214201 {
215- static const std::array <CharT, 4 >& null_constant ()
202+ static jsoncons::basic_string_view <CharT> null_literal ()
216203 {
217- static constexpr std::array <CharT, 4 > k{{ ' n ' , ' u ' , ' l ' , ' l ' }} ;
218- return k ;
204+ static jsoncons::basic_string_view <CharT> lit = JSONCONS_STRING_VIEW_CONSTANT (CharT, " null " ) ;
205+ return lit ;
219206 }
220- static const std::array <CharT, 4 >& true_constant ()
207+ static jsoncons::basic_string_view <CharT> true_literal ()
221208 {
222- static constexpr std::array <CharT, 4 > k{{ ' t ' , ' r ' , ' u ' , ' e ' }} ;
223- return k ;
209+ static jsoncons::basic_string_view <CharT> lit = JSONCONS_STRING_VIEW_CONSTANT (CharT, " true " ) ;
210+ return lit ;
224211 }
225- static const std::array <CharT, 5 >& false_constant ()
212+ static jsoncons::basic_string_view <CharT> false_literal ()
226213 {
227- static constexpr std::array <CharT, 5 > k{{ ' f ' , ' a ' , ' l ' , ' s ' , ' e ' }} ;
228- return k ;
214+ static jsoncons::basic_string_view <CharT> lit = JSONCONS_STRING_VIEW_CONSTANT (CharT, " false " ) ;
215+ return lit ;
229216 }
230217 public:
231218 using allocator_type = Allocator;
@@ -433,7 +420,7 @@ namespace detail {
433420 sink_.push_back (' ,' );
434421 }
435422
436- sink_.append (null_constant ().data (), null_constant ().size ());
423+ sink_.append (null_literal ().data (), null_literal ().size ());
437424
438425 if (!stack_.empty ())
439426 {
@@ -517,7 +504,16 @@ namespace detail {
517504 }
518505 }
519506
520- write_string (sv, tag, context, ec);
507+ if (!is_unquoted_safe (sv, ' ,' ))
508+ {
509+ sink_.push_back (' \" ' );
510+ write_string (sv, tag, context, ec);
511+ sink_.push_back (' \" ' );
512+ }
513+ else
514+ {
515+ write_string (sv, tag, context, ec);
516+ }
521517
522518 if (!stack_.empty ())
523519 {
@@ -648,7 +644,7 @@ namespace detail {
648644 }
649645 else
650646 {
651- sink_.append (null_constant ().data (), null_constant ().size ());
647+ sink_.append (null_literal ().data (), null_literal ().size ());
652648 }
653649 }
654650 else if (value == std::numeric_limits<double >::infinity ())
@@ -663,7 +659,7 @@ namespace detail {
663659 }
664660 else
665661 {
666- sink_.append (null_constant ().data (), null_constant ().size ());
662+ sink_.append (null_literal ().data (), null_literal ().size ());
667663 }
668664 }
669665 else
@@ -678,7 +674,7 @@ namespace detail {
678674 }
679675 else
680676 {
681- sink_.append (null_constant ().data (), null_constant ().size ());
677+ sink_.append (null_literal ().data (), null_literal ().size ());
682678 }
683679 }
684680 }
@@ -737,11 +733,11 @@ namespace detail {
737733
738734 if (value)
739735 {
740- sink_.append (true_constant ().data (), true_constant ().size ());
736+ sink_.append (true_literal ().data (), true_literal ().size ());
741737 }
742738 else
743739 {
744- sink_.append (false_constant ().data (), false_constant ().size ());
740+ sink_.append (false_literal ().data (), false_literal ().size ());
745741 }
746742
747743 if (!stack_.empty ())
@@ -750,6 +746,143 @@ namespace detail {
750746 }
751747 JSONCONS_VISITOR_RETURN;
752748 }
749+
750+ static bool is_unquoted_safe (jsoncons::basic_string_view<CharT> str, CharT delimiter = ' ,' )
751+ {
752+ if (str.empty ())
753+ {
754+ return false ;
755+ }
756+ if (is_number (str))
757+ {
758+ return false ;
759+ }
760+ if (str == null_literal () || str == true_literal () || str == false_literal ())
761+ {
762+ return false ;
763+ }
764+ if (str.front () == ' -' )
765+ {
766+ return false ;
767+ }
768+ for (auto c : str)
769+ {
770+ switch (c)
771+ {
772+ case ' :' :
773+ case ' [' :
774+ case ' ]' :
775+ case ' {' :
776+ case ' }' :
777+ case ' \" ' :
778+ case ' \\ ' :
779+ case ' \n ' :
780+ case ' \r ' :
781+ case ' \t ' :
782+ return false ;
783+ }
784+ if (c == delimiter)
785+ {
786+ return false ;
787+ }
788+ }
789+ return true ;
790+ }
791+ public:
792+ static bool is_number (jsoncons::basic_string_view<CharT> str)
793+ {
794+ int state = 0 ;
795+
796+ for (auto c : str)
797+ {
798+ switch (state)
799+ {
800+ case 0 :
801+ if (c == ' -' )
802+ {
803+ state = 1 ;
804+ }
805+ else if (c == ' 0' )
806+ {
807+ state = 2 ;
808+ }
809+ else if (c >= ' 1' && c <= ' 9' )
810+ {
811+ state = 3 ;
812+ }
813+ else
814+ {
815+ state = 9 ;
816+ }
817+ break ;
818+ case 1 : // leading minus
819+ if (c == ' 0' )
820+ {
821+ state = 2 ;
822+ }
823+ else if (c >= ' 1' && c <= ' 9' )
824+ {
825+ state = 3 ;
826+ }
827+ else
828+ {
829+ state = 9 ;
830+ }
831+ break ;
832+ case 2 : // after 0
833+ if (c == ' 0' )
834+ {
835+ state = 9 ;
836+ }
837+ else if (c == ' .' )
838+ {
839+ state = 4 ;
840+ }
841+ else if (c >= ' 1' && c <= ' 9' )
842+ {
843+ state = 3 ;
844+ }
845+ else
846+ {
847+ state = 9 ;
848+ }
849+ break ;
850+ case 3 : // expect digits or dot
851+ if (c == ' .' )
852+ {
853+ state = 4 ;
854+ }
855+ else if (!(c >= ' 0' && c <= ' 9' ))
856+ {
857+ state = 9 ;
858+ }
859+ break ;
860+ case 4 : // expect digits
861+ if (c >= ' 0' && c <= ' 9' )
862+ {
863+ state = 5 ;
864+ }
865+ else
866+ {
867+ state = 9 ;
868+ }
869+ break ;
870+ case 5 : // expect digits
871+ if (!(c >= ' 0' && c <= ' 9' ))
872+ {
873+ state = 9 ;
874+ }
875+ break ;
876+ default :
877+ break ;
878+ }
879+ }
880+ if (state == 2 || state == 3 || state == 5 )
881+ {
882+ return true ;
883+ }
884+ return false ;
885+ }
753886 };
754887
755888 using toon_stream_encoder = basic_toon_encoder<char ,jsoncons::stream_sink<char >>;
0 commit comments