function tf=cosmo_isfield(s, name, raise)
% checks the presence of (possibly nested) fieldnames in a struct
%
% tf=cosmo_isfield(s, name, raise)
%
% Inputs:
% s struct for which fieldnames are assessed
% name string or cell of strings with fieldnames.
% Fieldnames can take the form 'a.b.c', meaning that
% it checks for s to have a field 'a', s.a to have a
% field 'b', and s.a.b to have a field 'c'.
% raise Optional logical indicating whether an error should be
% raised if any fieldname is not present (default:
% false)
%
% Output:
% tf Nx1 logical array, where N=1 if name is a string and
% N=numel(name) if name is a cell. Each value is true
% only if the corresponding fieldname is present in s.
%
% Examples:
% % make a simple struct
% s=struct();
% s.a=1;
% s.b=2;
% s.c.d.e=3;
% %
% % check for presence of 'a' in s
% cosmo_isfield(s,'a')
% %|| true
% %
% % check for present of 'c' in s, 'd' in s.d, and 'e' in s.c.d
% cosmo_isfield(s,'c.d.e')
% %|| true
% %
% % check for the present of four fields (two are absent)
% cosmo_isfield(s,{'c.d.e','c.d.f','a','x'})
% %|| [true, false, true, false]
% %
% % this would raise an error if 'c.d.e' is not present
% cosmo_isfield(s,'c.not_present',true)
% %|| error('Struct does not have field .not_present')
%
%
% Notes:
% - Unlike the builtin 'isfield' function
% * if a struct x has more than one element (i.e. numel(x)>1), then
% the presence of sub-fields in the struct is not supported; in this
% case, either an error is thrown (if raise=true), or false is
% returned (if raise=false).
% * this function can check for multiple fields in one call and can
% check for the presence of nested structs
% * this function accepts non-structs as the first input argument; the
% result is then false for every name
%
% See also: isfield
%
% # For CoSMoMVPA's copyright information and license terms, #
% # see the COPYING file distributed with CoSMoMVPA. #
if nargin<3
raise=false;
end
if ischar(name)
tf=single_isfield(s, name, raise);
elseif iscellstr(name)
n=numel(name);
tf=false(1,n);
for k=1:n
tf(k)=single_isfield(s,name{k},raise);
end
else
error('Second argument must be string or cell with strings');
end
function s=key_name(keys, index)
s=cosmo_strjoin(keys(1:index),'.');
function has_key=single_isfield(s, name, raise)
has_key=false;
if all(name~='.')
keys={name};
else
keys=regexp(name,'\.','split');
end
nkeys=numel(keys);
value=s;
for j=1:nkeys
if ~isstruct(value)
if raise
if j==1
error('Input is not a struct');
else
error('Not a struct: .%s', key_name(keys,j));
end
end
return;
end
if numel(value)~=1 && j~=nkeys
if raise
error('Unsupported non-singleton struct');
end
return
end
key=keys{j};
if ~isfield(value,key)
if raise
error('Struct does not have field .%s',key_name(keys,j));
end
return;
end
if j<nkeys
value=value.(key);
end
end
has_key=true;