time | Calls | line |
---|
| | 1 | function t = subsasgnBraces(t,s,b)
|
| | 2 | %SUBSASGNBRACES Subscripted assignment to a table.
|
| | 3 |
|
| | 4 | % Copyright 2012-2019 The MathWorks, Inc.
|
| | 5 |
|
| | 6 | import matlab.internal.datatypes.isColon
|
| | 7 | import matlab.lang.internal.move % Avoid unsharing of shared-data copy across function call boundary
|
< 0.001 | 785 | 8 | subsType = matlab.internal.tabular.private.tabularDimension.subsType; % "import" for calls to subs2inds
|
| | 9 |
|
| | 10 | % '{}' is assignment to or into the contents of a subset of a table array.
|
| | 11 | % Any sort of subscripting may follow.
|
| | 12 |
|
< 0.001 | 785 | 13 | if ~isstruct(s), s = substruct('{}',s); end
|
| | 14 |
|
0.003 | 785 | 15 | if numel(s(1).subs) ~= t.metaDim.length
|
| | 16 | error(message('MATLAB:table:NDSubscript'));
|
< 0.001 | 785 | 17 | end
|
| | 18 |
|
< 0.001 | 785 | 19 | if ~isscalar(s)
|
| | 20 | % Syntax: t{rowIndices,varIndices}(...) = b
|
| | 21 | % t{rowIndices,varIndices}{...} = b
|
| | 22 | % t{rowIndices,varIndices}.name = b
|
| | 23 | %
|
| | 24 | % Assignment into contents of a table.
|
| | 25 | %
|
| | 26 | % t{rowIndices,varIndices} must refer to rows and vars that exist, and the
|
| | 27 | % assignment on whatever follows that can't add rows or columns or otherwise
|
| | 28 | % reshape the contents. This avoids cases where the indexing beyond
|
| | 29 | % t{rowIndices,varIndices} refers to things outside the subarray, but which
|
| | 30 | % already exist in t itself. So, cannot grow the table by an assignment
|
| | 31 | % like this. Even if the number of elements stayed the same, if the shape
|
| | 32 | % of those contents changed, we wouldn't know how to put them back into the
|
| | 33 | % original table.
|
| | 34 |
|
| | 35 | % Get the subarray's contents, and do the assignment on that.
|
| | 36 | try
|
| | 37 | c = t.subsrefBraces(s(1));
|
| | 38 | catch ME
|
| | 39 | outOfRangeIDs = ["MATLAB:table:RowIndexOutOfRange" "MATLAB:table:UnrecognizedRowName" ...
|
| | 40 | "MATLAB:table:VarIndexOutOfRange" "MATLAB:table:UnrecognizedVarName"];
|
| | 41 | matlab.internal.datatypes.throwInstead(ME, outOfRangeIDs, ...
|
| | 42 | "MATLAB:table:InvalidExpansion");
|
| | 43 | end
|
| | 44 | szOut = size(c);
|
| | 45 | s2 = s(2:end);
|
| | 46 |
|
| | 47 | if s(2).type ~= "." % t{rows,vars}(...) = ... or t{rows,vars}{...} = ...
|
| | 48 | rowIndices = s2(1).subs{1};
|
| | 49 | if isnumeric(rowIndices) || islogical(rowIndices) || isColon(rowIndices)
|
| | 50 | % Can leave these alone to save overhead of calling subs2inds
|
| | 51 | else
|
| | 52 | % The second level of braces-parens or braces-braces subscripting might use row
|
| | 53 | % labels inherited from the table's rows, translate those to indices.
|
| | 54 | if (size(c,2)>1) && isscalar(s2(1).subs)
|
| | 55 | error(message('MATLAB:table:InvalidLinearIndexing'));
|
| | 56 | end
|
| | 57 | rowIndices = t.rowDim.subs2inds(rowIndices);
|
| | 58 | s2(1).subs{1} = rowIndices;
|
| | 59 | end
|
| | 60 | else
|
| | 61 | % A reference to a property or field, so no row labels
|
| | 62 | end
|
| | 63 |
|
| | 64 | % Let t{rowIndices,varIndices}'s subsasgn handle the cascaded subscripting.
|
| | 65 | if isscalar(s2)
|
| | 66 | try %#ok<ALIGN>
|
| | 67 | % If b is a built-in type, or the same class as c, call subsasgn directly for
|
| | 68 | % fastest dispatch to c's (possibly overloaded) subscripting. Otherwise, force
|
| | 69 | % dispatch to c's subscripting even when b is dominant. In most cases, calling
|
| | 70 | % subsasgn via builtin guarantees dispatch on the first input. However, if c is
|
| | 71 | % a table, builtin would dispatch to default, not overloaded, subscripting, so
|
| | 72 | % use dot-method syntax.
|
| | 73 | if isobject(b)
|
| | 74 | if isa(c,class(b)) % c first is fast when it is built-in
|
| | 75 | c = subsasgn(c,s2,b); % dispatches correctly, even to tabular
|
| | 76 | elseif isa(c,'tabular')
|
| | 77 | c = c.subsasgn(s2,b);
|
| | 78 | else
|
| | 79 | c = builtin('subsasgn',c,s2,b);
|
| | 80 | end
|
| | 81 | else
|
| | 82 | c = subsasgn(c,s2,b);
|
| | 83 | end
|
| | 84 | catch ME, throw(ME); end
|
| | 85 | else % ~isscalar(s2)
|
| | 86 | % Trick the third and higher levels of subscripting in things like
|
| | 87 | % t{i,j}(...) etc. into dispatching to the right place even when
|
| | 88 | % t{i,j}, or something further down the chain, is itself a table.
|
| | 89 | try %#ok<ALIGN>
|
| | 90 | c = matlab.internal.tabular.private.subsasgnRecurser(c,s2,b);
|
| | 91 | catch ME, rethrow(ME); end % point to the line in subsasgnRecurser
|
| | 92 | end
|
| | 93 |
|
| | 94 | % The nested assignment is not allowed to change the size of the target.
|
| | 95 | if ~isequal(size(c),szOut)
|
| | 96 | error(message('MATLAB:table:InvalidContentsReshape'));
|
| | 97 | end
|
| | 98 |
|
| | 99 | % Now let the simple {} subscripting code handle assignment of the updated
|
| | 100 | % contents back into the original array.
|
| | 101 | b = c;
|
| | 102 | s = s(1);
|
< 0.001 | 785 | 103 | end
|
| | 104 |
|
| | 105 | % If the LHS is 0x0, then interpret ':' as the size of the corresponding dim
|
| | 106 | % from the RHS, not as nothing.
|
0.007 | 785 | 107 | assigningInto0x0 = all(size(t) == 0);
|
| | 108 |
|
| | 109 | % Translate variable (column) names into indices (translate ':' to 1:nvars)
|
< 0.001 | 785 | 110 | if assigningInto0x0 && isColon(s(1).subs{2})
|
| | 111 | varIndices = 1:size(b,2);
|
< 0.001 | 785 | 112 | else
|
0.017 | 785 | 113 | varIndices = t.varDim.subs2inds(s(1).subs{2},subsType.assignment,t.data);
|
< 0.001 | 785 | 114 | end
|
0.001 | 785 | 115 | existingVarLocs = find(varIndices <= t.varDim.length); % subscripts corresponding to existing vars
|
0.001 | 785 | 116 | newVarLocs = find(varIndices > t.varDim.length); % subscripts corresponding to new vars
|
| | 117 |
|
| | 118 | % Syntax: t{rowIndices,varIndices} = b
|
| | 119 | %
|
| | 120 | % Assignment to contents of a table.
|
0.001 | 785 | 121 | colSizes = ones(1,length(varIndices));
|
0.017 | 785 | 122 | colSizes(existingVarLocs) = cellfun(@(x)size(x,2),t.data(varIndices(existingVarLocs)));
|
| | 123 | % *** need to have subsasgnParens accept a row of cells to avoid the work of
|
| | 124 | % *** explicitly creating a table
|
< 0.001 | 785 | 125 | if isscalar(b)
|
0.026 | 785 | 126 | t0 = table;
|
0.120 | 785 | 127 | b = t0.subsasgnDot('Var1',b); % avoid constructor arg list issues when b is a char row
|
| | 128 | else
|
| | 129 | % We know the number of columns in each existing var, assume one column for
|
| | 130 | % new vars. If we have the right number of columns on the RHS, good.
|
| | 131 | if size(b,2) ~= sum(colSizes)
|
| | 132 | if (size(b,2) > sum(colSizes)) && isscalar(newVarLocs)
|
| | 133 | % If we have too many columns, but there's only one new var, give that var
|
| | 134 | % multiple columns.
|
| | 135 | colSizes(newVarLocs) = size(b,2) - sum(colSizes(existingVarLocs));
|
| | 136 | elseif isnumeric(b) && isequal(b,[]) && builtin('_isEmptySqrBrktLiteral',b)...
|
| | 137 | && isempty(newVarLocs) && (isColon(s(1).subs{1}) || isColon(s(1).subs{2}))
|
| | 138 | % If we have the wrong number of columns, and this looks like an attempt at
|
| | 139 | % deletion of existing contents, say how many columns were expected but also
|
| | 140 | % give a helpful error suggesting parens subscripting. Assignment of [] can
|
| | 141 | % never be deletion here, so if there's no colons or if there's an out of
|
| | 142 | % range subscript, let the else handle it as true assignment.
|
| | 143 | error(message('MATLAB:table:BracesAssignDelete',sum(colSizes)));
|
| | 144 | else
|
| | 145 | % Otherwise say how many columns were expected.
|
| | 146 | error(message('MATLAB:table:WrongNumberRHSCols',sum(colSizes)));
|
| | 147 | end
|
| | 148 | end
|
| | 149 | dimSz = num2cell(size(b)); dimSz{2} = colSizes;
|
| | 150 | b_data = mat2cell(b,dimSz{:});
|
| | 151 | b = table(b_data{:});
|
< 0.001 | 785 | 152 | end
|
0.262 | 785 | 153 | t = move(t).subsasgnParens(s,b,false);
|
Other subfunctions in this file are not included in this listing.