From f27fb17bc9beb7a9bdb32f9ae3166f8d55d74f56 Mon Sep 17 00:00:00 2001
From: Qianqian Fang <fangq@nmr.mgh.harvard.edu>
Date: Sat, 14 Jan 2012 04:12:49 +0000
Subject: [PATCH] jsonlab 0.8.0, major speed up of loadjson for matlab

git-svn-id: http://svn.code.sf.net/p/iso2mesh/code/trunk/jsonlab@338 786e58fb-9377-0410-9ff7-e4ac0ac0635c
---
 ChangeLog.txt |  11 +++-
 README.txt    | 137 +++++++++++++++++++++++++++-----------------------
 loadjson.m    |  55 ++++++++++++++++++--
 savejson.m    |  19 +++++--
 4 files changed, 148 insertions(+), 74 deletions(-)

diff --git a/ChangeLog.txt b/ChangeLog.txt
index 15b2650..768d78b 100644
--- a/ChangeLog.txt
+++ b/ChangeLog.txt
@@ -6,12 +6,19 @@
 
 JSONlab ChangeLog (key features marked by *):
 
-== JSONlab 0.5.1 (codename: Nexus Update 1), FangQ <fangq nmr mgh harvard edu> ==
+== JSONlab 0.8.0 (codename: Sentiel), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
+
+ 2012/01/13 *speed up loadjson by 20 fold when parsing large data arrays in matlab
+ 2012/01/11  remove row bracket if an array has 1 element, suggested by Mykel Kochenderfer
+ 2011/12/22 *accept sequence of 'param',value input in savejson and loadjson
+ 2011/11/18  fix struct array bug reported by Mykel Kochenderfer
+
+== JSONlab 0.5.1 (codename: Nexus Update 1), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
 
  2011/10/21  fix a bug in loadjson, previous code does not use any of the acceleration
  2011/10/20  loadjson supports JSON collections: appendable JSON objects
 
-== JSONlab 0.5.0 (codename: Nexus), FangQ <fangq nmr mgh harvard edu> ==
+== JSONlab 0.5.0 (codename: Nexus), FangQ <fangq (at) nmr.mgh.harvard.edu> ==
 
  2011/10/16  package and release jsonlab 0.5.0
  2011/10/15 *add json demo and regression test, support cpx numbers, fix double quote bug
diff --git a/README.txt b/README.txt
index 494b8d6..44d49e3 100644
--- a/README.txt
+++ b/README.txt
@@ -3,9 +3,9 @@
 =           An open-source MATLAB/Octave JSON encoder and decoder             =
 ===============================================================================
 
-*Copyright (c) 2011  Qianqian Fang <fangq at nmr.mgh.harvard.edu>
+*Copyright (c) 2011,2012  Qianqian Fang <fangq at nmr.mgh.harvard.edu>
 *License: BSD or GNU General Public License version 3 (GPL v3), see License*.txt
-*Version: 0.5.1 (Nexus)
+*Version: 0.8.0 (Sentinel)
 
 -------------------------------------------------------------------------------
 
@@ -65,70 +65,82 @@ the two functions can be found below:
 
 === loadjson.m ===
 <pre>
- data=loadjson(fname)
-
- parse a JSON (JavaScript Object Notation) file or string
-
- authors:Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
-            date: 2011/09/09
-         Nedialko Krouchev: http://www.mathworks.com/matlabcentral/fileexchange/25713
-            date: 2009/11/02
-         François Glineur: http://www.mathworks.com/matlabcentral/fileexchange/23393
-            date: 2009/03/22
-         Joel Feenstra: http://www.mathworks.com/matlabcentral/fileexchange/20565
-            date: 2008/07/03
-
- input:
-      fname: input file name, if fname contains "{}" or "[]", fname
-      will be interpreted as a JSON string
-
- output:
-      dat: a cell array, where {...} blocks are converted into cell arrays,
-           and [...] are converted to arrays
+  data=loadjson(fname,opt)
+     or
+  data=loadjson(fname,'param1',value1,'param2',value2,...)
+ 
+  parse a JSON (JavaScript Object Notation) file or string
+ 
+  authors:Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
+             date: 2011/09/09
+          Nedialko Krouchev: http://www.mathworks.com/matlabcentral/fileexchange/25713
+             date: 2009/11/02
+          Fran�ois Glineur: http://www.mathworks.com/matlabcentral/fileexchange/23393
+             date: 2009/03/22
+          Joel Feenstra: http://www.mathworks.com/matlabcentral/fileexchange/20565
+             date: 2008/07/03
+ 
+  input:
+       fname: input file name, if fname contains "{}" or "[]", fname
+              will be interpreted as a JSON string
+       opt: a struct to store parsing options, opt can be replaced by 
+            a list of ('param',value) pairs. The param string is equivallent
+            to a field in opt.
+ 
+  output:
+       dat: a cell array, where {...} blocks are converted into cell arrays,
+            and [...] are converted to arrays
 </pre>
 
 === savejson.m ===
 
 <pre>
- json=savejson(rootname,obj,opt)
-
- convert a MATLAB object (cell, struct or array) into a JSON (JavaScript
- Object Notation) string
-
- authors:Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
-            date: 2011/09/09
-
- input:
-      rootname: name of the root-object, if set to '', will use variable name
-      obj: a MATLAB object (array, cell, cell array, struct, struct array)
-      opt: a struct for additional options, use [] if all use default
-        opt can have the following fields (first in [.|.] is the default)
-        opt.FloatFormat ['%.10g'|string]: format to show each numeric element
-                         of a 1D/2D array;
-        opt.ArrayIndent [1|0]: if 1, output explicit data array with
-                         precedent indentation; if 0, no indentation
-        opt.ArrayToStruct[0|1]: when set to 0, savejson outputs 1D/2D
-                         array in JSON array format; if sets to 1, an
-                         array will be shown as a struct with fields
-                         "_ArrayType_", "_ArraySize_" and "_ArrayData_"; for
-                         sparse arrays, the non-zero elements will be
-                         saved to _ArrayData_ field in triplet-format i.e.
-                         (ix,iy,val) and "_ArrayIsSparse_" will be added
-                         with a value of 1; for a complex array, the 
-                         _ArrayData_ array will include two columns 
-                         (4 for sparse) to record the real and imaginary 
-                         parts, and also "_ArrayIsComplex_":1 is added. 
-        opt.ParseLogical [0|1]: if this is set to 1, logical array elem
-                         will use true/false rather than 1/0.
-
- output:
-      json: a string in the JSON format (see http://json.org)
-
- examples:
-      a=struct('node',[1  9  10; 2 1 1.2], 'elem',[9 1;1 2;2 3],...
-           'face',[9 01 2; 1 2 3; NaN,Inf,-Inf], 'author','FangQ');
-      savejson('mesh',a)
-      savejson('',a,struct('ArrayIndent',0,'FloatFormat','\t%.5g'))
+  json=savejson(rootname,obj,opt)
+     or
+  json=savejson(rootname,obj,'param1',value1,'param2',value2,...)
+ 
+  convert a MATLAB object (cell, struct or array) into a JSON (JavaScript
+  Object Notation) string
+ 
+  author: Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
+             created on 2011/09/09
+  
+  input:
+       rootname: name of the root-object, if set to '', will use variable name
+       obj: a MATLAB object (array, cell, cell array, struct, struct array)
+       opt: a struct for additional options, use [] if all use default
+         opt can have the following fields (first in [.|.] is the default)
+         opt.FloatFormat ['%.10g'|string]: format to show each numeric element
+                          of a 1D/2D array;
+         opt.ArrayIndent [1|0]: if 1, output explicit data array with
+                          precedent indentation; if 0, no indentation
+         opt.ArrayToStruct[0|1]: when set to 0, savejson outputs 1D/2D
+                          array in JSON array format; if sets to 1, an
+                          array will be shown as a struct with fields
+                          "_ArrayType_", "_ArraySize_" and "_ArrayData_"; for
+                          sparse arrays, the non-zero elements will be
+                          saved to _ArrayData_ field in triplet-format i.e.
+                          (ix,iy,val) and "_ArrayIsSparse_" will be added
+                          with a value of 1; for a complex array, the 
+                          _ArrayData_ array will include two columns 
+                          (4 for sparse) to record the real and imaginary 
+                          parts, and also "_ArrayIsComplex_":1 is added. 
+         opt.ParseLogical [0|1]: if this is set to 1, logical array elem
+                          will use true/false rather than 1/0.
+         opt.NoRowBracket [1|0]: if this is set to 1, arrays with a single
+                          numerical element will be shown without a square
+                          bracket, unless it is the root object; if 0, square
+                          brackets are forced for any numerical arrays.
+         opt can be replaced by a list of ('param',value) pairs. The param 
+         string is equivallent to a field in opt.
+  output:
+       json: a string in the JSON format (see http://json.org)
+ 
+  examples:
+       a=struct('node',[1  9  10; 2 1 1.2], 'elem',[9 1;1 2;2 3],...
+            'face',[9 01 2; 1 2 3; NaN,Inf,-Inf], 'author','FangQ');
+       savejson('mesh',a)
+       savejson('',a,'ArrayIndent',0,'FloatFormat','\t%.5g')
 </pre>
 
 === examples ===
@@ -155,7 +167,8 @@ Here are the known issues:
 # When processing names containing multi-byte characters, Octave and MATLAB \
 can give different field-names;
 # Can not handle classes;
-# Although significantly accelerated, loadjson of large JSON file may still take some time.
+# Although significantly accelerated, running loadjson for large JSON file may \
+still take some time.
 
 -------------------------------------------------------------------------------
 
diff --git a/loadjson.m b/loadjson.m
index 7c885e7..8c92409 100644
--- a/loadjson.m
+++ b/loadjson.m
@@ -12,9 +12,12 @@ function data = loadjson(fname,varargin)
 %            date: 2009/11/02
 %         François Glineur: http://www.mathworks.com/matlabcentral/fileexchange/23393
 %            date: 2009/03/22
-%         Joel Feenstra: http://www.mathworks.com/matlabcentral/fileexchange/20565
+%         Joel Feenstra:
+%         http://www.mathworks.com/matlabcentral/fileexchange/20565
 %            date: 2008/07/03
 %
+% $Id$
+%
 % input:
 %      fname: input file name, if fname contains "{}" or "[]", fname
 %             will be interpreted as a JSON string
@@ -177,14 +180,50 @@ function object = parse_array(varargin) % JSON array is written in row-major ord
 global pos inStr isoct
     parse_char('[');
     object = cell(0, 1);
+    dim2=[];
     if next_char ~= ']'
-        endpos=matching_bracket(inStr,pos);
+        [endpos e1l e1r maxlevel]=matching_bracket(inStr,pos);
         arraystr=['[' inStr(pos:endpos)];
+        arraystr=regexprep(arraystr,'"_NaN_"','NaN');
+        arraystr=regexprep(arraystr,'"([-+]*)_Inf_"','$1Inf');
         arraystr(find(arraystr==sprintf('\n')))=[];
         arraystr(find(arraystr==sprintf('\r')))=[];
+        %arraystr=regexprep(arraystr,'\s*,',','); % this is slow,sometimes needed
+        if(~isempty(e1l) && ~isempty(e1r)) % the array is in 2D or higher D
+            astr=inStr((e1l+1):(e1r-1));
+            astr=regexprep(astr,'"_NaN_"','NaN');
+            astr=regexprep(astr,'"([-+]*)_Inf_"','$1Inf');
+            astr(find(astr==sprintf('\n')))=[];
+            astr(find(astr==sprintf('\r')))=[];
+            astr(find(astr==' '))='';
+            if(isempty(find(astr=='[', 1))) % array is 2D
+                dim2=length(sscanf(astr,'%f,',[1 inf]));
+            end
+        else % array is 1D
+            astr=arraystr(2:end-1);
+            astr(find(astr==' '))='';
+            [obj count errmsg nextidx]=sscanf(astr,'%f,',[1,inf]);
+            if(nextidx>=length(astr)-1)
+                object=obj;
+                pos=endpos;
+                parse_char(']');
+                return;
+            end
+        end
+        if(~isempty(dim2))
+            astr=arraystr;
+            astr(find(astr=='['))='';
+            astr(find(astr==']'))='';
+            astr(find(astr==' '))='';
+            [obj count errmsg nextidx]=sscanf(astr,'%f,',inf);
+            if(nextidx>=length(astr)-1)
+                object=reshape(obj,dim2,numel(obj)/dim2)';
+                pos=endpos;
+                parse_char(']');
+                return;
+            end
+        end
         arraystr=regexprep(arraystr,'\]\s*,','];');
-        arraystr=regexprep(arraystr,'"_NaN_"','NaN');
-        arraystr=regexprep(arraystr,'"([-+]*)_Inf_"','$1Inf');
         try
            if(isoct && regexp(arraystr,'"','once'))
                 error('Octave eval can produce empty cells for JSON-like input');
@@ -415,25 +454,31 @@ while(pos<len)
 end
 
 %%-------------------------------------------------------------------------
-function endpos = matching_bracket(str,pos)
+function [endpos e1l e1r maxlevel] = matching_bracket(str,pos)
 global arraytoken
 level=1;
+maxlevel=level;
 endpos=0;
 bpos=arraytoken(arraytoken>=pos);
 tokens=str(bpos);
 len=length(tokens);
 pos=1;
+e1l=[];
+e1r=[];
 while(pos<=len)
     c=tokens(pos);
     if(c==']')
         level=level-1;
+        if(isempty(e1r)) e1r=bpos(pos); end
         if(level==0)
             endpos=bpos(pos);
             return
         end
     end
     if(c=='[')
+        if(isempty(e1l)) e1l=bpos(pos); end
         level=level+1;
+        maxlevel=max(maxlevel,level);
     end
     if(c=='"')
         pos=matching_quote(tokens,pos+1);
diff --git a/savejson.m b/savejson.m
index f36c23e..67f3a2b 100644
--- a/savejson.m
+++ b/savejson.m
@@ -1,12 +1,16 @@
 function json=savejson(rootname,obj,varargin)
 %
 % json=savejson(rootname,obj,opt)
+%    or
+% json=savejson(rootname,obj,'param1',value1,'param2',value2,...)
 %
 % convert a MATLAB object (cell, struct or array) into a JSON (JavaScript
 % Object Notation) string
 %
-% authors:Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
-%            date: 2011/09/09
+% author: Qianqian Fang (fangq<at> nmr.mgh.harvard.edu)
+%            created on 2011/09/09
+%
+% $Id$
 %
 % input:
 %      rootname: name of the root-object, if set to '', will use variable name
@@ -30,7 +34,12 @@ function json=savejson(rootname,obj,varargin)
 %                         parts, and also "_ArrayIsComplex_":1 is added. 
 %        opt.ParseLogical [0|1]: if this is set to 1, logical array elem
 %                         will use true/false rather than 1/0.
-%
+%        opt.NoRowBracket [1|0]: if this is set to 1, arrays with a single
+%                         numerical element will be shown without a square
+%                         bracket, unless it is the root object; if 0, square
+%                         brackets are forced for any numerical arrays.
+%        opt can be replaced by a list of ('param',value) pairs. The param 
+%        string is equivallent to a field in opt.
 % output:
 %      json: a string in the JSON format (see http://json.org)
 %
@@ -38,7 +47,7 @@ function json=savejson(rootname,obj,varargin)
 %      a=struct('node',[1  9  10; 2 1 1.2], 'elem',[9 1;1 2;2 3],...
 %           'face',[9 01 2; 1 2 3; NaN,Inf,-Inf], 'author','FangQ');
 %      savejson('mesh',a)
-%      savejson('',a,struct('ArrayIndent',0,'FloatFormat','\t%.5g'))
+%      savejson('',a,'ArrayIndent',0,'FloatFormat','\t%.5g')
 %
 % license:
 %     BSD or GPL version 3, see LICENSE_{BSD,GPLv3}.txt files for details
@@ -203,7 +212,7 @@ else
     	txt=sprintf('%s%s',padding1,matdata2json(item,level+1,varargin{:}));
     else
         if(numel(item)==1 && jsonopt('NoRowBracket',1,varargin{:})==1)
-            numtxt=regexprep(regexprep(matdata2json(item,level+1,varargin{:}),'^[',''),']','');
+            numtxt=regexprep(regexprep(matdata2json(item,level+1,varargin{:}),'^\[',''),']','');
            	txt=sprintf('%s"%s": %s',padding1,name,numtxt);
         else
     	    txt=sprintf('%s"%s": %s',padding1,name,matdata2json(item,level+1,varargin{:}));
-- 
GitLab