Skip to content

Commit

Permalink
added types.untyped.Ref to handle references. Fixed gitignore
Browse files Browse the repository at this point in the history
Lancewiu committed Apr 19, 2018
1 parent 89be61a commit bbb9573
Showing 13 changed files with 354 additions and 112 deletions.
17 changes: 8 additions & 9 deletions +file/Dataset.m
Original file line number Diff line number Diff line change
@@ -113,16 +113,15 @@
% type.
% therefore, we currently do not have a case for a regular typed
% dataset (because there isn't any.
if isstruct(obj.dtype)
props('table') = obj.dtype;
elseif isa(obj.dtype, 'java.util.HashMap')
props('target') = obj.dtype;
rt = obj.dtype.get('reftype');
if strcmp(rt, 'region')
props('region') = 'double';
if ~isempty(obj.dtype)
if isstruct(obj.dtype)
props('table') = obj.dtype;
elseif isa(obj.dtype, 'java.util.HashMap')
props('ref') = obj.dtype;
elseif ~isempty(obj.type)
%regular dataset
props('data') = obj.dtype;
end
else
%regular dataset. TODO
end

if ~isempty(obj.attributes)
2 changes: 1 addition & 1 deletion +file/fillClass.m
Original file line number Diff line number Diff line change
@@ -25,7 +25,7 @@
for i=1:length(propertylist)
propname = propertylist{i};
prop = classprops.named(propname);

if isa(prop, 'file.Attribute') && prop.readonly
ro_props.(propname) = prop.doc;
elseif ischar(prop)
10 changes: 9 additions & 1 deletion +file/fillConstructor.m
Original file line number Diff line number Diff line change
@@ -48,7 +48,15 @@
elseif isa(prop, 'file.Attribute')
fdfp = prop.dtype;
elseif isa(prop, 'java.util.HashMap')
fdfp = ['ref to ' prop.get('target_type')];
switch prop.get('reftype')
case 'region'
reftypenm = 'region';
case 'object'
reftypenm = 'object';
otherwise
error('Invalid reftype found whilst filling Constructor prop docs.');
end
fdfp = ['ref to ' prop.get('target_type') ' ' reftypenm];
elseif isa(prop, 'file.Dataset') && isempty(prop.type)
fdfp = fillDocFromProp(prop.dtype);
elseif isempty(prop.type)
5 changes: 0 additions & 5 deletions +file/fillValidators.m
Original file line number Diff line number Diff line change
@@ -135,10 +135,5 @@
ts = type;
end
fdvstr = ['types.util.checkDtype(''' name ''', ''' ts ''', val);'];

% special case for region reftype
if strcmp(name, 'region') && strcmp(type, 'double')
fdvstr = [fdvstr newline 'types.util.checkRegion(obj, val);'];
end
end
end
21 changes: 11 additions & 10 deletions +io/parseDataset.m
Original file line number Diff line number Diff line change
@@ -29,7 +29,6 @@
% compound data w/ reference (ElectrodeTable)
% All other cases do not exist in this current schema.
props = attrargs;
props('associated_nwbfile') = filename;

fid = H5F.open(filename);
did = H5D.open(fid, fullpath);
@@ -38,16 +37,17 @@
datatype = info.Datatype;
if strcmp(datatype.Class, 'H5T_REFERENCE')
reftype = datatype.Type;
switch reftype
case 'H5R_OBJECT'
%TODO when included in schema
case 'H5R_DATASET_REGION'
sid = H5R.get_region(did, reftype, data);
[start, finish] = H5S.get_select_bounds(sid);
props('target') = H5R.get_name(did, reftype, data);
props('region') = [start+1 finish];
H5S.close(sid);
path = H5R.get_name(did, reftype, data);
props('ref') = [];
if strcmp(reftype, 'H5R_DATASET_REGION')
sid = H5R.get_region(did, reftype, data);
[start, finish] = H5S.get_select_bounds(sid);
H5S.close(sid);
reg = [start finish];
else
reg = [];
end
refs([fullpath '/ref']) = struct('path', path, 'region', reg);
elseif strcmp(datatype.Class, 'H5T_COMPOUND')
t = table;
compound = datatype.Type.Member;
@@ -58,6 +58,7 @@
isref(j) = true;
end
end
else
end
kwargs = io.map2kwargs(props);
parsed = eval([typename '(kwargs{:})']);
98 changes: 98 additions & 0 deletions +types/+untyped/DynamicClass.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
classdef DynamicClass < handle & matlab.mixin.CustomDisplay
properties(Access=protected)
map;
validators;
allowAddProp;
end

methods
function obj = DynamicClass
obj.map = containers.Map;
obj.schema = containers.Map;
obj.allowAddProp = false;
end

function validate_property(obj, name, val)
if isKey(obj.schema, name)
feval(obj.schema(name), val);
elseif ~obj.allowAddProp
error('This class does not allow adding properties.');
end
end

function export(~, loc_id)
%write namespace and class name
[path, classname, ~] = fileparts(mfilename('fullpath'));
[~, namespacename, ~] = fileparts(path);
h5util.writeAttribute(loc_id, 'namespace', namespacename(2:end), 'string');
h5util.writeAttribute(loc_id, 'neurodata_type', classname(2:end), 'string');
end
end

methods(Sealed, Access=protected)
%% Subsref/Subsasgn Overrides

function varargout = subsref(obj, s)
if strcmp('{}', s(1).type)
error('subcont only supports ''.'' and ''()'' indexing');
end

if length(s) > 1
[varargout{1:nargout}] = subsref(obj.map(s(1).subs), s(2:end));
else
varargout{1} = obj.map(s.subs);
end
end

function obj = subsasgn(obj, s, varargin)
if strcmp('{}', s(1).type)
error('subcont only supports ''.'' and ''()'' indexing');
end

if strcmp('()', s(1).type)
obj.validate_property(s.subs, varargin{1});
obj.map(s.subs{:}) = varargin{1};
else
if length(s) > 1
obj.map(s(1).subs) = subsasgn(obj.map(s(1).subs), s(2:end), varargin);
else
obj.validate_property(s.subs, varargin{1});
obj.map(s.subs) = varargin{1};
end
end
end

%% Custom Display Overrides
function displayScalarObject(obj)
if isempty(obj.map)
disp(matlab.mixin.CustomDisplay.getSimpleHeader(obj));
else
disp([' ' matlab.mixin.CustomDisplay.getClassNameForHeader(obj)...
' with properties:' newline]);
mk = keys(obj.map);
maxwordlen = 0;
for i=1:length(mk)
mklen = length(mk{i});
if mklen > maxwordlen
maxwordlen = mklen;
end
end

for i=1:length(mk)
mknm = mk{i};
val = obj.map(mknm);
if ischar(val)
val = ['''' val ''''];
end
disp([repmat(' ', 1, (maxwordlen - length(mknm)) + 4)...
mknm ': ' strtrim(evalc('disp(val)'))]);
end
disp(' ');
end
end

function displayNonScalarObject(obj)
disp([strjoin(size(obj), 'x') ' ' getClassNameForHeader(obj)]);
end
end
end
92 changes: 66 additions & 26 deletions +types/+untyped/Link.m
Original file line number Diff line number Diff line change
@@ -1,30 +1,70 @@
classdef Link
properties
filename = '';
path;
ref;
end

methods
function obj = Link(path, filename, ref)
obj.path = path;

if nargin > 1
obj.filename = filename;
end

if nargin > 2
obj.ref = ref;
end
classdef Link < handle

properties(SetAccess=immutable)
nwb; %nwbfile into which link should be searching
filename;
end

properties
path;
end

properties(Hidden, SetAccess=immutable)
type; %type constraint, used by file generation
end

function export(obj, loc_id, nm)
plist = 'H5P_DEFAULT';
if isempty(obj.filename)
H5L.create_soft(obj.path, loc_id, nm, plist, plist);
else
H5L.create_external(obj.filename, obj.path, loc_id, nm, plist, plist);
end
methods
function obj = Link(path, context, type)
obj.path = path;

%if context is char, then it's an external link
%if context is nwbfile then it's a softlink
if ischar(context)
obj.filename = context;
obj.nwb = [];
elseif isa(context, 'nwbfile')
obj.filename = '';
obj.nwb = context;
else
error('Argument `context` must either be a filename for external links, or a nwbfile for soft links');
end

if nargin >= 3
if ~ischar(type)
error('Argument `type` must be a char array specifying type');
end
obj.type = type;
end
obj.deref();
end

function set.path(obj, val)
if ~ischar(val)
error('Property `path` should be a char array');
end
obj.path = val;
end

function refobj = deref(obj)
if isempty(obj.filename)
refobj = io.resolvePath(obj.nwb, obj.path);
if ~isa(refobj, obj.type)
error('Expected link to point to a `%s`. Got `%s`.', obj.type, class(refobj));
end
else
%there are no guarantees regarding external links so just
%resolve as HDF5 dataset.
refobj = h5read(obj.filename, obj.path);
end
end

function export(obj, loc_id, nm)
plist = 'H5P_DEFAULT';
if isempty(obj.filename)
H5L.create_soft(obj.path, loc_id, nm, plist, plist);
else
H5L.create_external(obj.filename, obj.path, loc_id, nm, plist, plist);
end
end
end
end
end
59 changes: 0 additions & 59 deletions +types/+untyped/MetaClass.m
Original file line number Diff line number Diff line change
@@ -10,63 +10,4 @@ function export(~, loc_id)
h5util.writeAttribute(loc_id, 'neurodata_type', namespace(2:end), 'string');
end
end

methods(Access=protected)
function res = validateDynamicProperty(obj, val)
res = [];
valmc = metaclass(val);
valparents = valmc.SuperclassList;
for i=1:length(valparents)
found = strcmp(obj.dynamic_constraints, valparents(i).Name);
if any(found)
res = obj.dynamic_constraints{found};
return;
end
end
end
end

methods(Sealed, Access=protected)
%% Subsref/Subsasgn Overrides
function varargout = subsref(obj, s)
if strcmp('{}', s(1).type)
error('This class only supports ''.'' and ''()'' indexing');
end

if isKey(obj.dynamic_properties, s(1).subs)
if length(s) > 1
[varargout{1:nargout}] = subsref(obj.dynamic_properties(s(1).subs), s(2:end));
else
varargout{1} = obj.dynamic_properties(s.subs);
end
else
[varargout{1:nargout}] = builtin('subsref', obj, s);
end
end

function obj = subsasgn(obj, s, varargin)
if strcmp('{}', s(1).type)
error('This class only supports ''.'' and ''()'' indexing');
end

if strcmp('()', s(1).type)
if ~iscellstr(s.subs)
error('Invalid class index type. Must be char array index');
end
obj.addDynamicProperty(s.subs{1}, varargin{1});
elseif any(strcmp(properties(obj), s(1).subs))
obj = builtin('subsasgn', obj, s, varargin);
else
if ~isKey(obj.dynamic_properties, s(1).subs)
error('No static or dynamic property %s', s(1).subs);
end
if length(s) > 1
obj.dynamic_properties(s(1).subs) = subsasgn(obj.map(s(1).subs), s(2:end), varargin);
else
obj.validate_property(s.subs, varargin{1});
obj.map(s.subs) = varargin{1};
end
end
end
end
end
Loading

0 comments on commit bbb9573

Please sign in to comment.