gusucode.com > datatypes 工具箱matlab源码程序 > datatypes/+matlab/+internal/+table/tableMetaDim.m

    classdef (Sealed) tableMetaDim < matlab.internal.table.tableDimension
%TABLEMETASDIM Internal class to represent a table's list of dimension.

% This class is for internal use only and will change in a
% future release.  Do not use this class.

    %   Copyright 2016 The MathWorks, Inc.
    
    properties(Constant, GetAccess=public)
        propertyNames = {'DimensionNames'};
    end
    properties(GetAccess=public, SetAccess=protected)
        dispRowHeader = false;
    end
    properties(GetAccess=protected, SetAccess=private)
        % This property controls whether validation of dim names is lenient for backwards
        % compatibility, see checkAgainstVarLabels and fixLabelsForCompatibility for more details.
        backwardsCompatibility = false;
    end
    methods
        function obj = tableMetaDim(length,labels,dispRowHeader,backwardsCompatibility)
            % Technically, this is not a table dimension, it's more like a table
            % meta-dimension. But it's close enough to var and row names to
            % reuse the infrastructure. Always initialize with two default
            % names, and orient them alons dim=2, as a row.
            import matlab.internal.datatypes.isCharStrings
            
            if nargin == 0
                length = 2;
                labels = matlab.internal.table.dfltDimNames;
            elseif nargin == 1
                labels = matlab.internal.table.dfltDimNames;
            else
                % This is the relevant parts of validateAndAssignLabels
                if ~isCharStrings(labels,true,false) % require cellstr, no empties
                    error(message('MATLAB:table:InvalidDimNames'));
                end
                labels = strtrim(labels(:)'); % a row vector, conveniently forces any empty to 0x1
                if (nargin > 3) && backwardsCompatibility % tables, for now
                    labels = fixLabelsForCompatibility(labels);
                else % timetables
                    matlab.internal.tableUtils.makeValidName(labels,'dimnamesError');
                    matlab.internal.table.checkDuplicateNames(labels,'dimnames');
                    matlab.internal.table.checkReservedNames(labels,'dimnames');
                end
            end
            obj = obj@matlab.internal.table.tableDimension(2,length,true,true,labels);
            
            if nargin > 2
                obj.dispRowHeader = dispRowHeader;
                if nargin > 3
                    obj.backwardsCompatibility = backwardsCompatibility;
                end
            end
        end
        
        %-----------------------------------------------------------------------
        function labels = defaultLabels(obj,indices)
            if nargin < 2
                indices = 1:obj.length;
            end
            labels = matlab.internal.table.dfltDimNames(indices);
        end
        
        %-----------------------------------------------------------------------
        function obj = lengthenTo(obj,~,~)
            assert(false);
        end
        
        %-----------------------------------------------------------------------
        function s = getProperties(obj)
            % Same order as tableMetaDim.propertyNames
            s.DimensionNames = obj.labels;
        end
        
        %-----------------------------------------------------------------------
        function obj = checkAgainstVarLabels(obj,varLabels,errorMode)
            import matlab.internal.tableUtils.warningWithoutTrace
            % Pre-2016b, DimensionNames were not required to be distinct from VariableNames,
            % but now they are. If they conflict, modify DimensionNames and warn.
            [modifiedLabels,wasConflicted] = matlab.lang.makeUniqueStrings(obj.labels,varLabels,namelengthmax);
            if any(wasConflicted)
                if nargin > 2
                    switch errorMode
                    case 'silent'
                        % OK
                    case 'warn'
                        warningWithoutTrace(message('MATLAB:table:DuplicateDimNamesVarNamesWarn',obj.labels{find(wasConflicted,1)}));
                    case 'error'
                        error(message('MATLAB:table:DuplicateDimNamesVarNames',obj.labels{find(wasConflicted,1)}));
                    otherwise
                        assert(false);
                end
                elseif obj.backwardsCompatibility % tables, for now
                    warningWithoutTrace(message('MATLAB:table:DuplicateDimnamesVarnamesBackCompat',obj.labels{find(wasConflicted,1)}));
                else % timetables
                    error(message('MATLAB:table:DuplicateDimNamesVarNames',obj.labels{find(wasConflicted,1)}));
                end
                obj.labels = modifiedLabels;
            end
        end
    end
    
    %===========================================================================
    methods (Access=protected)
        function obj = validateAndAssignLabels(obj,newLabels,dimIndices,fullAssignment,fixDups,fixEmpties,fixIllegal)
            import matlab.internal.datatypes.isCharString
            import matlab.internal.datatypes.isCharStrings
            
            if ~fullAssignment && isCharString(newLabels,fixEmpties)
                % Accept one character vector for (partial) assignment to one name, allow empty character vectors per caller.
                newLabels = { strtrim(newLabels) };
            elseif isCharStrings(newLabels,true,fixEmpties)
                % Accept a cellstr, allow empty character vectors per caller.
                newLabels = strtrim(newLabels(:)'); % a row vector, conveniently forces any empty to 0x1
            else
                error(message('MATLAB:table:InvalidDimNames'));
            end
            % Fill in empty names if allowed, and make them unique with respect
            % to the other new names. If not allowed, an error was already thrown.
            [newLabels,wasEmpty] = fillEmptyNames(newLabels,dimIndices);
            newLabels = matlab.lang.makeUniqueStrings(newLabels,wasEmpty,namelengthmax);
            
            if fixIllegal
                newLabels = matlab.internal.tableUtils.makeValidName(newLabels,'dimnamesWarn');
            else
                if obj.backwardsCompatibility % tables, for now
                    newLabels = fixLabelsForCompatibility(newLabels);
                else % timetables
                    newLabels = matlab.internal.tableUtils.makeValidName(newLabels,'dimnamesError');
                end
            end
            matlab.internal.table.checkReservedNames(newLabels,'dimnames');
            
            if fixDups
                % Make the new names (in their possibly modified form) unique with respect to
                % each other and to existing names.
                allNewLabels = obj.labels; allNewLabels(dimIndices) = newLabels;
                allNewLabels = matlab.lang.makeUniqueStrings(allNewLabels,dimIndices,namelengthmax);
                newLabels = allNewLabels(dimIndices);
            elseif fullAssignment
                % Check that the whole set of new names is unique
                matlab.internal.table.checkDuplicateNames(newLabels,'dimnames');
            else
                % Make sure empty new names that were filled in or modified do not duplicate any
                % of the other new names.
                newLabels = matlab.lang.makeUniqueStrings(newLabels,wasEmpty,namelengthmax);
                % Check that the new names do not duplicate each other or existing names.
                allNewLabels = obj.labels; allNewLabels(dimIndices) = newLabels;
                matlab.internal.table.checkDuplicateNames(newLabels,allNewLabels,dimIndices,'dimnames');
            end
            
            obj = obj.assignLabels(newLabels,fullAssignment,dimIndices);
        end
        
        %-----------------------------------------------------------------------
        function obj = makeUniqueForRepeatedIndices(obj,~)
            assert(false);
        end
        
        %-----------------------------------------------------------------------
        function throwRequiresLabels(obj) %#ok<MANU>
            msg = message('MATLAB:table:CannotRemoveDimNames');
            throwAsCaller(MException(msg.Identifier,msg.getString()));
        end
        function throwInvalidPartialLabelsAssignment(obj) %#ok<MANU>
            assert(false);
        end
        function throwIncorrectNumberOfLabels(obj) %#ok<MANU>
            msg = message('MATLAB:table:IncorrectNumberOfDimNames');
            throwAsCaller(MException(msg.Identifier,msg.getString()));
        end
        function throwIncorrectNumberOfLabelsPartial(obj) %#ok<MANU>
            msg = message('MATLAB:table:IncorrectNumberOfDimNamesPartial');
            throwAsCaller(MException(msg.Identifier,msg.getString()));
        end
        function throwIndexOutOfRange(obj) %#ok<MANU>
            msg = message('MATLAB:table:DimIndexOutOfRange');
            throwAsCaller(MException(msg.Identifier,msg.getString()));
        end
        function throwUnrecognizedLabel(obj,label) %#ok<INUSL>
            msg = message('MATLAB:table:UnrecognizedDimName',label{1});
            throwAsCaller(MException(msg.Identifier,msg.getString()));
        end
        function throwInvalidLabel(obj) %#ok<MANU>
            msg = message('MATLAB:table:InvalidDimName');
            throwAsCaller(MException(msg.Identifier,msg.getString()));
        end
        function throwInvalidSubscripts(obj) %#ok<MANU>
            msg = message('MATLAB:table:InvalidDimSubscript');
            throwAsCaller(MException(msg.Identifier,msg.getString()));
        end
    end
end

%-----------------------------------------------------------------------
function labels = fixLabelsForCompatibility(labels)
% Pre-R2016b, DimensionNames had almost no constraints, but there are new
% requirements to support new dot subscripting functionality added in R2016b.
% The old defaults met those requirements, so if the names are not (now) valid,
% they must have been intentionally changed from their old defaults (or perhaps
% DimensionNames{1} came from a column header in a file). In any case, to avoid
% breaking existing table code, modify any invalid names and warn.
import matlab.internal.tableUtils.warningWithoutTrace

originalLabels = labels;
% Pre-R2016b,names were not required to be valid MATLAB identifiers.
[labels,wasMadeValid] = matlab.internal.tableUtils.makeValidName(labels,'silent');
if any(wasMadeValid)
    warningWithoutTrace(message('MATLAB:table:DimNameNotValidIdentifierBackCompat',originalLabels{find(wasMadeValid,1)}));
end
% Pre-2016b, names were not required to be distinct from the list of reserved names.
wasReserved = matlab.internal.table.checkReservedNames(labels,'dimnames');
if any(wasReserved)
    warningWithoutTrace(message('MATLAB:table:DimnamesReservedNameConflictBackCompat',originalLabels{find(wasReserved,1)}));
    labels(wasReserved) = matlab.lang.makeUniqueStrings(labels(wasReserved),labels(wasReserved),namelengthmax);
end
end

%-----------------------------------------------------------------------
function [names,empties] = fillEmptyNames(names,indices)
empties = cellfun('isempty',names);
if any(empties)
    names(empties) = matlab.internal.table.dfltDimNames(indices(empties));
end
end