Mercurial > octave
changeset 28624:aae9d7f098bd
Support for RapidJSON 1.1.0 with jsonencode and jsondecode
* configure.ac: Define HAVE_RAPIDJSON for RapidJSON 1.1.0 and HAVE_RAPIDJSON_DEV
for the development or newer release in the future containing the
`rapidjson/cursorstreamwrapper.h` header file.
* libinterp/corefcn/jsondecode.cc: Improve docstrings and comments.
* libinterp/corefcn/jsonencode.cc (Fjsonencode): Enable the 'PrettyWriter'
option only if HAVE_RAPIDJSON_DEV is set to "1". Sort header includes.
Improve docstrings and comments.
This is the result of GSoC 2020 by Abdallah Elshamy and an addition to cset
5da49e37a6c9.
author | Abdallah Elshamy <abdallah.k.elshamy@gmail.com> |
---|---|
date | Tue, 18 Aug 2020 14:44:22 +0900 |
parents | 7bdd127d77e5 |
children | 173807014259 |
files | configure.ac libinterp/corefcn/jsondecode.cc libinterp/corefcn/jsonencode.cc |
diffstat | 3 files changed, 76 insertions(+), 54 deletions(-) [+] |
line wrap: on
line diff
--- a/configure.ac Sat Aug 15 23:41:26 2020 -0400 +++ b/configure.ac Tue Aug 18 14:44:22 2020 +0900 @@ -1337,11 +1337,14 @@ AC_CHECK_HEADER([rapidjson/rapidjson.h], [have_rapidjson=yes], [have_rapidjson=no rapid_json_warning="RapidJSON library not found. Octave will not be able to read or write JSON files."]) if test "$have_rapidjson" = yes; then - AC_CHECK_HEADER([rapidjson/cursorstreamwrapper.h], [have_rapidjson=yes], [have_rapidjson=no - rapid_json_warning="RapidJSON 1.1.0 or older found, but latest development version needed. Octave will not be able to read or write JSON files."]) + AC_CHECK_HEADER([rapidjson/cursorstreamwrapper.h], [have_rapidjson_dev=yes], [have_rapidjson_dev=no + rapid_json_warning="RapidJSON 1.1.0 or older found. Octave will not support the 'PrettyWriter' option in 'jsonencode'."]) fi if test "$have_rapidjson" = yes; then AC_DEFINE(HAVE_RAPIDJSON, 1, [Define to 1 if RapidJSON is available.]) + if test "$have_rapidjson_dev" = yes; then + AC_DEFINE(HAVE_RAPIDJSON_DEV, 1, [Define to 1 if the development version of RapidJSON is available.]) + fi else OCTAVE_CONFIGURE_WARNING([rapid_json_warning]) fi
--- a/libinterp/corefcn/jsondecode.cc Sat Aug 15 23:41:26 2020 -0400 +++ b/libinterp/corefcn/jsondecode.cc Tue Aug 18 14:44:22 2020 +0900 @@ -499,36 +499,43 @@ @example @group jsondecode ('[1, 2, null, 3]') - @result{} 1 2 NaN 3 + @result{} ans = + + 1 + 2 + NaN + 3 @end group @group jsondecode ('["foo", "bar", ["foo", "bar"]]') @result{} ans = - { - [1,1] = foo - [2,1] = bar - [3,1] = - { - [1,1] = foo - [2,1] = bar - } + @{ + [1,1] = foo + [2,1] = bar + [3,1] = + @{ + [1,1] = foo + [2,1] = bar + @} - } + @} @end group @group -jsondecode ('{"nu#m#ber": 7, "s#tr#ing": "hi"}', 'ReplacementStyle', 'delete') +jsondecode ('@{"nu#m#ber": 7, "s#tr#ing": "hi"@}', 'ReplacementStyle', 'delete') @result{} scalar structure containing the fields: - number = 7 - string = hi + + number = 7 + string = hi @end group @group -jsondecode ('{"1": "one", "2": "two"}', 'Prefix', 'm_') +jsondecode ('@{"1": "one", "2": "two"@}', 'Prefix', 'm_') @result{} scalar structure containing the fields: - m_1 = one - m_2 = two + + m_1 = one + m_2 = two @end group @end example @@ -538,8 +545,7 @@ #if defined (HAVE_RAPIDJSON) int nargin = args.length (); - // makeValidName options must be in pairs - // The number of arguments must be odd + // makeValidName options are pairs, the number of arguments must be odd. if (! (nargin % 2)) print_usage (); @@ -549,24 +555,24 @@ std::string json = args (0).string_value (); rapidjson::Document d; // DOM is chosen instead of SAX as SAX publishes events to a handler that - // decides what to do depending on the event only. This will cause a problem - // in decoding JSON arrays as the output may be an array or a cell and that - // doesn't only depend on the event (startArray) but also on the types of - // the elements inside the array + // decides what to do depending on the event only. This will cause a + // problem in decoding JSON arrays as the output may be an array or a cell + // and that doesn't only depend on the event (startArray) but also on the + // types of the elements inside the array. d.Parse <rapidjson::kParseNanAndInfFlag>(json.c_str ()); if (d.HasParseError ()) error("jsondecode: Parse error at offset %u: %s\n", - d.GetErrorOffset (), + static_cast<unsigned int> (d.GetErrorOffset ()), rapidjson::GetParseError_En (d.GetParseError ())); - return decode (d, args.slice (1, nargin-1)); + + return decode (d, args.slice (1, nargin - 1)); #else octave_unused_parameter (args); - err_disabled_feature ("jsondecode", - "RapidJSON is required for JSON encoding\\decoding"); + err_disabled_feature ("jsondecode", "JSON decoding through RapidJSON"); #endif }
--- a/libinterp/corefcn/jsonencode.cc Sat Aug 15 23:41:26 2020 -0400 +++ b/libinterp/corefcn/jsonencode.cc Tue Aug 18 14:44:22 2020 +0900 @@ -31,13 +31,13 @@ #include "defun.h" #include "error.h" #include "errwarn.h" +#include "oct-string.h" #include "ovl.h" -#include "oct-string.h" #if defined (HAVE_RAPIDJSON) -# include <rapidjson/writer.h> # include <rapidjson/prettywriter.h> # include <rapidjson/stringbuffer.h> +# include <rapidjson/writer.h> #endif #if defined (HAVE_RAPIDJSON) @@ -438,12 +438,12 @@ If the value of the option @qcode{"ConvertInfAndNaN"} is true, @qcode{"NaN"}, @qcode{"Inf"} and @qcode{"-Inf"} values will be converted to @qcode{"null"} -value in the output. If it is false, they will remain with their +value in the output. If it is false, they will remain with their original values. The default value for this option is true. If the value of the option @qcode{"PrettyWriter"} is true, the output text will -have indentations and line feeds. If it is false, the output will be condensed -and without any white-spaces. The default value for this option is false. +have indentations and line feeds. If it is false, the output will be condensed +and without any white-spaces. The default value for this option is false. -NOTES: @itemize @bullet @@ -459,12 +459,12 @@ @item It is not guaranteed to get the same dimensions for arrays if you encode -and then decode it. For example, If you encoded a row vector then decoded it, +and then decode it. For example, if you encoded a row vector then decoded it, you will get a column vector. @item It is not guaranteed to get the same data type if you encode and then decode -an Octave value as Octave supports more data types than JSON. For example, If +an Octave value as Octave supports more data types than JSON. For example, if you encoded an @qcode{"int32"} then decoded it, you will get a @qcode{"double"}. @end itemize @@ -529,20 +529,20 @@ @example @group jsonencode ([1 NaN; 3 4]) -@result{} [[1,null],[3,4]] +@result{} [[1,null],[3,4]] @end group @group jsonencode ([1 NaN; 3 4], "ConvertInfAndNaN", false) -@result{} [[1,NaN],[3,4]] +@result{} [[1,NaN],[3,4]] @end group @group jsonencode ([true; false], "ConvertInfAndNaN", false, "PrettyWriter", true) @result{} ans = [ - true, - false - ] + true, + false + ] @end group @group @@ -552,22 +552,22 @@ @group jsonencode (struct ('a', Inf, 'b', [], 'c', struct ())) -@result{} {"a":null,"b":[],"c":{}} +@result{} @{"a":null,"b":[],"c":@{@}@} @end group @group -jsonencode (struct ('structarray', struct ('a', {1; 3}, 'b', {2; 4}))) -@result{} {"structarray":[{"a":1,"b":2},{"a":3,"b":4}]} +jsonencode (struct ('structarray', struct ('a', @{1; 3@}, 'b', @{2; 4@}))) +@result{} @{"structarray":[@{"a":1,"b":2@},@{"a":3,"b":4@}]@} @end group @group -jsonencode ({'foo'; 'bar'; {'foo'; 'bar'}}) +jsonencode (@{'foo'; 'bar'; @{'foo'; 'bar'@}@}) @result{} ["foo","bar",["foo","bar"]] @end group @group -jsonencode (containers.Map({'foo'; 'bar'; 'baz'}, [1, 2, 3])) -@result{} {"bar":2,"baz":3,"foo":1} +jsonencode (containers.Map(@{'foo'; 'bar'; 'baz'@}, [1, 2, 3])) +@result{} @{"bar":2,"baz":3,"foo":1@} @end group @end example @@ -601,15 +601,29 @@ error ("jsonencode: Valid options are \'ConvertInfAndNaN\'" " and \'PrettyWriter\'"); } + + // FIXME: RapidJSON 1.1.0 (2016-08-25) is the latest release (2020-08-18) + // and does not support the "PrettyWriter" option. Once a newer + // RapidJSON version is released and established with major + // distributions, make that version a requirement. + #if ! defined (HAVE_RAPIDJSON_DEV) + if (PrettyWriter) + { + warn_disabled_feature ("jsonencode", + "the \'PrettyWriter\' option of RapidJSON"); + PrettyWriter = false; + } + #endif + rapidjson::StringBuffer json; if (PrettyWriter) - // In order to use the "PrettyWriter" option, you must use the development - // version of RapidJSON. The release causes an error in compilation. { - rapidjson::PrettyWriter<rapidjson::StringBuffer, rapidjson::UTF8<>, - rapidjson::UTF8<>, rapidjson::CrtAllocator, - rapidjson::kWriteNanAndInfFlag> writer (json); - encode (writer, args(0), ConvertInfAndNaN); + #if defined (HAVE_RAPIDJSON_DEV) + rapidjson::PrettyWriter<rapidjson::StringBuffer, rapidjson::UTF8<>, + rapidjson::UTF8<>, rapidjson::CrtAllocator, + rapidjson::kWriteNanAndInfFlag> writer (json); + encode (writer, args(0), ConvertInfAndNaN); + #endif } else { @@ -625,8 +639,7 @@ octave_unused_parameter (args); - err_disabled_feature ("jsonencode", - "RapidJSON is required for JSON encoding\\decoding"); + err_disabled_feature ("jsonencode", "JSON encoding through RapidJSON"); #endif }