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

    classdef (AllowedSubclasses = {?matlab.internal.table.tableRowNamesDim, ...
                               ?matlab.internal.table.tableRowTimesDim, ...
                               ?matlab.internal.table.tableVarNamesDim, ...
                               ?matlab.internal.table.tableMetaDim}) tableDimension
%TABLEDIMENSION Internal abstract class to represent a table's 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(Abstract, Constant, GetAccess=public)
        propertyNames;
    end
    
    % *** these should be SetAccess=private, except that lengthenTo writes to them
    properties(GetAccess=public, SetAccess=protected)
        orientation
        length
        labels
        
        % Distinguish between not having labels and a zero-length dimension with no labels.
        hasLabels = false
    end
    
    % These are SetAccess=private and constant over the lifetime of the object
    properties(GetAccess=public, SetAccess=private)
        % A variables dimension must have labels, but a rows dimension needn't.
        requireLabels = true
        requireUniqueLabels = true
    end
    
    properties(Constant, GetAccess=public)
        subsType = struct('reference',0,'assignment',1,'deletion',2)
    end
    
    methods
        function obj = tableDimension(dimOrientation,dimLength,require,requireUnique,dimLabels)
            if nargin == 0
                return
            end
            
            obj.orientation = dimOrientation;
            obj.length = dimLength;
            obj.requireLabels = require;
            obj.requireUniqueLabels = requireUnique;
            
            if nargin > 4
                if isvector(dimLabels) && (length(dimLabels) == dimLength)
                    obj.hasLabels = true;
                    if dimOrientation == 1
                        obj.labels = dimLabels(:); % row labels as column
                    else
                        obj.labels = dimLabels(:)'; % var labels or meta labels as row
                    end
                else
                    obj.throwIncorrectNumberOfLabels();
                end
            end
        end
        
        %-----------------------------------------------------------------------
        function obj = createLike(obj,dimLength,dimLabels)
            %CREATELIKE Create a tableDimension of the same kind as an existing one.
            if nargin < 3
                obj = obj.createLike_impl(dimLength);
            else
                obj = obj.createLike_impl(dimLength,dimLabels);
            end
        end
                
        
        %-----------------------------------------------------------------------
        function obj = removeLabels(obj)
            if obj.requireLabels
                obj.throwRequiresLabels();
            else
                obj.labels = {}; % optional labels is usually names
                obj.hasLabels = false;
            end
        end
        
        %-----------------------------------------------------------------------
        function labels = emptyLabels(obj,num)
            % EMPTYLABELS Return a vector of empty labels of the right kind.
            
            % Default behavior assumes the labels are names, subclasses with
            % non-name labels need to overload.
            if obj.orientation == 1 % row dim
                labels = repmat({''},num,1);
            else % var dim or meta dim
                labels = repmat({''},1,num);
            end
        end
        
        %-----------------------------------------------------------------------
        function labels = textLabels(obj,indices)
            % TEXTLABELS Return the labels converted to text.
            
            % Default behavior assumes the labels are names, subclasses with
            % non-name labels need to overload.
            if nargin < 2
                labels = obj.labels;
            else
                labels = obj.labels(indices);
            end
        end
        
        %-----------------------------------------------------------------------
        function obj = selectFrom(obj,toSelect)
            %SELECTFROM Return a subset of a tableDimimension for the specified indices.
            % The indices might be out of order, that's OK or repeated, that's handled.
            obj = obj.selectFrom_impl(toSelect);
        end
        
        %-----------------------------------------------------------------------
        function obj = deleteFrom(obj,toDelete)
            %DELETEFROM Return a subset of a tableDimension with the specified indices removed.
            obj = obj.deleteFrom_impl(toDelete);
        end

        %-----------------------------------------------------------------------
        function obj = assignInto(obj,obj2,assignInto)
            obj = obj.assignInto_impl(obj2,assignInto);
        end
        
        %-----------------------------------------------------------------------
        function obj = moveProps(obj,obj2,from,to) %#ok<INUSD>
            % By default, the are no properties (other than labels).
        end
        
        %-----------------------------------------------------------------------
        function obj = mergeProps(obj,obj2,order) %#ok<INUSD>
            % By default, the are no properties (other than labels).
        end
        
        %-----------------------------------------------------------------------
        function obj = setLabels(obj,newLabels,subscripts,fixDups,fixEmpties,fixIllegal)
            %SETLABELS Modify, overwrite, or remove a tableDimProps's labels.
            if nargin < 6
                % Should illegal labels be modified to make them legal?
                fixIllegal = false;
                if nargin < 5
                    % Should empty labels be filled in wth default labels?
                    fixEmpties = false;
                    if nargin < 4
                        % Should duplicate labels be made unique?
                        fixDups = false;
                    end
                end
            end
            
            % Subscripts equal to [] denotes a full assignment while the edge case of a
            % partial assignment to zero labels requires a 1x0 or 0x1 empty.
            fullAssignment = (nargin == 2) || isequal(subscripts,[]);
            if fullAssignment % replacing all labels
                indices = 1:obj.length;
            elseif obj.hasLabels % replacing some labels
                indices = obj.subs2inds(subscripts);
            else % don't allow a subscripted assignment to an empty property
                obj.throwInvalidPartialLabelsAssignment();
            end
            
            % Check the type of the new labels, and convert them to the canonical type as
            % necessary (and allowed). If this is a full assignment of a 0x0, and removing
            % the labels is allowed, validateLabels leaves the shape alone, otherwise it
            % reshapes to a vector of the appropriate orientation.
            obj = obj.validateAndAssignLabels(newLabels,indices,fullAssignment,fixDups,fixEmpties,fixIllegal);
        end
        
        %-----------------------------------------------------------------------
        function [indices,numIndices,maxIndex,isColon,updatedObj] = subs2inds(obj,subscripts,subsType)
            if nargin < 3, subsType = obj.subsType.reference; end; % subsType default to reference (0)
            if nargout < 5
                [indices,numIndices,maxIndex,isColon] = obj.subs2inds_impl(subscripts,subsType);                
            else
                [indices,numIndices,maxIndex,isColon,updatedObj] = obj.subs2inds_impl(subscripts,subsType);
            end
        end
    end
    
    methods (Abstract)
        labels = defaultLabels(indices);
        obj = lengthenTo(obj,maxIndex,newLabels)
        s = getProperties(obj)
    end
    
    %===========================================================================
    methods (Access=protected)                
        function [indices,numIndices,maxIndex,isColon,updatedObj] = subs2inds_impl(obj,subscripts,subsType)
            %SUBS2INDS Convert table subscripts (labels, logical, numeric) to indices.
            
            % Translate a table subscript object into actual subscripts
            if isa(subscripts,'matlab.internal.datatypes.tableSubscript')
                subscripts = subscripts.getSubscripts(obj);
            end
            
            if isnumeric(subscripts) || islogical(subscripts)                
                isColon = false;
                indices = subscripts(:);
                
                % Leave numeric and logical indices alone.
                if isnumeric(indices)
                    if any(isnan(indices))
                        error(message('MATLAB:badsubscript',getString(message('MATLAB:badsubscriptTextRange'))));
                    end
                    numIndices = numel(indices);
                    maxIndex = max(indices);
                else % logical
                    numIndices = sum(indices);
                    maxIndex = find(indices,1,'last');
                end
                
                switch subsType
                    case obj.subsType.reference
                        if maxIndex > obj.length
                            obj.throwIndexOutOfRange();
                        elseif nargout > 4
                            updatedObj = obj.selectFrom(indices);
                        end
                    case obj.subsType.assignment
                        if nargout > 4
                            if maxIndex > obj.length
                                updatedObj = obj.lengthenTo(maxIndex);
                            else
                                updatedObj = obj;
                            end
                        end
                    case obj.subsType.deletion
                        if maxIndex > obj.length
                            obj.throwIndexOutOfRange();
                        elseif nargout > 4
                            updatedObj = obj.deleteFrom(indices);
                        end
                    otherwise
                        assert(false);
                end
                
            elseif ischar(subscripts) && strcmp(subscripts, ':')
                % Leave ':' alone.
                isColon = true;
                indices = subscripts;
                numIndices = obj.length;
                maxIndex = obj.length;
                
                if nargout > 4
                    updatedObj = obj;
                end    
                
            else % "native" subscripts, i.e. names or times
                isColon = false;
                
                % Translate labels into indices.
                [subscripts,indices] = obj.validateNativeSubscripts(subscripts);
                numIndices = numel(subscripts);
                maxIndex = max(indices(:));
                
                switch subsType
                    case obj.subsType.reference
                        if nnz(indices) < numIndices
                            if obj.requireUniqueLabels
                                newLabels = unique(subscripts(~indices),'stable');
                                obj.throwUnrecognizedLabel(newLabels(1));
                            end
                            indices = indices(indices>0);
                        end
                        if nargout > 4
                            updatedObj = obj.selectFrom(indices);
                        end
                    case obj.subsType.assignment
                        if nnz(indices) < numIndices
                            [newLabels,~,newIndices] = unique(subscripts(~indices),'stable');
                            indices(~indices) = obj.length + newIndices;
                            maxIndex = max(indices(:));
                            if nargout > 4
                                updatedObj = obj.lengthenTo(maxIndex,newLabels);
                            end
                        elseif nargout > 4
                            updatedObj = obj;
                        end
                    case obj.subsType.deletion
                        if nnz(indices) < numIndices
                            newLabels = unique(subscripts(~indices),'stable');
                            obj.throwUnrecognizedLabel(newLabels(1));
                        elseif nargout > 4
                            updatedObj = obj.deleteFrom(indices);
                        end
                    otherwise
                        assert(false);
                end      
            end
            if obj.orientation == 1
                indices = indices(:);
            else
                indices = indices(:)';
            end
        end
        
        %-----------------------------------------------------------------------
        function obj = selectFrom_impl(obj,toSelect)
            %SELECTFROM_IMPL implements tableDimension's SELECTFROM method
            import matlab.internal.tableUtils.isUniqueNumeric
            
            if obj.hasLabels
                % Keep the labels the correct orientation.
                if obj.orientation == 1
                    obj.labels = obj.labels(toSelect(:));
                else
                    obj.labels = obj.labels(toSelect(:)');
                end
                
                % Only numeric subscripts can lead to repeated rows (thus labels), no
                % need to check otherwise.
                if isnumeric(toSelect) && ~isUniqueNumeric(toSelect)
                    obj = obj.makeUniqueForRepeatedIndices(toSelect);
                end
                
                obj.length = numel(obj.labels);
            elseif isnumeric(toSelect)
                obj.length = numel(toSelect);
            elseif islogical(toSelect)
                obj.length = sum(toSelect);
            elseif ischar(toSelect) && strcmp(toSelect, ':')
                % leave obj.length alone
            else
                assert(false);
            end            
        end
                    
        %-----------------------------------------------------------------------
        function obj = deleteFrom_impl(obj,toDelete)
            %DELETEFROM_IMPL implements tableDimension's DELETEFROM method
            if obj.hasLabels
                obj.labels(toDelete) = [];
            end
            keepIndices = 1:obj.length;
            keepIndices(toDelete) = [];
            obj.length = numel(keepIndices);
        end
        
        %-----------------------------------------------------------------------
        function obj = assignInto_impl(obj,obj2,assignInto)
            %ASSIGNINTO_IMPL implements tableDimension's ASSIGNITNO method
            if obj.hasLabels && obj2.hasLabels
                obj.labels(assignInto) = obj2.labels;
            elseif obj.hasLabels % && ~obj2.hasLabels
                obj.labels(assignInto) = obj2.emptyLabels(obj2.length); % *** creates invalid labels
            elseif obj2.hasLabels % && ~obj.hasLabels
                obj.labels = obj.emptyLabels(obj.length);
                obj.labels(assignInto) = obj2.labels;
                obj.hasLabels = true;
            end
        end
        
        %-----------------------------------------------------------------------
        function obj = createLike_impl(obj,dimLength,dimLabels)
            %CREATELIKE_IMPL implements tableDimension CREATELIKE method.
            obj.length = dimLength;
            if nargin < 3
                if obj.hasLabels
                    % This creates an invalid set of empty labels that must be set.
                    obj.labels = obj.emptyLabels(dimLength); % *** creates invalid labels
                else
                    obj.hasLabels = false;
                    obj.labels = obj.labels([]);
                end
            else
                obj = obj.setLabels(dimLabels,[]);
            end
        end
        
        %-----------------------------------------------------------------------
        function obj = assignLabels(obj,newLabels,fullAssignment,indices)
            if fullAssignment
                if isvector(newLabels)
                    % The number of new labels has to match what's being assigned to.
                    if numel(newLabels) ~= obj.length
                        obj.throwIncorrectNumberOfLabels();
                    end
                    obj.hasLabels = true;
                    obj.labels = newLabels;
                else % a 0x0
                    % Full assignment of a 0x0 clears out the existing labels, if allowed above by
                    % the subclass's validateLabels.
                    obj.labels = newLabels([]); % force a 0x0, for cosmetics
                    obj.hasLabels = false;
                end
            else % subscripted assignment
                % The number of new labels has to match what's being assigned to.
                if numel(newLabels) ~= numel(indices)
                    obj.throwIncorrectNumberOfLabelsPartial();
                end
                obj.labels(indices) = newLabels;
            end
        end
        
        %-----------------------------------------------------------------------
        function [subscripts,indices] = validateNativeSubscripts(obj,subscripts)
            import matlab.internal.datatypes.isCharStrings
            
            % Default behavior assumes the labels are names, subclasses with
            % non-name labels need to overload.
            if ischar(subscripts) % already weeded out ':'
                if isrow(subscripts)
                    subscripts = { subscripts };
                else
                    obj.throwInvalidLabel();
                end
            elseif isCharStrings(subscripts) % require a cell array, don't allow empty character vectors in it
                % OK
            else
                obj.throwInvalidSubscripts();
            end
            
            indices = zeros(size(subscripts));
            labs = obj.labels;
            for i = 1:numel(indices)
                indFirstMatch = find(strcmp(subscripts{i},labs), 1);
                if indFirstMatch
                    indices(i) = indFirstMatch;
                end
            end
        end
    end
    
    methods (Abstract, Access=protected)
        obj = validateAndAssignLabels(obj,newLabels,indices,fullAssignment,fixDups,fixEmpties,fixIllegal)
        obj = makeUniqueForRepeatedIndices(obj,indices)
        
        throwRequiresLabels(obj)
        throwInvalidPartialLabelsAssignment(obj)
        throwIncorrectNumberOfLabels(obj)
        throwIncorrectNumberOfLabelsPartial(obj)
        throwIndexOutOfRange(obj)
        throwUnrecognizedLabel(obj,label)
        throwInvalidLabel(obj)
        throwInvalidSubscripts(obj)
    end
end