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

Generated on Fri 20-Mar-2015 18:23:34 by m2html © 2005