Skip to content

Commit 065dbf8

Browse files
authored
Allow using empty array when indexing on DataStub object (#605)
* Coarse fix for #595 * Add test * Update test to test different data types * Make local function getEmptyRepresentation more explicit * Remove unused code from test
1 parent c3eedb7 commit 065dbf8

File tree

2 files changed

+68
-1
lines changed

2 files changed

+68
-1
lines changed

+tests/+unit/dataStubTest.m

+40
Original file line numberDiff line numberDiff line change
@@ -103,3 +103,43 @@ function testObjectCopy(testCase)
103103
tests.util.verifyContainerEqual(testCase, nwbNew, nwb);
104104
nwbExport(nwbNew, 'new.nwb');
105105
end
106+
107+
function testLoadWithEmptyIndices(testCase)
108+
nwb = NwbFile(...
109+
'identifier', 'DATASTUB',...
110+
'session_description', 'test datastub object copy',...
111+
'session_start_time', datetime());
112+
113+
% Add different datatypes to a table, and try to read them in later
114+
% using empty indexing on a DataStub representation
115+
tableToExport = table( ...
116+
{'test'}, ... % Cell
117+
0, ... % Double
118+
false, ... % Logical
119+
struct('x', 1, 'y', 1, 'z', 1) ... % Struct (compound)
120+
);
121+
dynamicTable = util.table2nwb(tableToExport);
122+
nwb.acquisition.set('Test', dynamicTable);
123+
124+
nwbExport(nwb, 'testLoadWithEmptyIndices.nwb')
125+
126+
nwbIn = nwbRead('testLoadWithEmptyIndices.nwb', 'ignorecache');
127+
128+
importedTable = nwbIn.acquisition.get('Test');
129+
varNames = transpose( string(importedTable.colnames) );
130+
131+
for iVarName = varNames
132+
iDataStub = importedTable.vectordata.get(iVarName).data;
133+
134+
testCase.assertClass(iDataStub, 'types.untyped.DataStub')
135+
value = iDataStub([]);
136+
testCase.assertEmpty(value)
137+
138+
if isstruct(tableToExport.(iVarName))
139+
expectedClass = 'table';
140+
else
141+
expectedClass = class(tableToExport.(iVarName));
142+
end
143+
testCase.assertClass(value, expectedClass)
144+
end
145+
end

+types/+untyped/@DataStub/load_mat_style.m

+28-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,14 @@
3434
, iDimension, dimensionSize);
3535
end
3636

37-
if isscalar(userSelection) && ~ischar(userSelection{1})
37+
if isscalar(userSelection) && isempty(userSelection{1})
38+
% If userselection (indices) is empty, get the first element of this
39+
% DataStub and try to return an empty representation of that type.
40+
data = obj.load_mat_style(1);
41+
data = getEmptyRepresentation(data);
42+
return
43+
44+
elseif isscalar(userSelection) && ~ischar(userSelection{1})
3845
% linear index into the fast dimension.
3946
orderedSelection = unique(userSelection{1});
4047

@@ -200,3 +207,23 @@
200207
indexKeyIndex((indexKeyIndexNextIndex+1):end) = 1;
201208
end
202209
end
210+
211+
function emptyInstance = getEmptyRepresentation(nonEmptyInstance)
212+
try
213+
emptyInstance = nonEmptyInstance;
214+
if istable(nonEmptyInstance)
215+
% To make an empty table instance, we need to use row/column colon
216+
% indices to clear all the table's data. We want to keep the
217+
% original table's metadata, like variable names etc, so we clear
218+
% the table data instead of creating a new empty table with
219+
% table.empty
220+
emptyInstance(:, :) = [];
221+
else
222+
% All other types should support linear indexing.
223+
emptyInstance(:) = [];
224+
end
225+
catch ME
226+
error('Failed to retrieve empty type for value of class "%s". Reason:\n%s', ...
227+
class(nonEmptyInstance), ME.message)
228+
end
229+
end

0 commit comments

Comments
 (0)