Skip to content

Commit afa8b16

Browse files
committed
direct map-like serialization
1 parent 0da8a8e commit afa8b16

File tree

4 files changed

+147
-94
lines changed

4 files changed

+147
-94
lines changed

include/boost/json/detail/writer.hpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ struct writer
5050

5151
// template<bool StackEmpty> bool write_true (detail::writer&, stream& ss);
5252
// template<bool StackEmpty> bool write_false (detail::writer&, stream& ss);
53-
// template<bool StackEmpty> bool write_string (detail::writer&, stream& ss);
5453
// template<bool StackEmpty> bool write_array (detail::writer&, stream& ss);
5554
// template<bool StackEmpty> bool write_object (detail::writer&, stream& ss);
5655

@@ -68,6 +67,20 @@ BOOST_JSON_DECL
6867
bool
6968
write_value<false>(writer& w, stream& ss);
7069

70+
template<bool StackEmpty>
71+
bool
72+
write_string(writer&, stream& ss);
73+
74+
extern template
75+
BOOST_JSON_DECL
76+
bool
77+
write_string<true>(writer&, stream& ss);
78+
79+
extern template
80+
BOOST_JSON_DECL
81+
bool
82+
write_string<false>(writer&, stream& ss);
83+
7184
bool
7285
BOOST_JSON_DECL
7386
write_int64(detail::writer&, stream& ss);

include/boost/json/impl/serializer.hpp

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#include <boost/core/addressof.hpp>
1414
#include <boost/json/conversion.hpp>
15+
#include <boost/core/addressof.hpp>
1516

1617
#ifdef _MSC_VER
1718
#pragma warning(push)
@@ -149,6 +150,113 @@ serialize_write(writer& w, stream& ss0, floating_point_conversion_tag )
149150
return resume_buffer(w, ss0);
150151
}
151152

153+
template<bool StackEmpty, class T>
154+
bool
155+
serialize_write(writer& w, stream& ss0, map_like_conversion_tag )
156+
{
157+
using std::get;
158+
using ConstIterator = iterator_type<T const>;
159+
using Mapped = remove_cvref< mapped_type<T> >;
160+
161+
T const* pt;
162+
local_stream ss(ss0);
163+
ConstIterator it;
164+
ConstIterator end;
165+
if( StackEmpty )
166+
{
167+
BOOST_ASSERT( w.st_.empty() );
168+
BOOST_ASSERT( w.p_ );
169+
pt = reinterpret_cast<T const*>(w.p_);
170+
it = pt->begin();
171+
end = pt->end();
172+
}
173+
else
174+
{
175+
BOOST_ASSERT( !w.st_.empty() );
176+
writer::state st;
177+
w.st_.pop(st);
178+
w.st_.pop(it);
179+
w.st_.pop(pt);
180+
end = pt->end();
181+
switch(st)
182+
{
183+
default:
184+
case writer::state::obj1: goto do_obj1;
185+
case writer::state::obj2: goto do_obj2;
186+
case writer::state::obj3: goto do_obj3;
187+
case writer::state::obj4: goto do_obj4;
188+
case writer::state::obj5: goto do_obj5;
189+
case writer::state::obj6: goto do_obj6;
190+
break;
191+
}
192+
}
193+
do_obj1:
194+
if(BOOST_JSON_LIKELY(ss))
195+
ss.append('{');
196+
else
197+
return w.suspend(
198+
writer::state::obj1, it, pt);
199+
if(BOOST_JSON_UNLIKELY(
200+
it == end))
201+
goto do_obj6;
202+
for(;;)
203+
{
204+
{
205+
string_view key = get<0>(*it);
206+
w.cs0_ = { key.data(), key.size() };
207+
}
208+
if( true )
209+
{
210+
if(BOOST_JSON_UNLIKELY( !write_string<true>(w, ss) ))
211+
return w.suspend(writer::state::obj2, it, pt);
212+
}
213+
else
214+
{
215+
do_obj2:
216+
if(BOOST_JSON_UNLIKELY( !write_string<false>(w, ss) ))
217+
return w.suspend(writer::state::obj2, it, pt);
218+
}
219+
do_obj3:
220+
if(BOOST_JSON_LIKELY(ss))
221+
ss.append(':');
222+
else
223+
return w.suspend(
224+
writer::state::obj3, it, pt);
225+
{
226+
Mapped const& ref = get<1>(*it);
227+
w.p_ = boost::addressof(ref);
228+
}
229+
if( true )
230+
{
231+
if(BOOST_JSON_UNLIKELY( !(serialize_write<true, Mapped>(w, ss)) ))
232+
return w.suspend(writer::state::obj4, it, pt);
233+
}
234+
else
235+
{
236+
do_obj4:
237+
if(BOOST_JSON_UNLIKELY( !(serialize_write<false, Mapped>(w, ss)) ))
238+
return w.suspend(writer::state::obj4, it, pt);
239+
}
240+
++it;
241+
if(BOOST_JSON_UNLIKELY(it == end))
242+
break;
243+
do_obj5:
244+
if(BOOST_JSON_LIKELY(ss))
245+
ss.append(',');
246+
else
247+
return w.suspend(
248+
writer::state::obj5, it, pt);
249+
}
250+
do_obj6:
251+
if(BOOST_JSON_LIKELY(ss))
252+
{
253+
ss.append('}');
254+
return true;
255+
}
256+
return w.suspend(
257+
writer::state::obj6, it, pt);
258+
}
259+
152260
template<bool StackEmpty, class T>
153261
bool
154262
serialize_write(writer& w, stream& ss0, sequence_conversion_tag )

include/boost/json/impl/serializer.ipp

Lines changed: 10 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,14 @@ do_utf5:
209209
goto do_str3;
210210
}
211211

212+
template
213+
bool
214+
write_string<true>(writer& w, stream& ss);
215+
216+
template
217+
bool
218+
write_string<false>(writer& w, stream& ss);
219+
212220
inline
213221
bool
214222
write_buffer(writer& w, stream& ss0)
@@ -305,99 +313,8 @@ template<bool StackEmpty>
305313
bool
306314
write_object(writer& w, stream& ss0)
307315
{
308-
object const* po;
309-
local_stream ss(ss0);
310-
object::const_iterator it;
311-
object::const_iterator end;
312-
if( StackEmpty )
313-
{
314-
BOOST_ASSERT( w.st_.empty() );
315-
BOOST_ASSERT( w.p_ );
316-
po = reinterpret_cast<object const*>(w.p_);
317-
it = po->begin();
318-
end = po->end();
319-
}
320-
else
321-
{
322-
BOOST_ASSERT( !w.st_.empty() );
323-
writer::state st;
324-
w.st_.pop(st);
325-
w.st_.pop(it);
326-
w.st_.pop(po);
327-
end = po->end();
328-
switch(st)
329-
{
330-
default:
331-
case writer::state::obj1: goto do_obj1;
332-
case writer::state::obj2: goto do_obj2;
333-
case writer::state::obj3: goto do_obj3;
334-
case writer::state::obj4: goto do_obj4;
335-
case writer::state::obj5: goto do_obj5;
336-
case writer::state::obj6: goto do_obj6;
337-
break;
338-
}
339-
}
340-
do_obj1:
341-
if(BOOST_JSON_LIKELY(ss))
342-
ss.append('{');
343-
else
344-
return w.suspend(
345-
writer::state::obj1, it, po);
346-
if(BOOST_JSON_UNLIKELY(
347-
it == end))
348-
goto do_obj6;
349-
for(;;)
350-
{
351-
w.cs0_ = {
352-
it->key().data(),
353-
it->key().size() };
354-
if( true )
355-
{
356-
if(BOOST_JSON_UNLIKELY( !write_string<true>(w, ss) ))
357-
return w.suspend(writer::state::obj2, it, po);
358-
}
359-
else
360-
{
361-
do_obj2:
362-
if(BOOST_JSON_UNLIKELY( !write_string<false>(w, ss) ))
363-
return w.suspend(writer::state::obj2, it, po);
364-
}
365-
do_obj3:
366-
if(BOOST_JSON_LIKELY(ss))
367-
ss.append(':');
368-
else
369-
return w.suspend(
370-
writer::state::obj3, it, po);
371-
w.p_ = &it->value();
372-
if( true )
373-
{
374-
if(BOOST_JSON_UNLIKELY( !write_value<true>(w, ss) ))
375-
return w.suspend(writer::state::obj4, it, po);
376-
}
377-
else
378-
{
379-
do_obj4:
380-
if(BOOST_JSON_UNLIKELY( !write_value<false>(w, ss) ))
381-
return w.suspend(writer::state::obj4, it, po);
382-
}
383-
++it;
384-
if(BOOST_JSON_UNLIKELY(it == end))
385-
break;
386-
do_obj5:
387-
if(BOOST_JSON_LIKELY(ss))
388-
ss.append(',');
389-
else
390-
return w.suspend(
391-
writer::state::obj5, it, po);
392-
}
393-
do_obj6:
394-
if(BOOST_JSON_LIKELY(ss))
395-
{
396-
ss.append('}');
397-
return true;
398-
}
399-
return w.suspend(
400-
writer::state::obj6, it, po);
316+
return serialize_write<StackEmpty, object>(
317+
w, ss0, map_like_conversion_tag() );
401318
}
402319

403320
template<bool StackEmpty>

test/serializer.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
#include <boost/json/null_resource.hpp>
1616
#include <boost/json/parse.hpp>
1717
#include <iostream>
18+
#include <map>
19+
#include <vector>
1820

1921
#include "parse-vectors.hpp"
2022
#include "test.hpp"
@@ -697,6 +699,19 @@ class serializer_test
697699
char buf[32];
698700
BOOST_TEST( sr.read(buf) == "[3.5E0,-1.4E1,7.7111E3]" );
699701
}
702+
{
703+
std::map<std::string, int> m{
704+
{"one", 1}, {"two", 2}, {"three", 3} };
705+
706+
serializer sr;
707+
sr.reset(&m);
708+
709+
char buf[32];
710+
string_view output = sr.read(buf);
711+
BOOST_TEST((
712+
parse(output) ==
713+
value{ {"one", 1}, {"two", 2}, {"three", 3} } ));
714+
}
700715
}
701716

702717
void

0 commit comments

Comments
 (0)