MatrixBerryCore
StructDisp.m
Go to the documentation of this file.
1 classdef StructDisp < handle
2 
3  methods
4  function self=StructDisp(varargin)
5 
6  import mxberry.core.parseparext;
7  [reg,propValCVec]=self.parseArgList(varargin);
8  [reg,~,self.isFullCheck]=parseparext(reg,...
9  {'isFullCheck';true;'islogical(x)&&isscalar(x)'},...
10  [1 1],'regDefList',{'isstruct(x)&&isscalar(x)'});
11  [self.inpPrintValues,self.structureName,...
12  self.maxArrayLength,self.depth,self.numberFormat]=...
13  deal(propValCVec{:});
14  self.initialize(reg{1});
15  end
16 
17  function resStr=char(self)
18  resultString=mxberry.core.string.catwithsep(self.dispCVec,...
19  sprintf('\n'));
20  resStr=[resultString,sprintf('\n')];
21  end
22  function disp(self)
23  disp(char(self));
24  end
25  function [changedRowIndVec,changedColIndVec]=update(self,SStructInp)
26 
27  if ~(isstruct(SStructInp)&&isscalar(SStructInp))
28  mxberry.core.throwerror('wrongInput',...
29  'SStructInp must be scalar structure')
30  end
31  if nargout>0
32  changedRowIndVec=nan(0,1);
33  changedColIndVec=nan(0,1);
34  end
35  [isLocalChanges,changedLeavesPathCVec,changedLeavesValCVec]=...
36  getleaveslist(SStructInp,self.SStruct,self.isFullCheck);
37  if isLocalChanges
38  if ~isempty(changedLeavesPathCVec)
39  [isLeavesVec,indLeavesVec]=ismember(changedLeavesPathCVec,...
40  {self.SLeavesInfoVec.path}.');
41  if any(isLeavesVec)
42  if ~all(isLeavesVec)
43  indLeavesVec=indLeavesVec(isLeavesVec);
44  changedLeavesValCVec(~isLeavesVec)=[];
45  end
46  SLeavesInfoVecCur=self.SLeavesInfoVec(indLeavesVec);
47  rowIndCVec={SLeavesInfoVecCur.rowIndVec}.';
48  colIndCVec={SLeavesInfoVecCur.colIndVec}.';
49  nLeaves=numel(indLeavesVec);
50  idVec=(1:nLeaves).';
51  inpCVec=self.getRecFieldPrintAddArgs();
52  [curDispCVec,outIdVec,curRowIndCVec,curColIndCVec]=...
53  self.recFieldPrint(...
54  {idVec,changedLeavesValCVec},inpCVec{:});
55  if ~isequal(idVec,outIdVec)
56  [~,indLeavesVec]=ismember(idVec,outIdVec);
57  curRowIndCVec=curRowIndCVec(indLeavesVec);
58  curColIndCVec=curColIndCVec(indLeavesVec);
59  end
60  isLocalChanges=isequal(...
61  cellfun('length',rowIndCVec),...
62  cellfun('length',curRowIndCVec));
63  if isLocalChanges
64  for iLeave=1:nLeaves
65  rowIndVec=rowIndCVec{iLeave};
66  colIndVec=colIndCVec{iLeave};
67  curRowIndVec=curRowIndCVec{iLeave};
68  curColIndVec=curColIndCVec{iLeave};
69  nRows=numel(rowIndVec);
70  for iRow=1:nRows
71  self.dispCVec{rowIndVec(iRow)}=...
72  [self.dispCVec{rowIndVec(iRow)}(...
73  1:(colIndVec(iRow)-1))...
74  curDispCVec{curRowIndVec(iRow)}(...
75  curColIndVec(iRow):end)];
76  end
77  end
78  self.SStruct=SStructInp;
79  if nargout>0
80  changedRowIndVec=vertcat(rowIndCVec{:});
81  changedColIndVec=vertcat(colIndCVec{:});
82  end
83  end
84  end
85  end
86  end
87  if ~isLocalChanges
88  self.initialize(SStructInp);
89  if nargout>0
90  nRows=numel(self.dispCVec);
91  changedRowIndVec=(1:nRows).';
92  changedColIndVec=ones(nRows,1);
93  end
94  end
95  end
96  end
97 
98  methods (Static)
99  function resStr=strucdisp(varargin)
100 
101  import mxberry.core.parseparext;
102  className=mfilename('class');
103  [reg,propValCVec]=feval([className '.parseArgList'],...
104  varargin);
105  reg=parseparext(reg,{},[1 2],...
106  'regDefList',{[],''},...
107  'regCheckList',{'isstruct(x)','isstring(x)'});
108  SInp=reg{1};
109  fileName=reg{2};
110  propValCVec=horzcat(propValCVec,{...
111  eval([className '.DASH_SYMBOL_CODE']),...
112  eval([className '.FILLER_SYMBOL_CODE'])});
113  %% Main program
114  %%%%% start program %%%%%
115  % start recursive function
116  listStr = mxberry.core.struct.StructDisp.recFieldPrint(SInp, 0,...
117  propValCVec{:});
118 
119  % 'listStr' is a cell array containing the output
120  % Now it's time to actually output the data
121  % Default is to output to the command window
122  % However, if the filename argument is defined, output it into a file
123  resultString=mxberry.core.string.catwithsep(listStr,sprintf('\n'));
124  if nargout==0
125  % write data to screen
126  disp(resultString);
127  else
128  resStr=[resultString,sprintf('\n')];
129  end
130  if ~isempty(fileName)
131  % open file and check for errors
132  fid = fopen(fileName, 'wt');
133  if fid < 0
134  error('Unable to open output file');
135  end
136  % write data to file
137  nListRows=length(listStr);
138  for iListRow = 1 : nListRows
139  fprintf(fid, '%s\n', listStr{iListRow});
140  end
141  % close file
142  fclose(fid);
143  end
144  end
145  end
146 
147  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
148  %% Private properties and methods
149  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
150 
151  properties (GetAccess=private,Constant,Hidden)
152  FILLER_SYMBOL_CODE=32;
153  DASH_SYMBOL_CODE=45;
154  DEFAULT_MAX_ARRAY_LENGTH=10;
155  DEFAULT_DEPTH=-1;
156  DEFAULT_PRINT_VALUES=true;
157  DEFAULT_NUMBER_FORMAT='%g';
158  DEFAULT_NAME = 'Structure';
159  end
160 
161  properties (Access=private,Hidden)
162  SStruct
163  dispCVec = cell(0,1);
164  SLeavesInfoVec = repmat(...
165  struct('path','','rowIndVec',NaN,'colIndVec',NaN),[0 1]);
166  depth
167  inpPrintValues
168  maxArrayLength
169  numberFormat
170  structureName
171  isFullCheck
172  end
173 
174  methods (Access=private,Hidden)
175  function initialize(self,SStructInp)
176  self.SStruct=SStructInp;
177  inpCVec=self.getRecFieldPrintAddArgs();
178  [self.dispCVec,...
179  leavesPathCVec,leavesRowIndCVec,leavesColIndCVec]=...
180  self.recFieldPrint(self.SStruct, inpCVec{:});
181  self.SLeavesInfoVec=struct(...
182  'path',leavesPathCVec,...
183  'rowIndVec',leavesRowIndCVec,...
184  'colIndVec',leavesColIndCVec);
185  end
186 
187  function inpCVec=getRecFieldPrintAddArgs(self)
188  inpCVec={0, self.inpPrintValues, self.structureName,...
189  self.maxArrayLength, self.depth, self.numberFormat,...
190  self.DASH_SYMBOL_CODE, self.FILLER_SYMBOL_CODE};
191  end
192  end
193 
194  methods (Access=private,Static,Hidden)
195  function [regCVec,propValCVec]=parseArgList(argCVec)
196  import mxberry.core.parseparext;
197  className=mfilename('class');
198  [regCVec,~,depthVal,printValuesVal,...
199  maxArrayLengthVal,numberFormatVal,...
200  structureNameVal]=parseparext(argCVec,...
201  {'depth','printValues','maxArrayLength',...
202  'numberFormat','defaultName',;...
203  getConstant('DEFAULT_DEPTH'),...
204  getConstant('DEFAULT_PRINT_VALUES'),...
205  getConstant('DEFAULT_MAX_ARRAY_LENGTH'),...
206  getConstant('DEFAULT_NUMBER_FORMAT'),...
207  getConstant('DEFAULT_NAME');
208  'isscalar(x)&&isnumeric(x)&&fix(x)==x',...
209  'islogical(x)&&isscalar(x)',...
210  'isscalar(x)&&isnumeric(x)&&fix(x)==x&&x>0',...
211  'isstring(x)',...
212  'isstring(x)'});
213  propValCVec={printValuesVal,structureNameVal,maxArrayLengthVal,...
214  depthVal,numberFormatVal};
215 
216  function res=getConstant(constantName)
217  res=eval([className '.' constantName]);
218  end
219  end
220 
221  %% FUNCTION: recFieldPrint
222 
223  function [listStr,leavesPathCVec,leavesRowIndCVec,leavesColIndCVec] = recFieldPrint(Structure, indent, printValues,structureName, maxArrayLength, depth, numberFormat,DASH_SYMBOL_CODE, FILLER_SYMBOL_CODE)
224  className=mfilename('class');
225  inpCVec={printValues,...
226  structureName, maxArrayLength, depth, numberFormat,...
227  DASH_SYMBOL_CODE, FILLER_SYMBOL_CODE};
228  isnListStrOnly=nargout>1;
229  % Start to initialiase the cell listStr. This cell is used to store all the
230  % output, as this is much faster then directly printing it to screen.
231  listStr = {};
232  if isnListStrOnly
233  leavesPathCVec = cell(0,1);
234  leavesRowIndCVec = cell(0,1);
235  leavesColIndCVec = cell(0,1);
236  end
237 
238  % "Structure" can be a scalar or a vector.
239  % In case of a vector, this recursive function is recalled for each of
240  % the vector elements. But if the values don't have to be printed, only
241  % the size of the structure and its fields are printed.
242  if isstruct(Structure) && numel(Structure) > 1
243  if (printValues == 0)
244  varStr = createArraySize(Structure, 'Structure');
245  body = feval([className '.recFieldPrint'],...
246  Structure(1), indent, inpCVec{:});
247  listStr = [{' '}; {[structureName, varStr]}; body; {' O'}];
248  else
249  sizeVec = size(Structure);
250  nStruc = min(numel(Structure), maxArrayLength);
251  subIndList=cell(1,length(sizeVec));
252  for iStruc = 1 : nStruc
253  if (~isscalar(Structure))
254  [subIndList{:}]=ind2sub(sizeVec,iStruc);
255  indexStr = sprintf('%d, ', [subIndList{:}]);
256  indexStr = horzcat('(', ...
257  indexStr(1:end-2), ')');
258  else
259  indexStr = sprintf('(%d)', iStruc);
260  end
261  if isnListStrOnly
262  [body,elemPathCVec,elemRowIndCVec,elemColIndCVec] = ...
263  feval([className '.recFieldPrint'],...
264  Structure(iStruc), indent, inpCVec{:});
265  nAdd=numel(listStr);
266  leavesPathCVec=vertcat(leavesPathCVec,...
267  strcat(indexStr,'.',elemPathCVec)); %#ok<AGROW>
268  leavesRowIndCVec=vertcat(leavesRowIndCVec,... cellfun(@(x)x+nAdd,...
269  elemRowIndCVec,'UniformOutput',false)); %#ok<AGROW>
270  leavesColIndCVec=vertcat(leavesColIndCVec,...
271  elemColIndCVec); %#ok<AGROW>
272  else
273  body = feval([className '.recFieldPrint'],...
274  Structure(iStruc), indent, inpCVec{:});
275  end
276  listStr = [listStr; {' '}; {[structureName,indexStr]}; body; {' O'}]; %#ok<AGROW>
277  end
278  if (numel(Structure) > maxArrayLength)
279  listStr = [listStr; {' '}; sprintf('<<%d elements more>>', ...
280  numel(Structure) - maxArrayLength)];
281  end
282  end
283  return
284  end
285 
286  %% Select structure fields
287  % The fields of the structure are distinguished between structure and
288  % non-structure fields. The structure fields are printed first, by
289  % recalling this function recursively.
290 
291  % First, select all fields.
292  %
293  if isstruct(Structure)
294  fields = fieldnames(Structure);
295  else
296  fields=Structure{1};
297  if ~iscell(fields)
298  leavesPathCVec=nan(0,1);
299  end
300  end
301  % Next, structfun is used to return an boolean array with information of
302  % which fields are of type structure.
303  if isempty(fields)
304  return;
305  end
306  if isstruct(Structure)
307  valsCVec = struct2cell(Structure);
308  else
309  valsCVec=Structure{2};
310  end
311  isStructVec = cellfun('isclass', valsCVec, 'struct');
312  % Finally, select all the structure fields
313 
314  strucFields = fields(isStructVec);
315  strucVals = valsCVec(isStructVec);
316 
317  %% Recursively print structure fields
318  % The next step is to select each structure field and handle it
319  % accordingly. Each structure can be empty, a scalar, a vector or a matrix.
320  % Matrices and long vectors are only printed with their fields and not with
321  % their values. Long vectors are defined as vectors with a length larger
322  % then the maxArrayLength value. The fields of an empty structure are not
323  % printed at all.
324  % It is not necessary to look at the length of the vector if the values
325  % don't have to be printed, as the fields of a vector or matrix structure
326  % are the same for each element.
327 
328  % First, some indentation calculations are required.
329 
330  [strIndent, strIndent2] = getIndentation(indent + 1);
331  listStr = [listStr; {strIndent2}];
332 
333  % Next, select each field seperately and handle it accordingly
334 
335  nFields = length(strucFields);
336  for iField = 1 : nFields
337  fieldName = strucFields{iField};
338  fieldVal = strucVals{iField};
339  isLeaves = false;
340  %
341  % Empty structure
342  isPrintWithSize=isempty(fieldVal);
343  if ~isPrintWithSize
344  if isscalar(fieldVal)
345  %line = sprintf('%s |--- %s', strIndent, fieldName);
346  line = horzcat(strIndent, ' |--- ', fieldName);
347  % Recall this function if the tree depth is not reached yet
348  if (depth < 0) || (indent + 1 < depth)
349  if isnListStrOnly
350  [lines,curPathCVec,curRowIndCVec,curColIndCVec] = ...
351  feval([className '.recFieldPrint'],...
352  fieldVal, indent + 1, inpCVec{:});
353  isLeaves = ~isempty(curPathCVec);
354  curRowIndCVec = cellfun(@(x)x+1,...
355  curRowIndCVec,'UniformOutput',false);
356  else
357  lines = feval([className '.recFieldPrint'],...
358  fieldVal, indent + 1, inpCVec{:});
359  end
360  curListStr = [{line}; lines; ...
361  {[strIndent ' | O']}];
362  else
363  if printValues
364  line = horzcat(line, ' :',...
365  createArraySize(fieldVal, 'Structure')); %#ok<AGROW>
366  end
367  curListStr = {line};
368  end
369  %
370  % Short vector structure of which the values should be printed
371  elseif (length(fieldVal) < maxArrayLength) && ...
372  ((depth < 0) || (indent + 1 < depth))
373  %
374  subIndList=cell(1,ndims(fieldVal));
375  sizeVec=size(fieldVal);
376 
377  % Use a for-loop to print all structures in the array
378  nFieldElement = numel(fieldVal);
379  curListStr = {};
380  if isnListStrOnly
381  curPathCVec = cell(0,1);
382  curRowIndCVec = cell(0,1);
383  curColIndCVec = cell(0,1);
384  end
385  for iFieldElement = 1 : nFieldElement
386  [subIndList{:}]=ind2sub(sizeVec,iFieldElement);
387  indexStr=sprintf('%d ',horzcat(subIndList{:}));
388  indexStr=indexStr(1:end-1);
389  elemName=horzcat('[',indexStr,']');
390  %
391  %line = sprintf('%s |--- %s(%s)', ...
392  % strIndent, fieldName, elemName);
393  line = horzcat(strIndent, ' |--- ',...
394  fieldName, '(', elemName, ')');
395  if isnListStrOnly
396  [lines,elemPathCVec,...
397  elemRowIndCVec,elemColIndCVec] = ...
398  feval([className '.recFieldPrint'],...
399  fieldVal(iFieldElement), indent + 1, inpCVec{:});
400  if ~isempty(elemPathCVec)
401  nAdd=numel(curListStr);
402  curPathCVec=vertcat(curPathCVec,...
403  strcat('(',strrep(indexStr,' ',','),').',...
404  elemPathCVec)); %#ok<AGROW>
405  curRowIndCVec=vertcat(curRowIndCVec,...
406  cellfun(@(x)x+nAdd+1,elemRowIndCVec,...
407  'UniformOutput',false)); %#ok<AGROW>
408  curColIndCVec=vertcat(curColIndCVec,...
409  elemColIndCVec); %#ok<AGROW>
410  end
411  else
412  lines = feval([className '.recFieldPrint'],...
413  fieldVal(iFieldElement), indent + 1, inpCVec{:});
414  end
415  curListStr = [curListStr;{line}; lines; ...
416  {[strIndent ' | O'];[strIndent ' | ']}]; %#ok<AGROW>
417  end
418  curListStr(end)=[];
419  if isnListStrOnly
420  isLeaves=~isempty(curPathCVec);
421  end
422  else
423  isPrintWithSize=true;
424  end
425  end
426  % Structure printed with size only
427  if isPrintWithSize
428  if printValues
429  strSize = createArraySize(fieldVal, 'Structure');
430  %line = sprintf('%s |--- %s :%s', ...
431  % strIndent, fieldName, strSize);
432  line = horzcat(strIndent, ' |--- ', fieldName,...
433  ' :', strSize);
434  else
435  line = horzcat(strIndent, ' |--- ', fieldName);
436  end
437  curListStr = {line};
438  end
439  %
440  if isLeaves
441  nAdd=numel(listStr);
442  if curPathCVec{1}(1)=='('
443  leavesPathCVec=vertcat(leavesPathCVec,...
444  strcat(fieldName,curPathCVec)); %#ok<AGROW>
445  else
446  leavesPathCVec=vertcat(leavesPathCVec,...
447  strcat(fieldName,'.',curPathCVec)); %#ok<AGROW>
448  end
449  leavesRowIndCVec=vertcat(leavesRowIndCVec,...
450  cellfun(@(x)x+nAdd,curRowIndCVec,...
451  'UniformOutput',false)); %#ok<AGROW>
452  leavesColIndCVec=vertcat(leavesColIndCVec,...
453  curColIndCVec); %#ok<AGROW>
454  end
455  % Some extra blank lines to increase readability
456  listStr = [listStr; curListStr; {[strIndent ' | ']}]; %#ok<AGROW>
457  end % End iField for-loop
458 
459  %% Field Filler
460  % To properly align the field names, a filler is required. To know how long
461  % the filler must be, the length of the longest fieldname must be found.
462  % Because 'fields' is a cell array, the function 'cellfun' can be used to
463  % extract the lengths of all fields.
464  if iscell(fields)
465  maxFieldLength = max(cellfun('length', fields));
466  else
467  maxFieldLength = 0;
468  end
469 
470  %% Print non-structure fields without values
471  % Print non-structure fields without the values. This can be done very
472  % quick.
473  if printValues == 0
474  noStrucFields = fields(~isStructVec);
475  nFields = length(noStrucFields);
476  fieldListStr = cell(nFields, 1);
477  for iField = 1 : nFields
478  fieldName = noStrucFields{iField};
479  filler = char(ones(1, ...
480  maxFieldLength - length(fieldName) + 2) * DASH_SYMBOL_CODE);
481  fieldListStr{iField} = [strIndent ' |' filler ' ' fieldName];
482  end
483  listStr = vertcat(listStr, fieldListStr);
484  return
485  end
486 
487 
488  %% Select non-structure fields (to print with values)
489  % Select fields that are not a structure and group them by data type. The
490  % following groups are distinguished:
491  % - characters and strings
492  % - numeric arrays
493  % - logical
494  % - empty arrays
495  % - matrices
496  % - numeric scalars
497  % - cell arrays
498  % - other data types
499 
500  % Character or string (array of characters)
501  isnProcessedVec=~isStructVec;
502  if any(isnProcessedVec)
503  isCharVec = isnProcessedVec;
504  isCharVec(isnProcessedVec) = ...
505  cellfun('isclass', valsCVec(isnProcessedVec), 'char');
506  charFields = fields(isCharVec);
507  charVals = valsCVec(isCharVec);
508  isnProcessedVec(isnProcessedVec)=~isCharVec(isnProcessedVec);
509  else
510  charFields = {};
511  end
512  %
513  % Logical fields
514  if any(isnProcessedVec)
515  isLogicalVec = isnProcessedVec;
516  isLogicalVec(isnProcessedVec) = ...
517  cellfun('isclass', valsCVec(isnProcessedVec), 'logical');
518  logicalFields = fields(isLogicalVec);
519  logicalVals = valsCVec(isLogicalVec);
520  isnProcessedVec(isnProcessedVec)=~isLogicalVec(isnProcessedVec);
521  else
522  logicalFields = {};
523  end
524  %
525  % Cell array
526  if any(isnProcessedVec)
527  isCellVec = isnProcessedVec;
528  isCellVec(isnProcessedVec) = ...
529  cellfun('isclass', valsCVec(isnProcessedVec), 'cell');
530  cellFields = fields(isCellVec);
531  cellVals = valsCVec(isCellVec);
532  isnProcessedVec(isnProcessedVec)=~isCellVec(isnProcessedVec);
533  else
534  cellFields = {};
535  end
536  %
537  % Empty arrays
538  if any(isnProcessedVec)
539  isEmptyVec = isnProcessedVec;
540  isEmptyVec(isnProcessedVec) = ...
541  cellfun('isempty', valsCVec(isnProcessedVec));
542  emptyFields = fields(isEmptyVec);
543  isnProcessedVec(isnProcessedVec)=~isEmptyVec(isnProcessedVec);
544  else
545  emptyFields = {};
546  end
547  %
548  % Numeric fields
549  if any(isnProcessedVec)
550  isNumericVec = isnProcessedVec;
551  isNumericVec(isnProcessedVec) = ...
552  cellfun(@isnumeric, valsCVec(isnProcessedVec));
553  isnProcessedVec(isnProcessedVec)=...
554  ~isNumericVec(isnProcessedVec);
555  %
556  % Numeric scalars
557  if any(isNumericVec)
558  isScalarVec = isNumericVec;
559  isScalarVec(isNumericVec) = ...
560  cellfun('prodofsize', valsCVec(isNumericVec)) == 1;
561  scalarFields = fields(isScalarVec);
562  scalarVals = valsCVec(isScalarVec);
563  isNumericVec(isScalarVec)=false;
564  else
565  scalarFields = {};
566  end
567  %
568  % Numeric vectors (arrays)
569  if any(isNumericVec)
570  isVectorVec = isNumericVec;
571  isVectorVec(isNumericVec) = ...
572  cellfun(@isvector, valsCVec(isNumericVec));
573  vectorFields = fields(isVectorVec);
574  vectorVals = valsCVec(isVectorVec);
575  isNumericVec(isVectorVec)=false;
576  else
577  vectorFields = {};
578  end
579  %
580  % Numeric matrix with dimension size 2 or higher
581  if any(isNumericVec)
582  %isMatrix = structfun(@(x) ndims(x) >= 2, Structure);
583  %isMatrix = isMatrix .* isNumeric .* not(isVector) ...
584  % .* not(isScalar) .* not(isEmpty);
585  matrixFields = fields(isNumericVec);
586  matrixVals = valsCVec(isNumericVec);
587  else
588  matrixFields = {};
589  end
590  else
591  scalarFields = {};
592  vectorFields = {};
593  matrixFields = {};
594  end
595  %
596  % Datatypes that are not checked for
597  if any(isnProcessedVec)
598  otherFields = fields(isnProcessedVec);
599  otherVals = valsCVec(isnProcessedVec);
600  else
601  otherFields = {};
602  end
603 
604  %% Print non-structure fields
605  % Print all the selected non structure fields
606  % - Strings are printed to a certain amount of characters
607  % - Vectors are printed as long as they are shorter than maxArrayLength
608  % - Matrices are printed if they have less elements than maxArrayLength
609  % - The values of cells are not printed
610 
611 
612  % Start with printing strings and characters. To avoid the display screen
613  % becoming a mess, the part of the string that is printed is limited to 31
614  % characters. In the future this might become an optional parameter in this
615  % function, but for now, it is placed in the code itself.
616  % if the string is longer than 31 characters, only the first 31 characters
617  % are printed, plus three dots to denote that the string is longer than
618  % printed.
619 
620  %maxStrLength = 31;
621  nFields = length(charFields);
622  fieldListStr = cell(nFields, 1);
623  if isnListStrOnly
624  fieldColIndVec = nan(nFields, 1);
625  end
626  for iField = 1 : nFields
627  fieldName = getFieldName(charFields,iField);
628  fieldVal = charVals{iField};
629  filler = char(ones(1, maxFieldLength - length(fieldName) + 2)...
630  * DASH_SYMBOL_CODE);
631  if (size(fieldVal, 1) > 1) && (size(fieldVal, 2) > 1)
632  varStr = createArraySize(fieldVal, 'char');
633  % elseif length(Field) > maxStrLength
634  % varStr = sprintf(' ''%s...''', Structure.(Field(1:maxStrLength)));
635  else
636  %varStr = sprintf(' ''%s''', fieldVal);
637  varStr = horzcat(' ''', reshape(fieldVal,1,[]), '''');
638  end
639  fieldListStr{iField} = [strIndent ' |' filler ' ' fieldName ' :' varStr];
640  if isnListStrOnly
641  fieldColIndVec(iField) = numel(fieldListStr{iField})-numel(varStr)+2;
642  end
643  end
644  if nFields
645  if isnListStrOnly
646  leavesPathCVec = vertcat(leavesPathCVec,charFields);
647  leavesRowIndCVec = vertcat(leavesRowIndCVec,...
648  num2cell(numel(listStr)+(1:nFields).'));
649  leavesColIndCVec = vertcat(leavesColIndCVec,...
650  num2cell(fieldColIndVec));
651  end
652  listStr = vertcat(listStr, fieldListStr);
653  end
654 
655  %% Print empty fields
656  nFields = length(emptyFields);
657  fieldListStr = cell(nFields, 1);
658  if isnListStrOnly
659  fieldColIndVec = nan(nFields, 1);
660  end
661  for iField = 1 : nFields
662  fieldName = getFieldName(emptyFields,iField);
663  filler = char(ones(1, maxFieldLength - length(fieldName) + 2)...
664  * DASH_SYMBOL_CODE);
665  fieldListStr{iField} = [strIndent ' |' filler ' ' fieldName ' : [ ]' ];
666  if isnListStrOnly
667  fieldColIndVec(iField) = numel(fieldListStr{iField})-2;
668  end
669  end
670  if nFields
671  if isnListStrOnly
672  leavesPathCVec = vertcat(leavesPathCVec,emptyFields);
673  leavesRowIndCVec = vertcat(leavesRowIndCVec,...
674  num2cell(numel(listStr)+(1:nFields).'));
675  leavesColIndCVec = vertcat(leavesColIndCVec,...
676  num2cell(fieldColIndVec));
677  end
678  listStr = vertcat(listStr, fieldListStr);
679  end
680  %% Print logicals. If it is a scalar, print true/false, else print vector
681  % information
682  nFields = length(logicalFields);
683  fieldListStr = cell(nFields, 1);
684  if isnListStrOnly
685  fieldColIndVec = nan(nFields, 1);
686  end
687  for iField = 1 : nFields
688  fieldName = getFieldName(logicalFields,iField);
689  fieldVal = logicalVals{iField};
690  filler = char(ones(1, maxFieldLength - length(fieldName) + 2)...
691  * DASH_SYMBOL_CODE);
692  if (isscalar(fieldVal))
693  if (fieldVal)
694  varStr = ' true';
695  else
696  varStr = ' false';
697  end
698  elseif (isvector(fieldVal) && ...
699  length(fieldVal) <= maxArrayLength)
700  varStr = repmat({'false '},1,numel(fieldVal));
701  if any(fieldVal)
702  varStr(fieldVal) = {'true '};
703  end
704  varStr = horzcat(varStr{:});
705  varStr = [' [' varStr(1:length(varStr) - 1) ']'];
706  else
707  varStr = createArraySize(fieldVal, 'Logic array');
708  end
709  fieldListStr{iField} = [strIndent ' |' filler ' ' fieldName ' :' varStr];
710  if isnListStrOnly
711  fieldColIndVec(iField) = numel(fieldListStr{iField})-numel(varStr)+2;
712  end
713  end
714  if nFields
715  if isnListStrOnly
716  leavesPathCVec = vertcat(leavesPathCVec,logicalFields);
717  leavesRowIndCVec = vertcat(leavesRowIndCVec,...
718  num2cell(numel(listStr)+(1:nFields).'));
719  leavesColIndCVec = vertcat(leavesColIndCVec,...
720  num2cell(fieldColIndVec));
721  end
722  listStr = vertcat(listStr, fieldListStr);
723  end
724 
725  % Print numeric scalar field. The %g format is used, so that integers
726  % floats and exponential numbers are printed in their own format.
727 
728  nFields = length(scalarFields);
729  fieldListStr = cell(nFields, 1);
730  if isnListStrOnly
731  fieldColIndVec = nan(nFields, 1);
732  end
733  for iField = 1 : nFields
734  fieldName = getFieldName(scalarFields,iField);
735  fieldVal = scalarVals{iField};
736  filler = char(ones(1, maxFieldLength - length(fieldName) + 2)...
737  * DASH_SYMBOL_CODE);
738  varStr = sprintf([' ',numberFormat], fieldVal);
739  fieldListStr{iField} = [strIndent ' |' filler ' ' fieldName ' :' varStr];
740  if isnListStrOnly
741  fieldColIndVec(iField) = numel(fieldListStr{iField})-numel(varStr)+2;
742  end
743  end
744  if nFields
745  if isnListStrOnly
746  leavesPathCVec = vertcat(leavesPathCVec,scalarFields);
747  leavesRowIndCVec = vertcat(leavesRowIndCVec,...
748  num2cell(numel(listStr)+(1:nFields).'));
749  leavesColIndCVec = vertcat(leavesColIndCVec,...
750  num2cell(fieldColIndVec));
751  end
752  listStr = vertcat(listStr, fieldListStr);
753  end
754 
755  %% Print numeric array. If the length of the array is smaller then
756  % maxArrayLength, then the values are printed. Else, print the length of
757  % the array.
758 
759  nFields = length(vectorFields);
760  fieldListStr = cell(nFields, 1);
761  if isnListStrOnly
762  fieldColIndVec = nan(nFields, 1);
763  end
764  for iField = 1 : nFields
765  fieldName = getFieldName(vectorFields,iField);
766  fieldVal = vectorVals{iField};
767  filler = char(ones(1, maxFieldLength - length(fieldName) + 2)...
768  * DASH_SYMBOL_CODE);
769  if length(fieldVal) > maxArrayLength
770  varStr = createArraySize(fieldVal, 'Array');
771  else
772  varStr = sprintf([numberFormat,' '], fieldVal);
773  varStr = [' [' varStr(1:length(varStr) - 1) ']'];
774  end
775  fieldListStr{iField} = [strIndent ' |' filler ' ' fieldName ...
776  ' :' varStr];
777  if isnListStrOnly
778  fieldColIndVec(iField) = numel(fieldListStr{iField})-numel(varStr)+2;
779  end
780  end
781  if nFields
782  if isnListStrOnly
783  leavesPathCVec = vertcat(leavesPathCVec,vectorFields);
784  leavesRowIndCVec = vertcat(leavesRowIndCVec,...
785  num2cell(numel(listStr)+(1:nFields).'));
786  leavesColIndCVec = vertcat(leavesColIndCVec,...
787  num2cell(fieldColIndVec));
788  end
789  listStr = vertcat(listStr, fieldListStr);
790  end
791  %% Print numeric matrices. If the matrix is two-dimensional and has more
792  % than maxArrayLength elements, only its size is printed.
793  % If the matrix is 'small', the elements are printed in a matrix structure.
794  % The top and the bottom of the matrix is indicated by a horizontal line of
795  % dashes. The elements are also lined out by using a format defined by
796  % numberFormat. Because the name of the matrix is only printed on the first
797  % line, the space is occupied by this name must be filled up on the other
798  % lines. This is done by defining a 'filler2'.
799  % This method was developed by S. Wegerich.
800 
801  nFields = length(matrixFields);
802  if isnListStrOnly
803  fieldRowIndCVec = cell(nFields, 1);
804  fieldColIndCVec = cell(nFields, 1);
805  end
806  for iField = 1 : nFields
807  fieldName = getFieldName(matrixFields,iField);
808  fieldVal = matrixVals{iField};
809  filler = char(ones(1, maxFieldLength - length(fieldName) + 2)...
810  * DASH_SYMBOL_CODE);
811  if numel(fieldVal) > maxArrayLength
812  varStr = createArraySize(fieldVal, 'Array');
813  varCell = {[strIndent ' |' filler ' ' fieldName ' :' varStr]};
814  if isnListStrOnly
815  fieldRowIndCVec{iField} = numel(listStr)+1;
816  fieldColIndCVec{iField} = numel(varCell{:})-numel(varStr)+2;
817  end
818  else
819  % matrixSize = size(Structure.(Field));
820  % filler2 = char(ones(1, maxFieldLength + 6) * FILLER_SYMBOL_CODE);
821  % dashes = char(ones(1, 12 * matrixSize(2) + 1) * DASH_SYMBOL_CODE);
822  printedFieldValue=cellfun(@(x)sprintf(numberFormat,x),...
823  num2cell(fieldVal),'UniformOutput',false);
824  if isnListStrOnly
825  [varCell,fieldRowIndCVec{iField},fieldColIndCVec{iField}]=...
826  formCellOfString(strIndent,printedFieldValue,...
827  maxFieldLength,[filler ' ' fieldName],...
828  FILLER_SYMBOL_CODE,DASH_SYMBOL_CODE);
829  fieldRowIndCVec{iField}=fieldRowIndCVec{iField}+numel(listStr);
830  else
831  varCell=formCellOfString(strIndent,printedFieldValue,...
832  maxFieldLength,[filler ' ' fieldName],...
833  FILLER_SYMBOL_CODE,DASH_SYMBOL_CODE);
834  end
835  end
836  listStr = [listStr; varCell]; %#ok<AGROW>
837  end
838  if nFields&&isnListStrOnly
839  leavesPathCVec=vertcat(leavesPathCVec,matrixFields);
840  leavesRowIndCVec = vertcat(leavesRowIndCVec,fieldRowIndCVec);
841  leavesColIndCVec = vertcat(leavesColIndCVec,fieldColIndCVec);
842  end
843  %% Print cell array information, i.e. the size of the cell array. The
844  % content of the cell array is not printed.
845  nFields = length(cellFields);
846  if isnListStrOnly
847  fieldRowIndCVec = cell(nFields, 1);
848  fieldColIndCVec = cell(nFields, 1);
849  end
850  for iField = 1 : nFields
851  fieldName = getFieldName(cellFields,iField);
852  fieldVal = cellVals{iField};
853  filler = char(ones(1, maxFieldLength - length(fieldName) + 2)...
854  * DASH_SYMBOL_CODE);
855  isMatOfStrings=ismatrix(fieldVal)&&...
856  iscellstr(fieldVal)&&...
857  all(all((cellfun('size',fieldVal,1)==1)&...
858  (cellfun('ndims',fieldVal)==2)));
859  if isempty(fieldVal)
860  varCell = {[strIndent ' |' filler ' ' fieldName ' : {}']};
861  if isnListStrOnly
862  fieldRowIndCVec{iField} = numel(listStr)+1;
863  fieldColIndCVec{iField} = numel(varCell{:})-1;
864  end
865  elseif (numel(fieldVal) > maxArrayLength)||~isMatOfStrings
866  varStr = createArraySize(fieldVal, 'Cell');
867  varCell = {[strIndent ' |' filler ' ' fieldName ' :' varStr]};
868  if isnListStrOnly
869  fieldRowIndCVec{iField} = numel(listStr)+1;
870  fieldColIndCVec{iField} = numel(varCell{:})-numel(varStr)+2;
871  end
872  else
873  if isnListStrOnly
874  [varCell,fieldRowIndCVec{iField},fieldColIndCVec{iField}]=...
875  formCellOfString(strIndent,fieldVal,...
876  maxFieldLength,[filler ' ' fieldName],...
877  FILLER_SYMBOL_CODE,DASH_SYMBOL_CODE);
878  fieldRowIndCVec{iField}=fieldRowIndCVec{iField}+numel(listStr);
879  else
880  varCell=...
881  formCellOfString(strIndent,fieldVal,...
882  maxFieldLength,[filler ' ' fieldName],...
883  FILLER_SYMBOL_CODE,DASH_SYMBOL_CODE);
884  end
885  end
886  listStr = [listStr; varCell]; %#ok<AGROW>
887  end
888  if nFields&&isnListStrOnly
889  leavesPathCVec=vertcat(leavesPathCVec,cellFields);
890  leavesRowIndCVec = vertcat(leavesRowIndCVec,fieldRowIndCVec);
891  leavesColIndCVec = vertcat(leavesColIndCVec,fieldColIndCVec);
892  end
893  %% Print unknown datatypes. These include objects and user-defined classes
894  nFields = length(otherFields);
895  fieldListStr = cell(nFields, 1);
896  if isnListStrOnly
897  fieldColIndVec = nan(nFields, 1);
898  end
899  for iField = 1 : nFields
900  fieldName = getFieldName(otherFields,iField);
901  fieldVal = otherVals{iField}; %#ok<NASGU>
902  filler = char(ones(1, maxFieldLength - length(fieldName) + 2)...
903  * DASH_SYMBOL_CODE);
904  varStr=[' ',evalc('display(fieldVal)')];
905  varStr=varStr(1:end-1);
906  fieldListStr{iField} = [strIndent ' |' filler ' ' fieldName ' :' varStr];
907  if isnListStrOnly
908  fieldColIndVec(iField) = numel(fieldListStr{iField})-numel(varStr)+2;
909  end
910  end
911  if nFields
912  if isnListStrOnly
913  leavesPathCVec = vertcat(leavesPathCVec,otherFields);
914  leavesRowIndCVec = vertcat(leavesRowIndCVec,...
915  num2cell(numel(listStr)+(1:nFields).'));
916  leavesColIndCVec = vertcat(leavesColIndCVec,...
917  num2cell(fieldColIndVec));
918  end
919  listStr = vertcat(listStr, fieldListStr);
920  end
921 
922  function fieldName=getFieldName(fieldNameList,iElem)
923  if iscell(fieldNameList)
924  fieldName=fieldNameList{iElem};
925  else
926  fieldName='';
927  end
928  end
929 
930  end
931  end
932 end
933 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
934 %% Inner functions
935 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
936 
937 function [varCell,rowIndVec,colIndVec]=formCellOfString(strIndent,fieldValue,maxFieldLength,filler,FILLER_SYMBOL_CODE,DASH_SYMBOL_CODE)
938 isnVarCellOnly=nargout>1;
939 matrixSize=size(fieldValue);
940 maxStringLength=max(max(cellfun('length',fieldValue)));
941 nVals = numel(fieldValue);
942 %adjustedFieldValue=cellfun(@(x)[x,...
943 % repmat(' ',1,maxStringLength-length(x)),'|'],...
944 % fieldValue,'UniformOutput',false);
945 addLenVec=maxStringLength-cellfun('length',fieldValue(:));
946 space = ' ';
947 adjustedFieldValue=cell(matrixSize);
948 for iVal=1:nVals
949  adjustedFieldValue{iVal}=horzcat(fieldValue{iVal},...
950  space(ones(1,addLenVec(iVal))),'|');
951 end
952 nDashes=(maxStringLength+1)* matrixSize(2)+1;
953 filler2 = char(ones(1, maxFieldLength + 6) * ...
954  FILLER_SYMBOL_CODE);
955 dashes = char(ones(1, nDashes)* ...
956  DASH_SYMBOL_CODE);
957 nRows = size(adjustedFieldValue,1);
958 varCell = cell(nRows+2,1);
959 if isnVarCellOnly
960  rowIndVec=(1:nRows+2).';
961  colIndVec=nan(nRows+2,1);
962 end
963 %
964 prefixStr=[strIndent ' |' filler2];
965 if isnVarCellOnly
966  colIndVec(1)=numel(prefixStr)+1;
967 end
968 varCell{1} = [prefixStr dashes];
969 %
970 % first line with field name
971 prefixStr=[strIndent ' |' filler ' : |'];
972 varStr=[adjustedFieldValue{1,:}];
973 if isnVarCellOnly
974  colIndVec(2)=numel(prefixStr)+1;
975 end
976 varCell{2} =[prefixStr varStr];
977 %
978 % second and higher number rows
979 prefixStr=[strIndent ' |' filler2 '|'];
980 if isnVarCellOnly
981  colIndVec(3:(nRows+1))=numel(prefixStr)+1;
982 end
983 for iRow = 2 : nRows
984  varStr = [adjustedFieldValue{iRow,:}];
985  varCell{iRow+1} = [prefixStr varStr];
986 end
987 prefixStr=[strIndent ' |' filler2];
988 if isnVarCellOnly
989  colIndVec(end)=numel(prefixStr)+1;
990 end
991 varCell{nRows+2} = [prefixStr dashes];
992 end
993 
994 %% FUNCTION: getIndentation
995 % This function creates the hierarchical indentations
996 
997 function [str, str2] = getIndentation(indent)
998 persistent outCVec;
999 if indent==1
1000  str = '';
1001  str2 = ' | ';
1002 else
1003  nOuts=numel(outCVec);
1004  if nOuts<indent
1005  x = ' | ';
1006  if nOuts>0
1007  str = outCVec{end};
1008  else
1009  str = '';
1010  end
1011  outCVec=horzcat(outCVec,cell(1,indent-nOuts));
1012  for iElem = nOuts+1 : indent
1013  str = cat(2, str, x);
1014  outCVec{iElem} = str;
1015  end
1016  str2 = str;
1017  str = outCVec{indent-1};
1018  else
1019  str = outCVec{indent-1};
1020  str2 = outCVec{indent};
1021  end
1022 end
1023 end
1024 
1025 %% FUNCTION: createArraySize
1026 % This function returns a string with the array size of the input variable
1027 % like: "[1x5 Array]" or "[2x3x5 Structure]" where 'Structure' and 'Array'
1028 % are defined by the type parameter
1029 
1030 function varStr = createArraySize(varName, type)
1031 varSize = size(varName);
1032 arraySizeStr = sprintf('%gx', varSize);
1033 arraySizeStr(length(arraySizeStr)) = [];
1034 varStr = [' [' arraySizeStr ' ' type ']'];
1035 end
1036 
1037 function [isLocalChanges,pathCVec,valCVec]=getleaveslist(SInp,SOld,isFullCheck)
1038 if nargin<3
1039  isFullCheck=true;
1040 end
1041 if isequaln(SInp,SOld)
1042  isLocalChanges=true;
1043  pathCVec=cell(0,1);
1044 else
1045  [isLocalChanges,pathCVec]=getleaveslistint(SInp,SOld);
1046 end
1047 if ~isLocalChanges
1048  pathCVec=cell(0,1);
1049  valCVec=cell(0,1);
1050  return;
1051 end
1052 if nargout>1
1053  nLeaves=length(pathCVec);
1054  valCVec=cell(nLeaves,1);
1055  for iLeave=1:nLeaves
1056  pathStr=pathCVec{iLeave};
1057  if pathStr(1)=='('
1058  valCVec{iLeave}=eval(['SInp' pathCVec{iLeave}]);
1059  else
1060  valCVec{iLeave}=eval(['SInp.' pathCVec{iLeave}]);
1061  end
1062  end
1063 end
1064  function [isLocalChanges,pathCVec]=getleaveslistint(SInp,SOld,fieldNameList)
1065  pathCVec=cell(0,1);
1066  if nargin>=3
1067  if isequaln(SInp,SOld)
1068  isLocalChanges=true;
1069  return;
1070  end
1071  else
1072  fieldNameList=fieldnames(SInp);
1073  end
1074  if isFullCheck
1075  sizeVec=size(SInp);
1076  oldFieldNameList=fieldnames(SOld);
1077  isLocalChanges=numel(fieldNameList)==numel(oldFieldNameList)&&...
1078  all(ismember(fieldNameList,oldFieldNameList))&&...
1079  isequal(sizeVec,size(SOld));
1080  if ~isLocalChanges||isempty(SInp)
1081  return;
1082  end
1083  else
1084  if isempty(SInp)
1085  isLocalChanges=true;
1086  return;
1087  end
1088  end
1089  nFields=numel(fieldNameList);
1090  isLocalChanges=true;
1091  %
1092  if nFields>0
1093  nElems=numel(SInp);
1094  fieldPathCVec=cell(nFields,nElems);
1095  isVector=nElems>1;
1096  if isVector
1097  if ~isFullCheck
1098  sizeVec=size(SInp);
1099  end
1100  subIndList=cell(1,length(sizeVec));
1101  end
1102  for iElem=1:nElems
1103  if isVector
1104  [subIndList{:}]=ind2sub(sizeVec,iElem);
1105  indexStr=sprintf('%d,',horzcat(subIndList{:}));
1106  indexStr=['(' indexStr(1:end-1) ')'];
1107  end
1108  for iField=1:nFields
1109  fieldName=fieldNameList{iField};
1110  SCur=SInp(iElem).(fieldName);
1111  SOldCur=SOld(iElem).(fieldName);
1112  isCurStruct=isstruct(SCur);
1113  if isFullCheck
1114  if isCurStruct~=isstruct(SOldCur)
1115  isLocalChanges=false;
1116  return;
1117  end
1118  end
1119  if isCurStruct
1120  curFieldNameList=fieldnames(SCur);
1121  if ~isempty(curFieldNameList)
1122  [isLocalChanges,fieldPathCVec{iField,iElem}]=...
1123  getleaveslistint(SCur,SOldCur,curFieldNameList);
1124  if ~isLocalChanges
1125  return;
1126  end
1127  curFieldPathCVec=fieldPathCVec{iField,iElem};
1128  nPaths=numel(curFieldPathCVec);
1129  if nElems==1
1130  if numel(SCur)==1
1131  prefixStr=horzcat(fieldName,'.');
1132  else
1133  prefixStr=fieldName;
1134  end
1135  else
1136  if numel(SCur)==1
1137  prefixStr=horzcat(indexStr,'.',fieldName,'.');
1138  else
1139  prefixStr=horzcat(indexStr,'.',fieldName);
1140  end
1141  end
1142  for iPath=1:nPaths
1143  curFieldPathCVec{iPath}=...
1144  horzcat(prefixStr,curFieldPathCVec{iPath});
1145  end
1146  fieldPathCVec{iField,iElem}=curFieldPathCVec;
1147  end
1148  elseif ~isequaln(SCur,SOldCur)
1149  if nElems==1
1150  fieldPathCVec{iField,iElem}={fieldName};
1151  else
1152  fieldPathCVec{iField,iElem}={horzcat(indexStr,'.',...
1153  fieldName)};
1154  end
1155  end
1156  end
1157  end
1158  pathCVec=vertcat(fieldPathCVec{:});
1159  end
1160  end
1161 end
function num2cell(in inpArray, in varargin)
NUM2CELL is an extension of Matlab built-in function "num2cell" designed to work correctly with empty...
function throwerror(in msgTag, in varargin)
THROWERROR works similarly to built-in ERROR function in case when there is no output arguments but s...
function parseparext(in args, in propNameValMat, in varargin)
PARSEPAREXT behaves in the same way as mxberry.core.parseparams but returns property values in a more...
function repmat(in inpArray, in varargin)
This class is responsible for displaying structure outline.
Definition: StructDisp.m:4
function isstring(in inpArray)
function ismember(in leftVec, in rightVec, in varargin)
ISMEMBER - ismember implementation for arrays of any type.
function catwithsep(in inpStrList, in sepStr)
CATWITHSEP concatenates input cell array of strings inserting a specified separator between the strin...
function cat(in dimNum, in varargin)