Home > matpower5.0 > nested_struct_copy.m

nested_struct_copy

PURPOSE ^

NESTED_STRUCT_COPY Copies values from one nested struct to another.

SYNOPSIS ^

function d = nested_struct_copy(d, s, opt, parent)

DESCRIPTION ^

NESTED_STRUCT_COPY  Copies values from one nested struct to another.

   DS = NESTED_STRUCT_COPY(D, S)
   DS = NESTED_STRUCT_COPY(D, S, OPT)
   DS = NESTED_STRUCT_COPY(D, S, OPT, PARENT)

   DS = NESTED_STRUCT_COPY(D, S) copies values from a source struct S to
   a destination struct D in a nested, recursive manner. That is, the value
   of each field in S is copied directly to the corresponding field in D,
   unless that value is itself a struct, in which case the copy is done
   via a recursive call to NESTED_STRUCT_COPY.

   Inputs:
       D - the destination struct that values are copied to
       S - the source struct containing the values to be copied from
       OPT - (optional) options struct controlling copy behavior, with fields:
           check - check that field name is valid, by looking for it in
                   OPT.valid_fields (defaults to D), before copying
                0 - (default) do not do any field name checking
                1 - fatal error if S contains an invalid field name
               -1 - skip any invalid fields in S
           copy_mode - how to handle assignment of fields that are structs
               ''          - (default) recursive call to nested_struct_copy()
               '='         - direct assignment, D.<field> = S.<field>
               @<function> - pointer to a function to be called with field
                             from S, returning field to assign to D
                             D.<field> = <function>(S.<field>)
           valid_fields - struct containing, the heirarchy of all of (and
                       only) the valid field names (field values are ignored)
           exceptions - a struct array, with the following fields, defining
                       exceptions to the top-level options
               name        - name (can be multi-level) of field to which
                             exception applies
               check       - same as OPT.check,     only for specified field
               copy_mode   - same as OPT.copy_mode, only for specified field
               valid_fields- same as OPT.valid_fields,   for specified field
       PARENT - cell array of parent field names used by NESTED_STRUCT_COPY
               with recursive calls to allow checking of multi-level field
               field names in exceptions, e.g. when called recursively to
               assign the field S.info.address.home the value of PARENT would
               be {'info', 'address'}.

   Output:
       DS - the combined destination struct 

   Examples:
       See T_NESTED_STRUCT_COPY (t_nested_struct_copy.m).

   TO DO:  Finish example.
           Implement an error that passes back the full field string of
           an invalid field so that mpoption can refer to it as option foo.

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SOURCE CODE ^

0001 function d = nested_struct_copy(d, s, opt, parent)
0002 %NESTED_STRUCT_COPY  Copies values from one nested struct to another.
0003 %
0004 %   DS = NESTED_STRUCT_COPY(D, S)
0005 %   DS = NESTED_STRUCT_COPY(D, S, OPT)
0006 %   DS = NESTED_STRUCT_COPY(D, S, OPT, PARENT)
0007 %
0008 %   DS = NESTED_STRUCT_COPY(D, S) copies values from a source struct S to
0009 %   a destination struct D in a nested, recursive manner. That is, the value
0010 %   of each field in S is copied directly to the corresponding field in D,
0011 %   unless that value is itself a struct, in which case the copy is done
0012 %   via a recursive call to NESTED_STRUCT_COPY.
0013 %
0014 %   Inputs:
0015 %       D - the destination struct that values are copied to
0016 %       S - the source struct containing the values to be copied from
0017 %       OPT - (optional) options struct controlling copy behavior, with fields:
0018 %           check - check that field name is valid, by looking for it in
0019 %                   OPT.valid_fields (defaults to D), before copying
0020 %                0 - (default) do not do any field name checking
0021 %                1 - fatal error if S contains an invalid field name
0022 %               -1 - skip any invalid fields in S
0023 %           copy_mode - how to handle assignment of fields that are structs
0024 %               ''          - (default) recursive call to nested_struct_copy()
0025 %               '='         - direct assignment, D.<field> = S.<field>
0026 %               @<function> - pointer to a function to be called with field
0027 %                             from S, returning field to assign to D
0028 %                             D.<field> = <function>(S.<field>)
0029 %           valid_fields - struct containing, the heirarchy of all of (and
0030 %                       only) the valid field names (field values are ignored)
0031 %           exceptions - a struct array, with the following fields, defining
0032 %                       exceptions to the top-level options
0033 %               name        - name (can be multi-level) of field to which
0034 %                             exception applies
0035 %               check       - same as OPT.check,     only for specified field
0036 %               copy_mode   - same as OPT.copy_mode, only for specified field
0037 %               valid_fields- same as OPT.valid_fields,   for specified field
0038 %       PARENT - cell array of parent field names used by NESTED_STRUCT_COPY
0039 %               with recursive calls to allow checking of multi-level field
0040 %               field names in exceptions, e.g. when called recursively to
0041 %               assign the field S.info.address.home the value of PARENT would
0042 %               be {'info', 'address'}.
0043 %
0044 %   Output:
0045 %       DS - the combined destination struct
0046 %
0047 %   Examples:
0048 %       See T_NESTED_STRUCT_COPY (t_nested_struct_copy.m).
0049 %
0050 %   TO DO:  Finish example.
0051 %           Implement an error that passes back the full field string of
0052 %           an invalid field so that mpoption can refer to it as option foo.
0053 
0054 %   MATPOWER
0055 %   $Id: nested_struct_copy.m 2229 2013-12-11 01:28:09Z ray $
0056 %   by Ray Zimmerman, PSERC Cornell
0057 %   Copyright (c) 2013 by Power System Engineering Research Center (PSERC)
0058 %
0059 %   This file is part of MATPOWER.
0060 %   See http://www.pserc.cornell.edu/matpower/ for more info.
0061 %
0062 %   MATPOWER is free software: you can redistribute it and/or modify
0063 %   it under the terms of the GNU General Public License as published
0064 %   by the Free Software Foundation, either version 3 of the License,
0065 %   or (at your option) any later version.
0066 %
0067 %   MATPOWER is distributed in the hope that it will be useful,
0068 %   but WITHOUT ANY WARRANTY; without even the implied warranty of
0069 %   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0070 %   GNU General Public License for more details.
0071 %
0072 %   You should have received a copy of the GNU General Public License
0073 %   along with MATPOWER. If not, see <http://www.gnu.org/licenses/>.
0074 %
0075 %   Additional permission under GNU GPL version 3 section 7
0076 %
0077 %   If you modify MATPOWER, or any covered work, to interface with
0078 %   other modules (such as MATLAB code and MEX-files) available in a
0079 %   MATLAB(R) or comparable environment containing parts covered
0080 %   under other licensing terms, the licensors of MATPOWER grant
0081 %   you additional permission to convey the resulting work.
0082 
0083 DEBUG = 0;
0084 
0085 %% set default input args
0086 if nargin < 4
0087     parent = {};
0088     if nargin < 3
0089         opt = struct;
0090     end
0091 end
0092 
0093 %% set up options
0094 if isfield(opt, 'check')
0095     check = opt.check;
0096 else
0097     check = 0;
0098 end
0099 if isfield(opt, 'copy_mode')
0100     copy_mode = opt.copy_mode;
0101 else
0102     copy_mode = '';
0103 end
0104 if isfield(opt, 'valid_fields')
0105     valid_fields = opt.valid_fields;
0106 else
0107     valid_fields = d;
0108 end
0109 if isfield(opt, 'exceptions')
0110     exceptions = opt.exceptions;
0111 else
0112     exceptions = struct('name', {});
0113 end
0114 
0115 %% form parent string
0116 if DEBUG, fprintf('nested_struct_copy() : parent = %s\n', strjoin(parent, '.')); end
0117 if nargin > 3 && ~isempty(parent)
0118     tmp = cell(2, length(parent));
0119     tmp(1,:) = parent;
0120     tmp(2,1:length(parent)-1) = {'.'};
0121     parentstr = [tmp{:}];
0122 else
0123     parentstr = '';
0124 end
0125 
0126 %% process fields
0127 fields = fieldnames(s);
0128 for f = 1:length(fields)
0129     ff = fields{f};
0130     [ck, cm, vf] = deal(check, copy_mode, valid_fields);
0131     
0132     %% form full field name
0133     if isempty(parentstr)
0134         str = ff;
0135     else
0136         str = [parentstr '.' ff];
0137     end
0138     
0139     %% field doesn't exist in valid_fields
0140     if ~isfield(valid_fields, ff)
0141         if ck > 0        %% throw an error
0142             error('nested_struct_copy: ''%s'' is not a valid field name', str);
0143         elseif ck < 0    %% skip to next field
0144             continue;
0145         end
0146     end
0147     
0148     %% look for an exception that matches this field
0149     if isempty(exceptions)
0150         k = [];
0151     else
0152         k = find(cellfun(@strcmp, {exceptions.name}', ...
0153                          cellstr(char(ones(length(exceptions),1) * str)) ));
0154         if ~isempty(k)
0155             if isfield(exceptions, 'copy_mode') && ...
0156                     ( ischar(exceptions(k).copy_mode) || ...
0157                      ~isempty(exceptions(k).copy_mode) )
0158                 cm = exceptions(k).copy_mode;
0159             end
0160             if isfield(exceptions, 'check') && ...
0161                     ~isempty(exceptions(k).check)
0162                 ck = exceptions(k).check;
0163             end
0164             if isfield(exceptions, 'valid_fields') && ...
0165                     ~isempty(exceptions(k).valid_fields)
0166                 vf = exceptions(k).valid_fields;
0167             end
0168         end
0169     end
0170 
0171     %% copy the field
0172     if strcmp(class(cm), 'function_handle')
0173         %% assign via function handle
0174         d.(ff) = cm(s.(ff));
0175     elseif ~isstruct(s.(ff)) || (ischar(cm) && strcmp(cm, '='))
0176         %% non-struct or struct with cm == '=', assign directly
0177         d.(ff) = s.(ff);
0178     elseif isstruct(s.(ff)) && isempty(cm)
0179         %% assign via recursive call to nested_struct_copy()
0180         if isfield(vf, ff)
0181             newvf = vf.(ff);    %% use sub-field of valid_fields if present
0182         else
0183             newvf = struct;
0184         end
0185         newopt = struct( ...
0186             'check',        ck, ...
0187             'copy_mode',    cm, ...
0188             'valid_fields', newvf, ...
0189             'exceptions',   exceptions ...
0190         );
0191         if ~isfield(d, ff)  %% create field if it doesn't exist in d
0192             d.(ff) = struct;
0193         end
0194         d.(ff) = nested_struct_copy(d.(ff), s.(ff), newopt, {parent{:}, ff});
0195     else
0196         error('nested_struct_copy: OPT.copy_mode must be '''', ''='', or a function handle\n');
0197     end
0198 end

Generated on Mon 26-Jan-2015 15:21:31 by m2html © 2005