function s=cosmo_structjoin(varargin)
% joins values in structs or key-value pairs
%
% s=cosmo_structjoin(arg1, arg2, ...)
%
% Inputs:
% arg{X} Any of the following:
% - if a cell, then it should contain structs or key-value
% pairs
% - if a struct, then value=arg{X}.(key) for each key in
% fieldnames(arg{X}) is stored as s.(key)=value.
% In this case, it is required that the struct is of size
% 1x1.
% - if a string, then it is stored as s.(arg{X})=arg{X+1}
%
% Returns:
% s Struct with fieldnames and their associated values
% as key-value pairs. Values in the input are stored from
% left-to-right.
%
% Example:
% x=cosmo_structjoin('a',{1;2},'b',{3,4});
% cosmo_disp(x);
% %|| .a
% %|| { [ 1 ]
% %|| [ 2 ] }
% %|| .b
% %|| { [ 3 ] [ 4 ] }
% y=cosmo_structjoin(x,'a',66,'x',x,{'c','hello'});
% cosmo_disp(y);
% %|| .a
% %|| [ 66 ]
% %|| .b
% %|| { [ 3 ] [ 4 ] }
% %|| .x
% %|| .a
% %|| { [ 1 ]
% %|| [ 2 ] }
% %|| .b
% %|| { [ 3 ] [ 4 ] }
% %|| .c
% %|| 'hello'
%
% % simulate a function definition function out=f(varargin)
% % to illustrate overriding default values
% varargin={'radius',2,'nsamples',12};
% defaults=struct();
% defaults.radius=10;
% defaults.nfeatures=2;
% params=cosmo_structjoin(defaults,varargin);
% cosmo_disp(params);
% %|| .radius
% %|| [ 2 ]
% %|| .nfeatures
% %|| [ 2 ]
% %|| .nsamples
% %|| [ 12 ]
%
% % illustrate overriding values in 'sub-structs' (structs as values in
% % other structs)
% v=struct();
% v.a.foo={1,2};
% v.b=3;
% w=struct();
% w.a.bar=[2,3];
% w.c=4;
% j=cosmo_structjoin(v,w);
% cosmo_disp(j)
% %|| .a
% %|| .foo
% %|| { [ 1 ] [ 2 ] }
% %|| .bar
% %|| [ 2 3 ]
% %|| .b
% %|| [ 3 ]
% %|| .c
% %|| [ 4 ]
%
%
% Notes:
% - this function can be used to parse input arguments (including
% varargin in a "'key1',value1,'key2',value2,..." fashion)
%
% # For CoSMoMVPA's copyright information and license terms, #
% # see the COPYING file distributed with CoSMoMVPA. #
% use a wrapper so that recursive calls can be forwarded to the wrapper
% without using mfilename
s=structjoin_wrapper(varargin{:});
function s=structjoin_wrapper(varargin)
s=struct(); % output
n=numel(varargin);
k=0;
while k<n
% go over all input arguments
k=k+1;
v=varargin{k}; %k-th argument
if iscell(v)
if isempty(v)
continue;
end
% use recursion
v=structjoin_wrapper(v{:});
end
if isstruct(v)
if numel(v)~=1
error(['only singleton structs (of size 1x1) '...
'are supported']);
end
% overwrite any values in s
fns=fieldnames(v);
for j=1:numel(fns);
fn=fns{j};
v_fn=v.(fn);
if isstruct(v_fn) && isfield(s,fn) && isstruct(s.(fn))
s.(fn)=structjoin_wrapper(s.(fn),v_fn);
else
s.(fn)=v_fn;
end
end
elseif ischar(v)
% <key>, <value> pair
if k+1>n
% cannot be last argument
error('Missing argument after key ''%s''', v);
end
% move forward to next argument and get value
k=k+1;
vv=varargin{k};
if isstruct(vv) && isfield(s,v) && isstruct(s.(v))
s.(v)=structjoin_wrapper(s.(v),vv);
else
s.(v)=vv;
end
else
error(['Illegal input at position %d: expected cell, struct, ',...
'or string'], k);
end
end