6 #ifndef JBSON_JSON_WRITER_HPP
7 #define JBSON_JSON_WRITER_HPP
12 #include "detail/config.hpp"
14 JBSON_PUSH_DISABLE_DOCUMENTATION_WARNING
15 #include <boost/utility/string_ref.hpp>
16 #include <boost/range/as_literal.hpp>
17 #include <boost/concept_check.hpp>
18 JBSON_CLANG_POP_WARNINGS
20 #include "element.hpp"
21 #include "document.hpp"
22 #include "builder.hpp"
23 #include "detail/visit.hpp"
25 JBSON_PUSH_DISABLE_DEPRECATED_WARNING
31 template <
typename OutputIterator,
typename Container>
32 std::decay_t<OutputIterator> write_json(
const basic_array<Container>&, OutputIterator);
33 template <
typename OutputIterator,
typename Container>
34 std::decay_t<OutputIterator> write_json(
const basic_document<Container>&, OutputIterator);
42 template <
typename T,
typename OutputIterator>
43 std::decay_t<OutputIterator> stringify(T&& v, OutputIterator out,
44 std::enable_if_t<std::is_integral<std::decay_t<T>>::value>* =
nullptr) {
45 if(std::is_same<T, bool>::value)
46 return boost::range::copy(boost::as_literal(!!v ?
"true" :
"false"), out);
47 std::array<char, std::numeric_limits<T>::digits10 + 2> int_str;
48 auto n = std::snprintf(int_str.data(), int_str.size(),
"%zd",
static_cast<ptrdiff_t
>(v));
50 assert(static_cast<size_t>(n) <= int_str.size());
51 return boost::range::copy(boost::string_ref{int_str.data(),
static_cast<size_t>(n)}, out);
54 template <
typename T,
typename OutputIterator>
55 std::decay_t<OutputIterator> stringify(T&& v, OutputIterator out,
56 std::enable_if_t<std::is_floating_point<std::decay_t<T>>::value>* =
nullptr) {
57 std::array<char, std::numeric_limits<T>::digits10 + 2> float_str;
58 auto n = std::snprintf(float_str.data(), float_str.size(),
"%.8g", v);
60 assert(static_cast<size_t>(n) <= float_str.size());
61 out = boost::range::copy(boost::string_ref{float_str.data(),
static_cast<size_t>(n)}, out);
65 template <
typename OutputIterator> std::decay_t<OutputIterator> stringify(boost::string_ref v, OutputIterator out) {
66 auto str = std::vector<char>(v.begin(), v.end());
67 for(
auto i = str.begin(); i != str.end(); ++i) {
70 i = ++str.insert(i,
'\\');
73 i = ++str.insert(i,
'\\');
76 i = ++str.insert(i,
'\\');
79 i = ++str.insert(i,
'\\');
83 i = ++str.insert(i,
'\\');
87 i = ++str.insert(i,
'\\');
91 i = ++str.insert(i,
'\\');
95 i = ++str.insert(i,
'\\');
100 std::array<char, 7> hex;
101 auto n = std::snprintf(hex.data(), hex.size(),
"\\u%04x", std::char_traits<char>::to_int_type(*i));
104 i = str.insert(i, hex.begin(), std::next(hex.begin(), n));
110 out = boost::range::copy(str, out);
115 template <
typename C,
typename EC,
typename OutputIterator>
116 std::decay_t<OutputIterator> stringify(
const basic_document<C, EC>& doc, OutputIterator out) {
117 out = boost::range::copy(boost::as_literal(
"{ "), out);
119 auto end = doc.end();
120 for(
auto it = doc.begin(); it != end;) {
121 out = stringify(it->name(), out);
122 out = boost::range::copy(boost::as_literal(
" : "), out);
123 out = detail::visit<detail::json_element_visitor>(it->type(), *it, out);
125 out = boost::range::copy(boost::as_literal(
", "), out);
128 return boost::range::copy(boost::as_literal(
" }"), out);
131 template <
typename C,
typename EC,
typename OutputIterator>
132 std::decay_t<OutputIterator> stringify(
const basic_array<C, EC>& arr, OutputIterator out) {
133 out = boost::range::copy(boost::as_literal(
"[ "), out);
135 auto end = arr.end();
136 for(
auto it = arr.begin(); it != end;) {
137 out = detail::visit<detail::json_element_visitor>(it->type(), *it, out);
139 out = boost::range::copy(boost::as_literal(
", "), out);
142 return boost::range::copy(boost::as_literal(
" ]"), out);
147 #ifndef DOXYGEN_SHOULD_SKIP_THIS
150 #include <boost/concept/detail/concept_def.hpp>
151 BOOST_concept(OutputIterator, (TT)(ValueT)) {
152 BOOST_CONCEPT_USAGE(OutputIterator) {
159 TT i{std::declval<TT>()}, j{std::declval<TT>()};
162 #include <boost/concept/detail/concept_undef.hpp>
165 #endif // DOXYGEN_SHOULD_SKIP_THIS
167 template <element_type EType,
typename Element,
typename OutputIteratorT>
struct json_element_visitor {
168 static_assert(detail::is_element<std::decay_t<Element>>::value,
"");
169 BOOST_CONCEPT_ASSERT((concepts::OutputIteratorConcept<OutputIteratorT, char>));
171 json_element_visitor() =
default;
173 std::decay_t<OutputIteratorT> operator()(Element&& e, OutputIteratorT out)
const {
174 return stringify(get<EType>(e), out);
178 #ifndef DOXYGEN_SHOULD_SKIP_THIS
181 template <
typename Element,
typename OutputIterator>
183 std::decay_t<OutputIterator> operator()(Element&& e, std::decay_t<OutputIterator> out)
const {
184 auto oid = get<element_type::oid_element>(e);
185 std::array<char, 25> buf;
186 for(
size_t i = 0; i < oid.size(); ++i)
187 std::snprintf(&buf[i * 2], 3,
"%0.2x", static_cast<unsigned char>(oid[i]));
195 template <
typename Element,
typename OutputIterator>
197 std::decay_t<OutputIterator> operator()(Element&& e, std::decay_t<OutputIterator> out)
const {
198 using string_type = decltype(get<element_type::string_element>(e));
200 using oid_type = decltype(get<element_type::oid_element>(e));
202 std::tie(ref, oid) = get<element_type::db_pointer_element>(e);
203 return stringify(static_cast<document>(
210 template <
typename Element,
typename OutputIterator>
212 std::decay_t<OutputIterator> operator()(Element&& e, std::decay_t<OutputIterator> out)
const {
213 return stringify(static_cast<document>(builder(
"$date", e.template value<int64_t>())), out);
218 template <
typename Element,
typename OutputIterator>
220 std::decay_t<OutputIterator> operator()(Element&& e, std::decay_t<OutputIterator> out)
const {
221 using string_type = decltype(get<element_type::string_element>(e));
222 string_type regex, options;
223 std::tie(regex, options) = get<element_type::regex_element>(e);
231 template <
typename Element,
typename OutputIterator>
233 std::decay_t<OutputIterator> operator()(Element&&, std::decay_t<OutputIterator> out)
const {
return out; }
237 template <
typename Element,
typename OutputIterator>
239 std::decay_t<OutputIterator> operator()(Element&&, std::decay_t<OutputIterator> out)
const {
240 return boost::range::copy(boost::as_literal(
"null"), out);
244 template <
typename Element,
typename OutputIterator>
246 std::decay_t<OutputIterator> operator()(Element&&, std::decay_t<OutputIterator> out)
const {
247 return boost::range::copy(boost::as_literal(
"null"), out);
251 template <
typename Element,
typename OutputIterator>
253 std::decay_t<OutputIterator> operator()(Element&&, std::decay_t<OutputIterator> out)
const {
254 return boost::range::copy(boost::as_literal(
"null"), out);
258 template <
typename Element,
typename OutputIterator>
260 std::decay_t<OutputIterator> operator()(Element&&, std::decay_t<OutputIterator> out)
const {
261 return boost::range::copy(boost::as_literal(
"null"), out);
265 #endif // DOXYGEN_SHOULD_SKIP_THIS
269 template <
typename OutputIterator,
typename Container>
270 std::decay_t<OutputIterator> write_json(
const basic_array<Container>& arr, OutputIterator out) {
271 return detail::stringify(arr, out);
274 template <
typename OutputIterator,
typename Container>
275 std::decay_t<OutputIterator> write_json(
const basic_document<Container>& doc, OutputIterator out) {
276 return detail::stringify(doc, out);
283 #endif // JBSON_JSON_WRITER_HPP
element_type
The element_type enum represents a BSON data type.
std::string or boost::string_ref (string_type)