time | Calls | line |
---|
| | 1 | function [b,varargout] = subsrefDot(t,s)
|
| | 2 | %SUBSREFDOT Subscripted reference for a table.
|
| | 3 |
|
| | 4 | % Copyright 2012-2019 The MathWorks, Inc.
|
| | 5 |
|
| | 6 | import matlab.internal.datatypes.isColon
|
| | 7 | import matlab.internal.datatypes.isScalarInt
|
| | 8 | import matlab.internal.datatypes.tryThrowIllegalDotMethodError
|
| | 9 | import matlab.lang.correction.ReplaceIdentifierCorrection
|
| | 10 |
|
| | 11 | % '.' is a reference to a table variable or property. Any sort of
|
| | 12 | % subscripting may follow. Row labels for cascaded () or {} subscripting on
|
| | 13 | % a variable are inherited from the table.
|
| | 14 |
|
| | 15 | % This method handles RHS subscripting expressions such as
|
| | 16 | % t.Var
|
| | 17 | % t.Var.Field
|
| | 18 | % t.Var{rowindices} or t.Var{rowindices,...}
|
| | 19 | % t.Var{rownames} or t.Var{rownames,...}
|
| | 20 | % or their dynamic var name versions, and also when there is deeper subscripting such as
|
| | 21 | % t.Var.Field[anything else]
|
| | 22 | % t.Var{...}[anything else]
|
| | 23 | % However, dotParenReference is called directly for RHS subscripting expressions such as
|
| | 24 | % t.Var(rowindices) or t.Var(rowindices,...)
|
| | 25 | % t.Var(rownames) or t.Var(rownames,...)
|
| | 26 | % or their dynamic var name versions, and also when there is deeper subscripting such as
|
| | 27 | % t.Var(...)[anything else]
|
| | 28 |
|
0.066 | 1026425 | 29 | if ~isstruct(s), s = substruct('.',s); end
|
| | 30 |
|
| | 31 | % Translate variable (column) name into an index. Avoid overhead of
|
| | 32 | % t.varDim.subs2inds in this simple case.
|
0.757 | 1026425 | 33 | varName = convertStringsToChars(s(1).subs);
|
0.041 | 1026425 | 34 | if isnumeric(varName)
|
| | 35 | % Allow t.(i) where i is an integer
|
0.043 | 1026410 | 36 | varIndex = varName;
|
3.136 | 1026410 | 37 | if ~isScalarInt(varIndex,1)
|
| | 38 | error(message('MATLAB:table:IllegalVarIndex'));
|
0.584 | 1026410 | 39 | elseif varIndex > t.varDim.length
|
| | 40 | error(message('MATLAB:table:VarIndexOutOfRange'));
|
0.046 | 1026410 | 41 | end
|
< 0.001 | 15 | 42 | elseif ischar(varName) && (isrow(varName) || isequal(varName,'')) % isCharString(varName)
|
< 0.001 | 15 | 43 | varIndex = find(matches(t.varDim.labels,varName));
|
< 0.001 | 15 | 44 | if isempty(varIndex)
|
| | 45 | % If there's no such var, it may be a reference to the 'Properties'
|
| | 46 | % (virtual) property. Handle those, but disallow references to
|
| | 47 | % any property directly. Check this first as a failsafe against
|
| | 48 | % shadowing .Properties by a dimension name.
|
< 0.001 | 4 | 49 | if varName == "Properties"
|
< 0.001 | 4 | 50 | if isscalar(s)
|
| | 51 | if nargout < 2
|
| | 52 | b = t.getProperties;
|
| | 53 | else
|
| | 54 | nargoutchk(0,1);
|
| | 55 | end
|
< 0.001 | 4 | 56 | else
|
| | 57 | % If there's cascaded subscripting into the property, let the
|
| | 58 | % property's subsref handle the reference. This may result in
|
| | 59 | % a comma-separated list, so ask for and assign to as many
|
| | 60 | % outputs as we're given. That is the number of outputs on
|
| | 61 | % the LHS of the original expression, or if there was no LHS,
|
| | 62 | % it comes from numArgumentsFromSubscript.
|
< 0.001 | 4 | 63 | try
|
< 0.001 | 4 | 64 | if nargout < 2
|
0.003 | 4 | 65 | b = t.getProperty(s(2:end));
|
| | 66 | else
|
| | 67 | [b,varargout{1:nargout-1}] = t.getProperty(s(2:end));
|
< 0.001 | 4 | 68 | end
|
| | 69 | catch ME
|
| | 70 | if ME.identifier == "MATLAB:table:UnknownProperty"
|
| | 71 | propName = s(2).subs;
|
| | 72 | match = find(matches(t.propertyNames,propName,"IgnoreCase",true),1);
|
| | 73 | if ~isempty(match) % a property name, but with wrong case
|
| | 74 | match = t.propertyNames{match};
|
| | 75 | throw(MException(message('MATLAB:table:UnknownPropertyCase',propName,match)) ...
|
| | 76 | .addCorrection(ReplaceIdentifierCorrection(propName,match)));
|
| | 77 | else
|
| | 78 | throw(ME);
|
| | 79 | end
|
| | 80 | else
|
| | 81 | throw(ME);
|
| | 82 | end
|
< 0.001 | 4 | 83 | end
|
< 0.001 | 4 | 84 | end
|
< 0.001 | 4 | 85 | return
|
| | 86 | elseif matches(varName,t.metaDim.labels{1})
|
| | 87 | % If it's the row dimension name, return the row labels
|
| | 88 | varIndex = 0;
|
| | 89 | elseif matches(varName,t.metaDim.labels{2})
|
| | 90 | % If it's the vars dimension name, return t{:,:}. Deeper subscripting
|
| | 91 | % is not supported, use explicit braces for that.
|
| | 92 | if ~isscalar(s)
|
| | 93 | error(message('MATLAB:table:NestedSubscriptingWithDotVariables',t.metaDim.labels{2}));
|
| | 94 | end
|
| | 95 | varIndex = -1;
|
| | 96 | elseif matches(varName,'Properties',"IgnoreCase", true) % .Properties, but with wrong case
|
| | 97 | throw(MException(message('MATLAB:table:UnrecognizedVarNamePropertiesCase',varName)) ...
|
| | 98 | .addCorrection(ReplaceIdentifierCorrection(varName, 'Properties')));
|
| | 99 | else
|
| | 100 | match = find(matches(t.propertyNames,varName,"IgnoreCase", true),1);
|
| | 101 | if ~isempty(match)
|
| | 102 | match = t.propertyNames{match};
|
| | 103 | if matches(varName,match) % a valid property name
|
| | 104 | throw(MException(message('MATLAB:table:IllegalPropertyReference',varName)) ...
|
| | 105 | .addCorrection(ReplaceIdentifierCorrection(varName, append('Properties.', match))));
|
| | 106 | else % a property name, but with wrong case
|
| | 107 | throw(MException(message('MATLAB:table:IllegalPropertyReferenceCase',varName,match)) ...
|
| | 108 | .addCorrection(ReplaceIdentifierCorrection(varName, append('Properties.', match))));
|
| | 109 | end
|
| | 110 | else
|
| | 111 | match = find(matches(t.varDim.labels,varName,"IgnoreCase",true),1);
|
| | 112 | if ~isempty(match) % an existing variable name
|
| | 113 | match = t.varDim.labels{match};
|
| | 114 | throw(MException(message('MATLAB:table:UnrecognizedVarNameCase',varName,match)) ...
|
| | 115 | .addCorrection(ReplaceIdentifierCorrection(varName,match)));
|
| | 116 | elseif matches(varName,t.metaDim.labels{1},'IgnoreCase',true) % the row dimension name
|
| | 117 | throw(MException(message('MATLAB:table:RowDimNameCase',varName,t.metaDim.labels{1})) ...
|
| | 118 | .addCorrection(ReplaceIdentifierCorrection(varName,t.metaDim.labels{1})));
|
| | 119 | elseif matches(varName,t.metaDim.labels{2},'IgnoreCase',true) % the variables dimension name
|
| | 120 | throw(MException(message('MATLAB:table:VariablesDimNameCase',varName,t.metaDim.labels{2})) ...
|
| | 121 | .addCorrection(ReplaceIdentifierCorrection(varName,t.metaDim.labels{2})));
|
| | 122 | elseif matches(t.defaultDimNames{1},varName) % trying to access row labels by default name
|
| | 123 | throw(t.throwSubclassSpecificError('RowDimNameNondefault',varName,t.metaDim.labels{1}) ...
|
| | 124 | .addCorrection(ReplaceIdentifierCorrection(varName,t.metaDim.labels{1})));
|
| | 125 | elseif matches(t.defaultDimNames{2},varName) % trying to access variables by default name
|
| | 126 | throw(MException(message('MATLAB:table:VariablesDimNameNondefault',varName,t.metaDim.labels{2})) ...
|
| | 127 | .addCorrection(ReplaceIdentifierCorrection(varName,t.metaDim.labels{2})));
|
| | 128 | else
|
| | 129 | tryThrowIllegalDotMethodError(t,varName,'MethodsWithNoCorrection',t.methodsWithNonTabularFirstArgument,'MessageCatalog','MATLAB:table');
|
| | 130 | error(message('MATLAB:table:UnrecognizedVarName',varName));
|
| | 131 | end
|
| | 132 | end
|
| | 133 | end
|
< 0.001 | 11 | 134 | end
|
| | 135 | else
|
| | 136 | error(message('MATLAB:table:IllegalVarSubscript'));
|
0.040 | 1026421 | 137 | end
|
| | 138 |
|
0.052 | 1026421 | 139 | if varIndex > 0
|
1.364 | 1026421 | 140 | b = t.data{varIndex};
|
| | 141 | elseif varIndex == 0
|
| | 142 | b = t.rowDim.labels;
|
| | 143 | else % varIndex == -1
|
| | 144 | b = t.extractData(1:t.varDim.length);
|
0.046 | 1026421 | 145 | end
|
| | 146 |
|
0.052 | 1026421 | 147 | if isscalar(s)
|
| | 148 | % If there's no additional subscripting, return the table variable.
|
0.008 | 138611 | 149 | if nargout > 1
|
| | 150 | nargoutchk(0,1);
|
0.007 | 138611 | 151 | end
|
0.036 | 887810 | 152 | else
|
2.519 | 887810 | 153 | s2 = s(2);
|
1.008 | 887810 | 154 | if ~isequal(s2.type,'.') % t.Var(...) or t.Var{...}
|
0.571 | 887810 | 155 | rowIndices = s2.subs{1};
|
0.063 | 887810 | 156 | if isnumeric(rowIndices) || islogical(rowIndices) || isColon(rowIndices)
|
| | 157 | % Can leave these alone to save overhead of calling subs2inds
|
< 0.001 | 5390 | 158 | else
|
| | 159 | % Dot-parens or dot-braces subscripting might use row labels inherited from the
|
| | 160 | % table, translate those to indices.
|
0.018 | 5390 | 161 | if ~iscolumn(b) && isscalar(s2.subs)
|
| | 162 | error(message('MATLAB:table:InvalidLinearIndexing'));
|
< 0.001 | 5390 | 163 | end
|
0.264 | 5390 | 164 | numericRowIndices = t.rowDim.subs2inds(rowIndices);
|
| | 165 | % subs2inds returns the indices as a col vector, but subscripting on
|
| | 166 | % a table variable (as opposed to on a table) should follow the usual
|
| | 167 | % reshaping rules. Nothing to do for one (char) name, including ':', but
|
| | 168 | % preserve a cellstr subscript's original shape.
|
0.010 | 5390 | 169 | if iscell(rowIndices), numericRowIndices = reshape(numericRowIndices,size(rowIndices)); end
|
0.026 | 5390 | 170 | s(2).subs{1} = numericRowIndices;
|
0.021 | 5390 | 171 | s2 = s(2); % update the local copy
|
0.034 | 887810 | 172 | end
|
| | 173 | else
|
| | 174 | % A reference to a property or field, so no row labels
|
0.036 | 887810 | 175 | end
|
| | 176 |
|
| | 177 | % Now let the variable's subsref handle the remaining subscripts in things
|
| | 178 | % like t.name(...) or t.name{...} or t.name.property. This may return a
|
| | 179 | % comma-separated list, so ask for and assign to as many outputs as we're
|
| | 180 | % given. That is the number of outputs on the LHS of the original expression,
|
| | 181 | % or if there was no LHS, it comes from numArgumentsFromSubscript.
|
| | 182 | %
|
| | 183 | % subsrefDot's output args are defined as [b,varargout] so the nargout==1
|
| | 184 | % case can avoid varargout, although that adds complexity to the nargout==0
|
| | 185 | % case. See detailed comments in subsref.
|
0.044 | 887810 | 186 | if length(s) == 2
|
0.039 | 887810 | 187 | try %#ok<ALIGN>
|
0.096 | 887810 | 188 | if nargout == 1
|
11.163 | 887810 | 189 | b = subsref(b,s2); % dispatches correctly, even to tabular
|
| | 190 | elseif nargout > 1
|
| | 191 | [b,varargout{1:nargout-1}] = subsref(b,s2); % dispatches correctly, even to tabular
|
| | 192 | else % nargout == 0
|
| | 193 | % Let varargout bump magic capture either one output or zero
|
| | 194 | % outputs. See detailed comments in subsref.
|
| | 195 | [varargout{1:nargout}] = subsref(b,s2); % call it just for error handling
|
| | 196 | if isempty(varargout)
|
| | 197 | % There is nothing to return, remove the first output arg.
|
| | 198 | clear b
|
| | 199 | else
|
| | 200 | % Shift the return value into the first output arg.
|
| | 201 | b = varargout{1};
|
| | 202 | varargout = {}; % never any additional values
|
| | 203 | end
|
0.105 | 887810 | 204 | end
|
| | 205 | catch ME, throw(ME); end
|
| | 206 | else % length(s) > 2
|
| | 207 | % Trick the third and higher levels of subscripting in things like
|
| | 208 | % t.Var{i}(...) etc. into dispatching to the right place when
|
| | 209 | % t.Var{i}, or something further down the chain, is itself a table.
|
| | 210 | try %#ok<ALIGN>
|
| | 211 | if nargout == 1
|
| | 212 | b = matlab.internal.tabular.private.subsrefRecurser(b,s(2:end));
|
| | 213 | elseif nargout > 1
|
| | 214 | [b,varargout{1:nargout-1}] = matlab.internal.tabular.private.subsrefRecurser(b,s(2:end));
|
| | 215 | else % nargout == 0
|
| | 216 | % Let varargout bump magic capture either one output or zero
|
| | 217 | % outputs. See detailed comments in subsref.
|
| | 218 | [varargout{1:nargout}] = matlab.internal.tabular.private.subsrefRecurser(b,s(2:end));
|
| | 219 | if isempty(varargout)
|
| | 220 | % There is nothing to return, remove the first output arg.
|
| | 221 | clear b
|
| | 222 | else
|
| | 223 | % Shift the return value into the first output arg.
|
| | 224 | b = varargout{1};
|
| | 225 | varargout = {}; % never any additional values
|
| | 226 | end
|
| | 227 | end
|
| | 228 | catch ME, rethrow(ME); end % point to the line in subsrefRecurser
|
0.037 | 887810 | 229 | end
|
1.348 | 1026421 | 230 | end
|
Other subfunctions in this file are not included in this listing.