aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2024-09-04 10:17:23 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2024-09-04 10:17:23 +0200
commit85fbf3f0284268073fdfe1ed6d9dbfe54dc4d4bb (patch)
tree0f3aed577ca2b47956c0dd907817caa602a217c6
parent3852a414a4fa2b4006c5dca475a23add619cb2a1 (diff)
Add ability to customize/disable multi-value separator in JSON serializer
-rw-r--r--libbutl/json/serializer.cxx23
-rw-r--r--libbutl/json/serializer.hxx45
-rw-r--r--libbutl/json/serializer.ixx19
3 files changed, 57 insertions, 30 deletions
diff --git a/libbutl/json/serializer.cxx b/libbutl/json/serializer.cxx
index fbd569a..ae6c6b0 100644
--- a/libbutl/json/serializer.cxx
+++ b/libbutl/json/serializer.cxx
@@ -1,6 +1,6 @@
#include <cstdio> // snprintf
#include <cstdarg> // va_list
-#include <cstring> // memcpy
+#include <cstring> // memcpy, strlen
#include <ostream>
#include <libbutl/json/serializer.hxx>
@@ -38,23 +38,23 @@ namespace butl
}
buffer_serializer::
- buffer_serializer (string& s, size_t i)
+ buffer_serializer (string& s, size_t i, const char* mvs)
: buffer_serializer (const_cast<char*> (s.data ()), size_, s.size (),
dynarray_overflow<string>,
dynarray_flush<string>,
&s,
- i)
+ i, mvs)
{
size_ = s.size ();
}
buffer_serializer::
- buffer_serializer (vector<char>& v, size_t i)
+ buffer_serializer (vector<char>& v, size_t i, const char* mvs)
: buffer_serializer (v.data (), size_, v.size (),
dynarray_overflow<vector<char>>,
dynarray_flush<vector<char>>,
&v,
- i)
+ i, mvs)
{
size_ = v.size ();
}
@@ -83,12 +83,12 @@ namespace butl
}
stream_serializer::
- stream_serializer (ostream& os, size_t i)
+ stream_serializer (ostream& os, size_t i, const char* mvs)
: buffer_serializer (tmp_, sizeof (tmp_),
ostream_overflow,
ostream_flush,
&os,
- i)
+ i, mvs)
{
}
@@ -195,10 +195,13 @@ namespace butl
}
else if (values_ != 0) // Subsequent top-level value.
{
- // Top-level value separation. For now we always separate them with
- // newlines, which is the most common/sensible way.
+ // Top-level value separation.
//
- sep = make_str ("\n", 1);
+ sep = make_str (
+ mv_separator_,
+ (mv_separator_ == nullptr || mv_separator_[0] == '\0' ? 0 :
+ mv_separator_[1] == '\0' ? 1 :
+ strlen (mv_separator_)));
}
switch (*e)
diff --git a/libbutl/json/serializer.hxx b/libbutl/json/serializer.hxx
index 5192cb4..29fd63f 100644
--- a/libbutl/json/serializer.hxx
+++ b/libbutl/json/serializer.hxx
@@ -64,9 +64,9 @@ namespace butl
//
// Note that unlike the parser, the serializer is always in the multi-
// value mode allowing the serialization of zero or more values. Note also
- // that while values are separated with newlines, there is no trailing
- // newline after the last (or only) value and the user is expected to add
- // it manually if needed.
+ // that while values are by default separated with newlines, there is no
+ // trailing newline after the last (or only) value and the user is
+ // expected to add it manually, if needed.
//
// Also note that while RFC8259 recommends object members to have unique
// names, the serializer does not enforce this.
@@ -74,19 +74,30 @@ namespace butl
class LIBBUTL_SYMEXPORT buffer_serializer
{
public:
- // Serialize to string growing it as necessary.
+ // Serialize to string growing it as necessary. Note that the result is
+ // appended to any existing data in the string.
//
// The indentation argument specifies the number of indentation spaces
// that should be used for pretty-printing. If 0 is passed, no
// pretty-printing is performed.
//
+ // The multi_value_separator argument specifies the character sequence
+ // to use to separate multiple top-level values. NULL or empty string
+ // means no separator. Note that it is kept as a reference and so must
+ // outlive the serializer instance.
+ //
explicit
- buffer_serializer (std::string&, std::size_t indentation = 2);
+ buffer_serializer (std::string&,
+ std::size_t indentation = 2,
+ const char* multi_value_separator = "\n");
- // Serialize to vector of characters growing it as necessary.
+ // Serialize to vector of characters growing it as necessary. Note that
+ // the result is appended to any existing data in the vector.
//
explicit
- buffer_serializer (std::vector<char>&, std::size_t indentation = 2);
+ buffer_serializer (std::vector<char>&,
+ std::size_t indentation = 2,
+ const char* multi_value_separator = "\n");
// Serialize to a fixed array.
//
@@ -98,7 +109,8 @@ namespace butl
//
template <std::size_t N>
buffer_serializer (std::array<char, N>&, std::size_t& size,
- std::size_t indentation = 2);
+ std::size_t indentation = 2,
+ const char* multi_value_separator = "\n");
// Serialize to a fixed buffer.
//
@@ -109,7 +121,8 @@ namespace butl
// next() call that reaches the limit will throw invalid_json_output.
//
buffer_serializer (void* buf, std::size_t& size, std::size_t capacity,
- std::size_t indentation = 2);
+ std::size_t indentation = 2,
+ const char* multi_value_separator = "\n");
// The overflow function is called when the output buffer is out of
// space. The extra argument is a hint indicating the extra space likely
@@ -154,7 +167,8 @@ namespace butl
overflow_function*,
flush_function*,
void* data,
- std::size_t indentation = 2);
+ std::size_t indentation = 2,
+ const char* multi_value_separator = "\n");
// As above but the length of the output text written is tracked in the
// size argument.
@@ -163,7 +177,8 @@ namespace butl
overflow_function*,
flush_function*,
void* data,
- std::size_t indentation = 2);
+ std::size_t indentation = 2,
+ const char* multi_value_separator = "\n");
// Begin/end an object.
//
@@ -390,6 +405,10 @@ namespace butl
// The number of complete top-level values serialized thus far.
//
std::size_t values_ = 0;
+
+ // Multi-value separator.
+ //
+ const char* mv_separator_;
};
class LIBBUTL_SYMEXPORT stream_serializer: public buffer_serializer
@@ -402,7 +421,9 @@ namespace butl
// Otherwise, those are reported as the invalid_json_output exception.
//
explicit
- stream_serializer (std::ostream&, std::size_t indentation = 2);
+ stream_serializer (std::ostream&,
+ std::size_t indentation = 2,
+ const char* multi_value_separator = "\n");
protected:
char tmp_[4096];
diff --git a/libbutl/json/serializer.ixx b/libbutl/json/serializer.ixx
index a719ef6..ed5178a 100644
--- a/libbutl/json/serializer.ixx
+++ b/libbutl/json/serializer.ixx
@@ -25,36 +25,39 @@ namespace butl
inline buffer_serializer::
buffer_serializer (void* b, std::size_t& s, std::size_t c,
overflow_function* o, flush_function* f, void* d,
- std::size_t i)
+ std::size_t i, const char* mvs)
: buf_ {b, s, c},
overflow_ (o),
flush_ (f),
data_ (d),
indent_ (i),
- sep_ (indent_ != 0 ? ",\n" : "")
+ sep_ (indent_ != 0 ? ",\n" : ""),
+ mv_separator_ (mvs)
{
}
template <std::size_t N>
inline buffer_serializer::
- buffer_serializer (std::array<char, N>& a, std::size_t& s, std::size_t i)
+ buffer_serializer (std::array<char, N>& a, std::size_t& s,
+ std::size_t i, const char* mvs)
: buffer_serializer (a.data (), s, a.size (),
nullptr, nullptr, nullptr,
- i)
+ i, mvs)
{
}
inline buffer_serializer::
- buffer_serializer (void* b, std::size_t& s, std::size_t c, std::size_t i)
- : buffer_serializer (b, s, c, nullptr, nullptr, nullptr, i)
+ buffer_serializer (void* b, std::size_t& s, std::size_t c,
+ std::size_t i, const char* mvs)
+ : buffer_serializer (b, s, c, nullptr, nullptr, nullptr, i, mvs)
{
}
inline buffer_serializer::
buffer_serializer (void* b, std::size_t c,
overflow_function* o, flush_function* f, void* d,
- std::size_t i)
- : buffer_serializer (b, size_, c, o, f, d, i)
+ std::size_t i, const char* mvs)
+ : buffer_serializer (b, size_, c, o, f, d, i, mvs)
{
size_ = 0;
}