Home > matpower6.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 %   Copyright (c) 2013-2016, Power Systems Engineering Research Center (PSERC)
0056 %   by Ray Zimmerman, PSERC Cornell
0057 %
0058 %   This file is part of MATPOWER.
0059 %   Covered by the 3-clause BSD License (see LICENSE file for details).
0060 %   See http://www.pserc.cornell.edu/matpower/ for more info.
0061 
0062 DEBUG = 0;
0063 
0064 %% set default input args
0065 if nargin < 4
0066     parent = {};
0067     if nargin < 3
0068         opt = struct;
0069     end
0070 end
0071 
0072 %% set up options
0073 if isfield(opt, 'check')
0074     check = opt.check;
0075 else
0076     check = 0;
0077 end
0078 if isfield(opt, 'copy_mode')
0079     copy_mode = opt.copy_mode;
0080 else
0081     copy_mode = '';
0082 end
0083 if isfield(opt, 'valid_fields')
0084     valid_fields = opt.valid_fields;
0085 else
0086     valid_fields = d;
0087 end
0088 if isfield(opt, 'exceptions')
0089     exceptions = opt.exceptions;
0090 else
0091     exceptions = struct('name', {});
0092 end
0093 
0094 %% form parent string
0095 if DEBUG, fprintf('nested_struct_copy() : parent = %s\n', strjoin(parent, '.')); end
0096 if nargin > 3 && ~isempty(parent)
0097     pl = length(parent);
0098     tmp = cell(2, pl);
0099     tmp(1,:) = parent;
0100     tmp(2,1:pl-1) = {'.'};
0101     tmp(2,pl) = {''};
0102     parentstr = [tmp{:}];
0103 else
0104     parentstr = '';
0105 end
0106 
0107 %% process fields
0108 fields = fieldnames(s);
0109 for f = 1:length(fields)
0110     ff = fields{f};
0111     
0112     %% form full field name
0113     if isempty(parentstr)
0114         str = ff;
0115     else
0116         str = [parentstr '.' ff];
0117     end
0118     
0119     %% field doesn't exist in valid_fields
0120     if ~isfield(valid_fields, ff)
0121         if check > 0        %% throw an error
0122             error('nested_struct_copy: ''%s'' is not a valid field name', str);
0123         elseif check < 0    %% skip to next field
0124             continue;
0125         end
0126     end
0127     
0128     ck = check;
0129     cm = copy_mode;
0130     vf = valid_fields;
0131     
0132     %% look for an exception that matches this field
0133     if isempty(exceptions)
0134         k = [];
0135     else
0136         k = find(strcmp(str, {exceptions.name}'), 1);
0137         if ~isempty(k)
0138             if isfield(exceptions, 'copy_mode') && ...
0139                     ( ischar(exceptions(k).copy_mode) || ...
0140                      ~isempty(exceptions(k).copy_mode) )
0141                 cm = exceptions(k).copy_mode;
0142             end
0143             if isfield(exceptions, 'check') && ...
0144                     ~isempty(exceptions(k).check)
0145                 ck = exceptions(k).check;
0146             end
0147             if isfield(exceptions, 'valid_fields') && ...
0148                     ~isempty(exceptions(k).valid_fields)
0149                 vf = exceptions(k).valid_fields;
0150             end
0151         end
0152     end
0153 
0154     %% copy the field
0155     if strcmp(class(cm), 'function_handle')
0156         %% assign via function handle
0157         d.(ff) = cm(s.(ff));
0158     elseif ~isstruct(s.(ff)) || (ischar(cm) && strcmp(cm, '=')) || ...
0159             (isfield(d, ff) && ~isstruct(d.(ff)))
0160         %% non-struct OR struct with cm == '=' OR struct to non-struct copy
0161         %% assign directly
0162         d.(ff) = s.(ff);
0163     elseif isstruct(s.(ff)) && isempty(cm)
0164         %% assign via recursive call to nested_struct_copy()
0165         if isfield(vf, ff)
0166             newvf = vf.(ff);    %% use sub-field of valid_fields if present
0167         else
0168             newvf = struct;
0169         end
0170         newopt = struct( ...
0171             'check',        ck, ...
0172             'copy_mode',    cm, ...
0173             'valid_fields', newvf, ...
0174             'exceptions',   exceptions ...
0175         );
0176         if ~isfield(d, ff)  %% create field if it doesn't exist in d
0177             d.(ff) = struct;
0178         end
0179         d.(ff) = nested_struct_copy(d.(ff), s.(ff), newopt, {parent{:}, ff});
0180     else
0181         error('nested_struct_copy: OPT.copy_mode must be '''', ''='', or a function handle\n');
0182     end
0183 end

Generated on Fri 16-Dec-2016 12:45:37 by m2html © 2005