Skip to content

Commit 7cb2404

Browse files
committed
toon_encoder tests
1 parent a2f4d19 commit 7cb2404

File tree

3 files changed

+223
-65
lines changed

3 files changed

+223
-65
lines changed

include/jsoncons_ext/toon/toon_encoder.hpp

Lines changed: 198 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -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>>;

test/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,7 @@ add_executable(unit_tests
206206
ubjson/src/encode_ubjson_tests.cpp
207207
ubjson/src/ubjson_cursor_tests.cpp
208208
ubjson/src/ubjson_encoder_tests.cpp
209+
toon/src/toon_encoder_tests.cpp
209210
corelib/src/testmain.cpp
210211
)
211212

0 commit comments

Comments
 (0)