GNU Octave  9.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
jsonencode.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 2020-2024 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING. If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25 
26 #if defined (HAVE_CONFIG_H)
27 # include "config.h"
28 #endif
29 
30 #include "builtin-defun-decls.h"
31 #include "defun.h"
32 #include "error.h"
33 #include "errwarn.h"
34 #include "oct-string.h"
35 #include "ovl.h"
36 
37 #if defined (HAVE_RAPIDJSON)
38 # include <rapidjson/stringbuffer.h>
39 # include <rapidjson/writer.h>
40 # if defined (HAVE_RAPIDJSON_PRETTYWRITER)
41 # include <rapidjson/prettywriter.h>
42 # endif
43 #endif
44 
45 #if defined (HAVE_RAPIDJSON)
46 
47 //! Encodes a scalar Octave value into a numerical JSON value.
48 //!
49 //! @param writer RapidJSON's writer that is responsible for generating JSON.
50 //! @param obj scalar Octave value.
51 //! @param ConvertInfAndNaN @c bool that converts @c Inf and @c NaN to @c null.
52 //!
53 //! @b Example:
54 //!
55 //! @code{.cc}
56 //! octave_value obj (7);
57 //! encode_numeric (writer, obj, true);
58 //! @endcode
59 
60 template <typename T> void
61 encode_numeric (T& writer, const octave_value& obj,
62  const bool& ConvertInfAndNaN)
63 {
64  double value = obj.scalar_value ();
65 
66  if (obj.is_bool_scalar ())
67  writer.Bool (obj.bool_value ());
68  // Any numeric input from the interpreter will be in double type so in order
69  // to detect ints, we will check if the floor of the input and the input are
70  // equal using fabs (A - B) < epsilon method as it is more accurate.
71  // If value > 999999, MATLAB will encode it in scientific notation (double)
72  else if (fabs (floor (value) - value) < std::numeric_limits<double>::epsilon ()
73  && value <= 999999 && value >= -999999)
74  writer.Int64 (value);
75  // Possibly write NULL for non-finite values (-Inf, Inf, NaN, NA)
76  else if (ConvertInfAndNaN && ! octave::math::isfinite (value))
77  writer.Null ();
78  else if (obj.is_double_type ())
79  writer.Double (value);
80  else
81  error ("jsonencode: unsupported type");
82 }
83 
84 //! Encodes character vectors and arrays into JSON strings.
85 //!
86 //! @param writer RapidJSON's writer that is responsible for generating JSON.
87 //! @param obj character vectors or character arrays.
88 //! @param original_dims The original dimensions of the array being encoded.
89 //! @param level The level of recursion for the function.
90 //!
91 //! @b Example:
92 //!
93 //! @code{.cc}
94 //! octave_value obj ("foo");
95 //! encode_string (writer, obj, true);
96 //! @endcode
97 
98 template <typename T> void
99 encode_string (T& writer, const octave_value& obj,
100  const dim_vector& original_dims, int level = 0)
101 {
102  charNDArray array = obj.char_array_value ();
103 
104  if (array.isempty ())
105  writer.String ("");
106  else if (array.isvector ())
107  {
108  // Handle the special case where the input is a vector with more than
109  // 2 dimensions (e.g. cat (8, ['a'], ['c'])). In this case, we don't
110  // split the inner vectors of the input; we merge them into one.
111  if (level == 0)
112  {
113  std::string char_vector = "";
114  for (octave_idx_type i = 0; i < array.numel (); ++i)
115  char_vector += array(i);
116  writer.String (char_vector.c_str ());
117  }
118  else
119  for (octave_idx_type i = 0; i < array.numel () / original_dims(1); ++i)
120  {
121  std::string char_vector = "";
122  for (octave_idx_type k = 0; k < original_dims(1); ++k)
123  char_vector += array(i * original_dims(1) + k);
124  writer.String (char_vector.c_str ());
125  }
126  }
127  else
128  {
129  octave_idx_type idx;
130  octave_idx_type ndims = array.ndims ();
131  dim_vector dims = array.dims ();
132 
133  // In this case, we already have a vector. So, we transform it to 2-D
134  // vector in order to be detected by "isvector" in the recursive call
135  if (dims.num_ones () == ndims - 1)
136  {
137  // Handle the special case when the input is a vector with more than
138  // 2 dimensions (e.g. cat (8, ['a'], ['c'])). In this case, we don't
139  // add dimension brackets and treat it as if it is a vector
140  if (level != 0)
141  // Place an opening and a closing bracket (represents a dimension)
142  // for every dimension that equals 1 until we reach the 2-D vector
143  for (int i = level; i < ndims - 1; ++i)
144  writer.StartArray ();
145 
146  encode_string (writer, array.as_row (), original_dims, level);
147 
148  if (level != 0)
149  for (int i = level; i < ndims - 1; ++i)
150  writer.EndArray ();
151  }
152  else
153  {
154  // We place an opening and a closing bracket for each dimension
155  // that equals 1 to preserve the number of dimensions when decoding
156  // the array after encoding it.
157  if (original_dims(level) == 1 && level != 1)
158  {
159  writer.StartArray ();
160  encode_string (writer, array, original_dims, level + 1);
161  writer.EndArray ();
162  }
163  else
164  {
165  // The second dimension contains the number of the chars in
166  // the char vector. We want to treat them as a one object,
167  // so we replace it with 1
168  dims(1) = 1;
169 
170  for (idx = 0; idx < ndims; ++idx)
171  if (dims(idx) != 1)
172  break;
173  // Create the dimensions that will be used to call "num2cell"
174  // We called "num2cell" to divide the array to smaller sub-arrays
175  // in order to encode it recursively.
176  // The recursive encoding is necessary to support encoding of
177  // higher-dimensional arrays.
178  RowVector conversion_dims;
179  conversion_dims.resize (ndims - 1);
180  for (octave_idx_type i = 0; i < idx; ++i)
181  conversion_dims(i) = i + 1;
182  for (octave_idx_type i = idx ; i < ndims - 1; ++i)
183  conversion_dims(i) = i + 2;
184 
185  octave_value_list args (obj);
186  args.append (conversion_dims);
187 
188  Cell sub_arrays = octave::Fnum2cell (args)(0).cell_value ();
189 
190  writer.StartArray ();
191 
192  for (octave_idx_type i = 0; i < sub_arrays.numel (); ++i)
193  encode_string (writer, sub_arrays(i), original_dims,
194  level + 1);
195 
196  writer.EndArray ();
197  }
198  }
199  }
200 }
201 
202 //! Encodes a struct Octave value into a JSON object or a JSON array depending
203 //! on the type of the struct (scalar struct or struct array.)
204 //!
205 //! @param writer RapidJSON's writer that is responsible for generating JSON.
206 //! @param obj struct Octave value.
207 //! @param ConvertInfAndNaN @c bool that converts @c Inf and @c NaN to @c null.
208 //!
209 //! @b Example:
210 //!
211 //! @code{.cc}
212 //! octave_value obj (octave_map ());
213 //! encode_struct (writer, obj,true);
214 //! @endcode
215 
216 template <typename T> void
217 encode_struct (T& writer, const octave_value& obj, const bool& ConvertInfAndNaN)
218 {
219  octave_map struct_array = obj.map_value ();
220  octave_idx_type numel = struct_array.numel ();
221  bool is_array = (numel != 1);
222  string_vector keys = struct_array.keys ();
223 
224  if (is_array)
225  writer.StartArray ();
226 
227  for (octave_idx_type i = 0; i < numel; ++i)
228  {
229  writer.StartObject ();
230  for (octave_idx_type k = 0; k < keys.numel (); ++k)
231  {
232  writer.Key (keys(k).c_str ());
233  encode (writer, struct_array(i).getfield (keys(k)), ConvertInfAndNaN);
234  }
235  writer.EndObject ();
236  }
237 
238  if (is_array)
239  writer.EndArray ();
240 }
241 
242 //! Encodes a Cell Octave value into a JSON array
243 //!
244 //! @param writer RapidJSON's writer that is responsible for generating JSON.
245 //! @param obj Cell Octave value.
246 //! @param ConvertInfAndNaN @c bool that converts @c Inf and @c NaN to @c null.
247 //!
248 //! @b Example:
249 //!
250 //! @code{.cc}
251 //! octave_value obj (cell ());
252 //! encode_cell (writer, obj,true);
253 //! @endcode
254 
255 template <typename T> void
256 encode_cell (T& writer, const octave_value& obj, const bool& ConvertInfAndNaN)
257 {
258  Cell cell = obj.cell_value ();
259 
260  writer.StartArray ();
261 
262  for (octave_idx_type i = 0; i < cell.numel (); ++i)
263  encode (writer, cell(i), ConvertInfAndNaN);
264 
265  writer.EndArray ();
266 }
267 
268 //! Encodes a numeric or logical Octave array into a JSON array
269 //!
270 //! @param writer RapidJSON's writer that is responsible for generating JSON.
271 //! @param obj numeric or logical Octave array.
272 //! @param ConvertInfAndNaN @c bool that converts @c Inf and @c NaN to @c null.
273 //! @param original_dims The original dimensions of the array being encoded.
274 //! @param level The level of recursion for the function.
275 //! @param is_logical optional @c bool that indicates if the array is logical.
276 //!
277 //! @b Example:
278 //!
279 //! @code{.cc}
280 //! octave_value obj (NDArray ());
281 //! encode_array (writer, obj,true);
282 //! @endcode
283 
284 template <typename T> void
285 encode_array (T& writer, const octave_value& obj, const bool& ConvertInfAndNaN,
286  const dim_vector& original_dims, int level = 0,
287  bool is_logical = false)
288 {
289  NDArray array = obj.array_value ();
290  // is_logical is assigned at level 0. I think this is better than changing
291  // many places in the code, and it makes the function more modular.
292  if (level == 0)
293  is_logical = obj.islogical ();
294 
295  if (array.isempty ())
296  {
297  writer.StartArray ();
298  writer.EndArray ();
299  }
300  else if (array.isvector ())
301  {
302  writer.StartArray ();
303  for (octave_idx_type i = 0; i < array.numel (); ++i)
304  {
305  if (is_logical)
306  encode_numeric (writer, bool (array(i)), ConvertInfAndNaN);
307  else
308  encode_numeric (writer, array(i), ConvertInfAndNaN);
309  }
310  writer.EndArray ();
311  }
312  else
313  {
314  octave_idx_type idx;
315  octave_idx_type ndims = array.ndims ();
316  dim_vector dims = array.dims ();
317 
318  // In this case, we already have a vector. So, we transform it to 2-D
319  // vector in order to be detected by "isvector" in the recursive call
320  if (dims.num_ones () == ndims - 1)
321  {
322  // Handle the special case when the input is a vector with more than
323  // 2 dimensions (e.g. ones ([1 1 1 1 1 6])). In this case, we don't
324  // add dimension brackets and treat it as if it is a vector
325  if (level != 0)
326  // Place an opening and a closing bracket (represents a dimension)
327  // for every dimension that equals 1 till we reach the 2-D vector
328  for (int i = level; i < ndims - 1; ++i)
329  writer.StartArray ();
330 
331  encode_array (writer, array.as_row (), ConvertInfAndNaN,
332  original_dims, level + 1, is_logical);
333 
334  if (level != 0)
335  for (int i = level; i < ndims - 1; ++i)
336  writer.EndArray ();
337  }
338  else
339  {
340  // We place an opening and a closing bracket for each dimension
341  // that equals 1 to preserve the number of dimensions when decoding
342  // the array after encoding it.
343  if (original_dims (level) == 1)
344  {
345  writer.StartArray ();
346  encode_array (writer, array, ConvertInfAndNaN,
347  original_dims, level + 1, is_logical);
348  writer.EndArray ();
349  }
350  else
351  {
352  for (idx = 0; idx < ndims; ++idx)
353  if (dims(idx) != 1)
354  break;
355 
356  // Create the dimensions that will be used to call "num2cell"
357  // We called "num2cell" to divide the array to smaller sub-arrays
358  // in order to encode it recursively.
359  // The recursive encoding is necessary to support encoding of
360  // higher-dimensional arrays.
361  RowVector conversion_dims;
362  conversion_dims.resize (ndims - 1);
363  for (octave_idx_type i = 0; i < idx; ++i)
364  conversion_dims(i) = i + 1;
365  for (octave_idx_type i = idx ; i < ndims - 1; ++i)
366  conversion_dims(i) = i + 2;
367 
368  octave_value_list args (obj);
369  args.append (conversion_dims);
370 
371  Cell sub_arrays = octave::Fnum2cell (args)(0).cell_value ();
372 
373  writer.StartArray ();
374 
375  for (octave_idx_type i = 0; i < sub_arrays.numel (); ++i)
376  encode_array (writer, sub_arrays(i), ConvertInfAndNaN,
377  original_dims, level + 1, is_logical);
378 
379  writer.EndArray ();
380  }
381  }
382  }
383 }
384 
385 //! Encodes any Octave object. This function only serves as an interface
386 //! by choosing which function to call from the previous functions.
387 //!
388 //! @param writer RapidJSON's writer that is responsible for generating JSON.
389 //! @param obj any @ref octave_value that is supported.
390 //! @param ConvertInfAndNaN @c bool that converts @c Inf and @c NaN to @c null.
391 //!
392 //! @b Example:
393 //!
394 //! @code{.cc}
395 //! octave_value obj (true);
396 //! encode (writer, obj,true);
397 //! @endcode
398 
399 template <typename T> void
400 encode (T& writer, const octave_value& obj, const bool& ConvertInfAndNaN)
401 {
402  if (obj.is_real_scalar ())
403  encode_numeric (writer, obj, ConvertInfAndNaN);
404  // As I checked for scalars, this will detect numeric & logical arrays
405  else if (obj.isnumeric () || obj.islogical ())
406  encode_array (writer, obj, ConvertInfAndNaN, obj.dims ());
407  else if (obj.is_string ())
408  encode_string (writer, obj, obj.dims ());
409  else if (obj.isstruct ())
410  encode_struct (writer, obj, ConvertInfAndNaN);
411  else if (obj.iscell ())
412  encode_cell (writer, obj, ConvertInfAndNaN);
413  else if (obj.class_name () == "containers.Map")
414  // To extract the data in containers.Map, convert it to a struct.
415  // The struct will have a "map" field whose value is a struct that
416  // contains the desired data.
417  // To avoid warnings due to that conversion, disable the
418  // "Octave:classdef-to-struct" warning and re-enable it.
419  {
420  octave::unwind_action restore_warning_state
421  ([] (const octave_value_list& old_warning_state)
422  {
423  octave::set_warning_state (old_warning_state);
424  }, octave::set_warning_state ("Octave:classdef-to-struct", "off"));
425 
426  encode_struct (writer, obj.scalar_map_value ().getfield ("map"),
427  ConvertInfAndNaN);
428  }
429  else if (obj.isobject ())
430  {
431  octave::unwind_action restore_warning_state
432  ([] (const octave_value_list& old_warning_state)
433  {
434  octave::set_warning_state (old_warning_state);
435  }, octave::set_warning_state ("Octave:classdef-to-struct", "off"));
436 
437  encode_struct (writer, obj.scalar_map_value (), ConvertInfAndNaN);
438  }
439  else
440  error ("jsonencode: unsupported type");
441 }
442 
443 #endif
444 
446 
447 DEFUN (jsonencode, args, ,
448  doc: /* -*- texinfo -*-
449 @deftypefn {} {@var{JSON_txt} =} jsonencode (@var{object})
450 @deftypefnx {} {@var{JSON_txt} =} jsonencode (@dots{}, "ConvertInfAndNaN", @var{TF})
451 @deftypefnx {} {@var{JSON_txt} =} jsonencode (@dots{}, "PrettyPrint", @var{TF})
452 
453 Encode Octave data types into JSON text.
454 
455 The input @var{object} is an Octave variable to encode.
456 
457 The output @var{JSON_txt} is the JSON text that contains the result of encoding
458 @var{object}.
459 
460 If the value of the option @qcode{"ConvertInfAndNaN"} is true then @code{NaN},
461 @code{NA}, @code{-Inf}, and @code{Inf} values will be converted to
462 @qcode{"null"} in the output. If it is false then they will remain as their
463 original values. The default value for this option is true.
464 
465 If the value of the option @qcode{"PrettyPrint"} is true, the output text will
466 have indentations and line feeds. If it is false, the output will be condensed
467 and written without whitespace. The default value for this option is false.
468 
469 Programming Notes:
470 
471 @itemize @bullet
472 @item
473 Complex numbers are not supported.
474 
475 @item
476 classdef objects are first converted to structs and then encoded.
477 
478 @item
479 To preserve escape characters (e.g., @qcode{"@backslashchar{}n"}), use
480 single-quoted strings.
481 
482 @item
483 Every character after the null character (@qcode{"@backslashchar{}0"}) in a
484 double-quoted string will be dropped during encoding.
485 
486 @item
487 Encoding and decoding an array is not guaranteed to preserve the dimensions
488 of the array. In particular, row vectors will be reshaped to column vectors.
489 
490 @item
491 Encoding and decoding is not guaranteed to preserve the Octave data type
492 because JSON supports fewer data types than Octave. For example, if you
493 encode an @code{int8} and then decode it, you will get a @code{double}.
494 @end itemize
495 
496 This table shows the conversions from Octave data types to JSON data types:
497 
498 @multitable @columnfractions 0.50 0.50
499 @headitem Octave data type @tab JSON data type
500 @item logical scalar @tab Boolean
501 @item logical vector @tab Array of Boolean, reshaped to row vector
502 @item logical array @tab nested Array of Boolean
503 @item numeric scalar @tab Number
504 @item numeric vector @tab Array of Number, reshaped to row vector
505 @item numeric array @tab nested Array of Number
506 @item @code{NaN}, @code{NA}, @code{Inf}, @code{-Inf}@*
507 when @qcode{"ConvertInfAndNaN" = true} @tab @qcode{"null"}
508 @item @code{NaN}, @code{NA}, @code{Inf}, @code{-Inf}@*
509 when @qcode{"ConvertInfAndNaN" = false} @tab @qcode{"NaN"}, @qcode{"NaN"},
510 @qcode{"Infinity"}, @qcode{"-Infinity"}
511 @item empty array @tab @qcode{"[]"}
512 @item character vector @tab String
513 @item character array @tab Array of String
514 @item empty character array @tab @qcode{""}
515 @item cell scalar @tab Array
516 @item cell vector @tab Array, reshaped to row vector
517 @item cell array @tab Array, flattened to row vector
518 @item struct scalar @tab Object
519 @item struct vector @tab Array of Object, reshaped to row vector
520 @item struct array @tab nested Array of Object
521 @item classdef object @tab Object
522 @end multitable
523 
524 Examples:
525 
526 @example
527 @group
528 jsonencode ([1, NaN; 3, 4])
529 @result{} [[1,null],[3,4]]
530 @end group
531 
532 @group
533 jsonencode ([1, NaN; 3, 4], "ConvertInfAndNaN", false)
534 @result{} [[1,NaN],[3,4]]
535 @end group
536 
537 @group
538 ## Escape characters inside a single-quoted string
539 jsonencode ('\0\a\b\t\n\v\f\r')
540 @result{} "\\0\\a\\b\\t\\n\\v\\f\\r"
541 @end group
542 
543 @group
544 ## Escape characters inside a double-quoted string
545 jsonencode ("\a\b\t\n\v\f\r")
546 @result{} "\u0007\b\t\n\u000B\f\r"
547 @end group
548 
549 @group
550 jsonencode ([true; false], "PrettyPrint", true)
551 @result{} ans = [
552  true,
553  false
554  ]
555 @end group
556 
557 @group
558 jsonencode (['foo', 'bar'; 'foo', 'bar'])
559 @result{} ["foobar","foobar"]
560 @end group
561 
562 @group
563 jsonencode (struct ('a', Inf, 'b', [], 'c', struct ()))
564 @result{} @{"a":null,"b":[],"c":@{@}@}
565 @end group
566 
567 @group
568 jsonencode (struct ('structarray', struct ('a', @{1; 3@}, 'b', @{2; 4@})))
569 @result{} @{"structarray":[@{"a":1,"b":2@},@{"a":3,"b":4@}]@}
570 @end group
571 
572 @group
573 jsonencode (@{'foo'; 'bar'; @{'foo'; 'bar'@}@})
574 @result{} ["foo","bar",["foo","bar"]]
575 @end group
576 
577 @group
578 jsonencode (containers.Map(@{'foo'; 'bar'; 'baz'@}, [1, 2, 3]))
579 @result{} @{"bar":2,"baz":3,"foo":1@}
580 @end group
581 @end example
582 
583 @seealso{jsondecode}
584 @end deftypefn */)
585 {
586 #if defined (HAVE_RAPIDJSON)
587 
588  int nargin = args.length ();
589  // jsonencode has two options 'ConvertInfAndNaN' and 'PrettyPrint'
590  if (nargin != 1 && nargin != 3 && nargin != 5)
591  print_usage ();
592 
593  // Initialize options with their default values
594  bool ConvertInfAndNaN = true;
595  bool PrettyPrint = false;
596 
597  for (octave_idx_type i = 1; i < nargin; ++i)
598  {
599  if (! args(i).is_string ())
600  error ("jsonencode: option must be a string");
601  if (! args(i+1).is_bool_scalar ())
602  error ("jsonencode: option value must be a logical scalar");
603 
604  std::string option_name = args(i++).string_value ();
605  if (string::strcmpi (option_name, "ConvertInfAndNaN"))
606  ConvertInfAndNaN = args(i).bool_value ();
607  else if (string::strcmpi (option_name, "PrettyPrint"))
608  PrettyPrint = args(i).bool_value ();
609  else
610  error ("jsonencode: "
611  R"(Valid options are "ConvertInfAndNaN" and "PrettyPrint")");
612  }
613 
614 # if ! defined (HAVE_RAPIDJSON_PRETTYWRITER)
615  if (PrettyPrint)
616  {
617  warn_disabled_feature ("jsonencode",
618  R"(the "PrettyPrint" option of RapidJSON)");
619  PrettyPrint = false;
620  }
621 # endif
622 
623  rapidjson::StringBuffer json;
624  if (PrettyPrint)
625  {
626 # if defined (HAVE_RAPIDJSON_PRETTYWRITER)
627  rapidjson::PrettyWriter<rapidjson::StringBuffer, rapidjson::UTF8<>,
628  rapidjson::UTF8<>, rapidjson::CrtAllocator,
629  rapidjson::kWriteNanAndInfFlag> writer (json);
630  writer.SetIndent (' ', 2);
631  encode (writer, args(0), ConvertInfAndNaN);
632 # endif
633  }
634  else
635  {
636  rapidjson::Writer<rapidjson::StringBuffer, rapidjson::UTF8<>,
637  rapidjson::UTF8<>, rapidjson::CrtAllocator,
638  rapidjson::kWriteNanAndInfFlag> writer (json);
639  encode (writer, args(0), ConvertInfAndNaN);
640  }
641 
642  return octave_value (json.GetString ());
643 
644 #else
645 
646  octave_unused_parameter (args);
647 
648  err_disabled_feature ("jsonencode", "JSON encoding through RapidJSON");
649 
650 #endif
651 }
652 
653 /*
654 Functional BIST tests are located in test/json/jsonencode_BIST.tst
655 
656 ## Input validation tests
657 %!testif HAVE_RAPIDJSON
658 %! fail ("jsonencode ()");
659 %! fail ("jsonencode (1, 2)");
660 %! fail ("jsonencode (1, 2, 3, 4)");
661 %! fail ("jsonencode (1, 2, 3, 4, 5, 6)");
662 %! fail ("jsonencode (1, 2, true)", "option must be a string");
663 %! fail ("jsonencode (1, 'string', ones (2,2))", ...
664 %! "option value must be a logical scalar");
665 %! fail ("jsonencode (1, 'foobar', true)", ...
666 %! 'Valid options are "ConvertInfAndNaN"');
667 
668 %!testif HAVE_RAPIDJSON; ! __have_feature__ ("RAPIDJSON_PRETTYWRITER")
669 %! fail ("jsonencode (1, 'PrettyPrint', true)", ...
670 %! "warning", 'the "PrettyPrint" option of RapidJSON was unavailable');
671 
672 */
673 
674 OCTAVE_END_NAMESPACE(octave)
octave_value_list Fnum2cell(const octave_value_list &=octave_value_list(), int=0)
Definition: cellfun.cc:1872
Array< T, Alloc > as_row() const
Return the array as a row vector.
Definition: Array.h:431
bool isvector() const
Size of the specified dimension.
Definition: Array.h:654
int ndims() const
Size of the specified dimension.
Definition: Array.h:671
bool isempty() const
Size of the specified dimension.
Definition: Array.h:651
const dim_vector & dims() const
Return a const-reference so that dims ()(i) works efficiently.
Definition: Array.h:503
octave_idx_type numel() const
Number of elements in the array.
Definition: Array.h:414
Definition: Cell.h:43
void resize(octave_idx_type n, const double &rfv=0)
Definition: dRowVector.h:102
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:94
int num_ones() const
Definition: dim-vector.cc:86
string_vector keys() const
Definition: oct-map.h:335
octave_idx_type numel() const
Definition: oct-map.h:368
octave_value getfield(const std::string &key) const
Definition: oct-map.cc:183
std::string class_name() const
Definition: ov.h:1347
bool bool_value(bool warn=false) const
Definition: ov.h:885
bool is_real_scalar() const
Definition: ov.h:610
Cell cell_value() const
octave_scalar_map scalar_map_value() const
bool is_string() const
Definition: ov.h:637
bool isnumeric() const
Definition: ov.h:750
charNDArray char_array_value(bool frc_str_conv=false) const
Definition: ov.h:897
double scalar_value(bool frc_str_conv=false) const
Definition: ov.h:847
bool iscell() const
Definition: ov.h:604
octave_map map_value() const
NDArray array_value(bool frc_str_conv=false) const
Definition: ov.h:859
bool is_double_type() const
Definition: ov.h:695
bool is_bool_scalar() const
Definition: ov.h:622
bool isstruct() const
Definition: ov.h:649
bool isobject() const
Definition: ov.h:664
bool islogical() const
Definition: ov.h:735
dim_vector dims() const
Definition: ov.h:541
octave_idx_type numel() const
Definition: str-vec.h:100
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
void print_usage(void)
Definition: defun-int.h:72
#define DEFUN(name, args_name, nargout_name, doc)
Macro to define a builtin function.
Definition: defun.h:56
void() error(const char *fmt,...)
Definition: error.cc:988
octave_value_list set_warning_state(const std::string &id, const std::string &state)
void err_disabled_feature(const std::string &fcn, const std::string &feature, const std::string &pkg)
Definition: errwarn.cc:53
void warn_disabled_feature(const std::string &fcn, const std::string &feature, const std::string &pkg)
Definition: errwarn.cc:318
bool isfinite(double x)
Definition: lo-mappers.h:192
std::complex< T > floor(const std::complex< T > &x)
Definition: lo-mappers.h:130
T::size_type numel(const T &str)
Definition: oct-string.cc:74
bool strcmpi(const T &str_a, const T &str_b)
True if strings are the same, ignoring case.
return octave_value(v1.char_array_value() . concat(v2.char_array_value(), ra_idx),((a1.is_sq_string()||a2.is_sq_string()) ? '\'' :'"'))