Code covered by the BSD License  

Highlights from
fRMField

image thumbnail
from fRMField by Jan Simon
Remove a field from a struct efficiently - fast C-Mex

TestfRMField(doSpeed)
function TestfRMField(doSpeed)
% Automatic test: fRMField
% This is a routine for automatic testing. It is not needed for processing and
% can be deleted or moved to a folder, where it does not bother.
%
% TestfRMField(doSpeed)
% INPUT:
%   doSpeed: Optional logical flag to trigger time consuming speed tests.
%            Default: TRUE. If no speed test is defined, this is ignored.
% OUTPUT:
%   On failure the test stops with an error.
%
% Tested: Matlab 6.5, 7.7, 7.8, WinXP, 32 bit
% Author: Jan Simon, Heidelberg, (C) 2010 matlab.THISYEAR(a)nMINUSsimon.de

% $JRev: R0j V:020 Sum:AB1BaJFwql1C Date:19-Aug-2010 23:57:17 $
% $License: NOT_RELEASED $
% $File: Tools\UnitTests_\TestfRMField.m $

% Initialize: ==================================================================
% Global Interface: ------------------------------------------------------------
FuncName = mfilename;

% Initial values: --------------------------------------------------------------
% Program Interface: -----------------------------------------------------------
if nargin == 0
   doSpeed = true;
end

% User Interface: --------------------------------------------------------------
% Do the work: =================================================================
disp(['== Test fRMField  ', datestr(now, 0)]);
disp(['  Version: ', which('fRMField')]);
pause(0.01);

fprintf('\n== Known answer tests:\n');

% Empty array:
S = [];
R = fRMField(S, '');
if isempty(R)
   disp('  ok: remove '''' from []');
else
   error([FuncName, ': Remove '''' from []']);
end

R = fRMField(S, 'field');
if isempty(R)
   disp('  ok: remove ''field'' from []');
else
   error([FuncName, ': Remove ''field'' from []']);
end

R = fRMField(S, {});
if isempty(R)
   disp('  ok: remove {} from []');
else
   error([FuncName, ': Remove {} from []']);
end

R = fRMField(S, {''});
if isempty(R)
   disp('  ok: remove {''''} from []');
else
   error([FuncName, ': Remove {''''} from []']);
end

R = fRMField(S, {'field'});
if isempty(R)
   disp('  ok: remove {''field''} from []');
else
   error([FuncName, ': Remove {''field''} from []']);
end

R = fRMField(S, {'field1', 'field2'});
if isempty(R)
   disp('  ok: remove {''field1'', ''field2''} from []');
else
   error([FuncName, ': Remove {''field1'', ''field2''} from []']);
end

% Empty struct:
S = struct([]);
R = fRMField(S, '');
if isempty(fieldnames(R))
   disp('  ok: remove '''' from struct([])');
else
   error([FuncName, ': Remove '''' from struct([])']);
end

R = fRMField(S, 'field');
if isempty(fieldnames(R))
   disp('  ok: remove ''field'' from struct([])');
else
   error([FuncName, ': Remove ''field'' from struct([])']);
end

R = fRMField(S, {});
if isempty(R)
   disp('  ok: remove {} from struct([])');
else
   error([FuncName, ': Remove {} from struct([])']);
end

R = fRMField(S, {''});
if isempty(R)
   disp('  ok: remove {''''} from struct([])');
else
   error([FuncName, ': Remove {''''} from struct([])']);
end

R = fRMField(S, {'field'});
if isempty(R)
   disp('  ok: remove {''field''} from struct([])');
else
   error([FuncName, ': Remove {''field''} from struct([])']);
end

R = fRMField(S, {'field1', 'field2'});
if isempty(R)
   disp('  ok: remove {''field1'', ''field2''} from struct([])');
else
   error([FuncName, ...
         ': Remove {''field1'', ''field2''} from struct([])']);
end

% Struct with 1 field:
S = struct('A', 1);
R = fRMField(S, '');
if isequal(S, R)
   disp('  ok: remove '''' from S.A');
else
   error([FuncName, ': Remove '''' from S.A']);
end

R = fRMField(S, 'field');
if isequal(S, R)
   disp('  ok: remove ''field'' from S.A');
else
   error([FuncName, ': Remove ''field'' from S.A']);
end

R = fRMField(S, {});
if isequal(S, R)
   disp('  ok: remove {} from S.A');
else
   error([FuncName, ': Remove {} from S.A']);
end

R = fRMField(S, {''});
if isequal(S, R)
   disp('  ok: remove {''''} from S.A');
else
   error([FuncName, ': Remove {''''} from S.A']);
end

R = fRMField(S, {'field'});
if isequal(S, R)
   disp('  ok: remove {''field''} from S.A');
else
   error([FuncName, ': Remove {''field''} from S.A']);
end

R = fRMField(S, {'field1', 'field2'});
if isequal(S, R)
   disp('  ok: remove {''field1'', ''field2''} from S.A');
else
   error([FuncName, ': Remove {''field1'', ''field2''} from S.A']);
end

% Remove existing fields:
R = fRMField(S, 'A');
if isempty(Xfieldnames(R))
   disp('  ok: remove ''A'' from S.A');
else
   error([FuncName, ': Remove ''A'' from S.A']);
end

R = fRMField(S, {'A'});
if isempty(Xfieldnames(R))
   disp('  ok: remove {''A''} from S.A');
else
   error([FuncName, ': Remove {''A''} from S.A']);
end

R = fRMField(S, {'A', 'field'});
if isempty(Xfieldnames(R))
   disp('  ok: remove {''A'', ''field''} from S.A');
else
   error([FuncName, ': Remove {''A'', ''field''} from S.A']);
end

% S with 2 fields:
S = struct('A', 1, 'B', 2);
Want = struct('B', 2);
R = fRMField(S, 'A');
if isequal(R, Want)
   disp('  ok: remove ''A'' from S.(A,B)');
else
   error([FuncName, ': Remove ''A'' from S.(A,B)']);
end

R = fRMField(S, {'A'});
if isequal(R, Want)
   disp('  ok: remove {''A''} from S.(A,B)');
else
   error([FuncName, ': Remove {''A''} from S.(A,B)']);
end

R = fRMField(S, {'A', 'field'});
if isequal(R, Want)
   disp('  ok: remove {''A'', ''field''} from S.(A,B)');
else
   error([FuncName, ': Remove {''A'', ''field''} from S.(A,B)']);
end

R = fRMField(S, {'field', 'A'});
if isequal(R, Want)
   disp('  ok: remove {''field'', ''A''} from S.(A,B)');
else
   error([FuncName, ': Remove {''field'', ''A''} from S.(A,B)']);
end

R = fRMField(S, {'A', 'B'});
if isempty(Xfieldnames(R))
   disp('  ok: remove {''A'', ''B''} from S.(A,B)');
else
   error([FuncName, ': Remove {''A'', ''B''} from S.(A,B)']);
end

R = fRMField(S, {'B', 'A'});
if isempty(Xfieldnames(R))
   disp('  ok: remove {''B'', ''A''} from S.(A,B)');
else
   error([FuncName, ': Remove {''B'', ''A''} from S.(A,B)']);
end

R = fRMField(S, {'A', 'B', 'field'});
if isempty(Xfieldnames(R))
   disp('  ok: remove {''A'', ''B'', ''field''} from S.(A,B)');
else
   error([FuncName, ': Remove {''A'', ''B'', ''field''} from S.(A,B)']);
end

R = fRMField(S, {'B', 'field', 'A'});
if isempty(Xfieldnames(R))
   disp('  ok: remove {''B'', ''field'', ''A''} from S.(A,B)');
else
   error([FuncName, ': Remove {''B'', ''field'', ''A''} from S.(A,B)']);
end

% Struct array:
S    = struct('A', {1, 11}, 'B', {2, 22});
Want = struct('B', {2, 22});
R    = fRMField(S, 'A');
if isequal(R, Want)
   disp('  ok: remove ''A'' from S(1:2).(A,B)');
else
   error([FuncName, ': Remove ''A'' from S(1:2).(A,B)']);
end

R = fRMField(S, {'A'});
if isequal(R, Want)
   disp('  ok: remove {''A''} from S(1:2).(A,B)');
else
   error([FuncName, ': Remove {''A''} from S(1:2).(A,B)']);
end

R = fRMField(S, {'A', 'field'});
if isequal(R, Want)
   disp('  ok: remove {''A'', ''field''} from S(1:2).(A,B)');
else
   error([FuncName, ': Remove {''A'', ''field''} from S(1:2).(A,B)']);
end

R = fRMField(S, {'field', 'A'});
if isequal(R, Want)
   disp('  ok: remove {''field'', ''A''} from S(1:2).(A,B)');
else
   error([FuncName, ': Remove {''field'', ''A''} from S(1:2).(A,B)']);
end

R = fRMField(S, {'A', 'B'});
if isempty(Xfieldnames(R))
   disp('  ok: remove {''A'', ''B''} from S(1:2).(A,B)');
else
   error([FuncName, ': Remove {''A'', ''B''} from S(1:2).(A,B)']);
end

R = fRMField(S, {'B', 'A'});
if isempty(Xfieldnames(R))
   disp('  ok: remove {''B'', ''A''} from S(1:2).(A,B)');
else
   error([FuncName, ': Remove {''B'', ''A''} from S(1:2).(A,B)']);
end

R = fRMField(S, {'A', 'B', 'field'});
if isempty(Xfieldnames(R))
   disp('  ok: remove {''A'', ''B'', ''field''} from S(1:2).(A,B)');
else
   error([FuncName, ...
         ': Remove {''A'', ''B'', ''field''} from S(1:2).(A,B)']);
end

R = fRMField(S, {'B', 'field', 'A'});
if isempty(Xfieldnames(R))
   disp('  ok: remove {''B'', ''field'', ''A''} from S(1:2).(A,B)');
else
   error([FuncName, ...
         ': Remove {''B'', ''field'', ''A''} from S(1:2).(A,B)']);
end

% ------------------------------------------------------------------------------
fprintf('\n== Test Speed:\n');
minT = eps;

% Find a suiting number of loops:
S = struct('A', 1, 'B', zeros(1, 100), 'C', ones(100, 100));
if doSpeed
   iLoop     = 0;
   startTime = cputime;
   while cputime - startTime < 1.0
      v     = fRMField(S, 'A'); %#ok<NASGU>
      clear('v');
      iLoop = iLoop + 1;
   end
   nDigit = max(1, floor(log10(max(1, iLoop))) - 1);
   nLoops = max(2, round(iLoop / 10 ^ nDigit) * 10 ^ nDigit);
else
   disp('  Reduced speed measurement - displayed times are meaningless!');
   nLoops = 2;
end

S = struct('A', 1, 'B', zeros(1, 100), 'C', ones(100, 100));

tic;
for i = 1:nLoops
   v = rmfield(S, 'C'); %#ok<NASGU>
   clear('v');
end
etM = toc + minT;

tic;
for i = 1:nLoops
   v = fRMField(S, 'C'); %#ok<NASGU>
   clear('v');
end
etOpt = toc + minT;

fprintf(['  Remove 1 field from Struct with 3 fields (%d loops):\n', ...
      '    RMFIELD:  %.2f sec\n', ...
      '    fRMField: %.2f sec  ==>  %.1f%% of RMFIELD\n\n'], ...
   nLoops, etM, etOpt, 100 * etOpt / etM);

% ------------------------------
nField = 100;
Field  = cell(nField, 1);
Data   = cell(nField, 1);
for i = 1:nField
   Field{i} = sprintf('Field%.3d', i);
   Data{i}  = zeros(10);
end
S = cell2struct(Data, Field);

if doSpeed
   iLoop     = 0;
   startTime = cputime;
   while cputime - startTime < 1.0
      for j = 1:nField
         v = rmfield(S, Field{j});  %#ok<NASGU>
         clear('v');
      end
      iLoop = iLoop + 1;
   end
   nLoops = ceil(iLoop / (cputime - startTime));
else
   nLoops = 2;
end

tic;
for i = 1:nLoops
   for j = 1:nField
      v = rmfield(S, Field{j});  %#ok<NASGU>
      clear('v');
   end
end
etM = toc + minT;

tic;
for i = 1:nLoops
   for j = 1:nField
      v = fRMField(S, Field{j});  %#ok<NASGU>
      clear('v');
   end
end
etOpt = toc + minT;

fprintf(['  Remove 1 field from Struct with %d fields (%d loops):\n', ...
      '    RMFIELD:  %.2f sec\n', ...
      '    fRMField: %.2f sec  ==>  %.1f%% of RMFIELD\n\n'], ...
   nField, nLoops, etM, etOpt, 100 * etOpt / etM);

% -----------------------------
remove = Field(1:2:end);
nLoops = nLoops * 50;

tic;
for i = 1:nLoops
   v = rmfield(S, remove);  %#ok<NASGU>
   clear('v');
end
etM = toc + minT;

tic;
for i = 1:nLoops
   v = fRMField(S, remove);  %#ok<NASGU>
   clear('v');
end
etOpt = toc + minT;

fprintf(['  Remove %d field from Struct with %d fields (%d loops):\n', ...
      '    RMFIELD:  %.2f sec\n', ...
      '    fRMField: %.2f sec  ==>  %.1f%% of RMFIELD\n\n'], ...
   length(remove), nField, nLoops, etM, etOpt, 100 * etOpt / etM);

% Bye:
fprintf('== fRMField seems to work well.\n');

return;

% ******************************************************************************
function F = Xfieldnames(S)
% Reply fieldnames and {} if input is []:

if isa(S, 'struct')
   F = fieldnames(S);
elseif isempty(S)
   F = {};
else
   error('TestfRMField(Xfieldnames): neither struct nor []?!');
end

return;

Contact us