www.gusucode.com > bigdata 工具箱 matlab源码程序 > bigdata/+matlab/+bigdata/+internal/+util/DisplayInfo.m

    %DisplayInfo Structure holding information required to display a tall array
%   Also includes underlying implementations of display methods.

% Copyright 2016 The MathWorks, Inc.
classdef DisplayInfo
    properties (SetAccess = immutable, GetAccess = private)
        % Function to emit a blank line if necessary (tied to 'format loose')
        BlankLineFcn
    end
    properties (SetAccess = immutable)
        % Does the destination support hyperlinks
        IsHot
        % Do we have preview data
        IsPreviewAvailable
        % Name of the array we're displaying
        Name
        % Structure returned by getArrayInfo
        ArrayInfo
    end
    
    methods (Access = private)
        function [arrayType, showSize, emptyStr] = calculateArrayType(~, dataClass, dataNDims, dataSize)
        % Calculate a word to describe the array. Same logic also works out whether the
        % size needs to be shown.
            
            arrayType = 'array';
            showSize  = true;
            emptyStr  = '';
            if any(dataSize == 0)
                emptyStr = 'empty';
            end
            if dataNDims == 2
                if all(dataSize ~= 1)
                    arrayType = 'matrix';
                elseif all(dataSize == 1)
                    arrayType = ''; % scalar - nothing printed for that though.
                    showSize  = false;
                elseif dataSize(1) == 1
                    arrayType = 'row vector';
                else
                    arrayType = 'column vector';
                end
            end
            
            % Override type for 'table' - never show an array type.
            if strcmp(dataClass, 'table')
                arrayType = '';
            elseif isempty(dataClass) || ~ismember(dataClass, iNumericTypeClasses())
                % Unknown or non-numeric arrays always show simply as 'array'
                arrayType = 'array';
            end
        end
        
        function szStr = calculateSizeStr(~, dataNDims, dataSize)
        % Calculate a MxNx... or similar size string.
            
            if isnan(dataNDims)
                % No size information at all, MxNx...
                dimStrs = {'M', 'N', '...'};
            else
                % Known number of dimensions
                
                % unknownDimLetters are the placeholders we'll use in the size specification
                unknownDimLetters = 'M':'Z';
                
                dimStrs = cell(1, dataNDims);
                for idx = 1:dataNDims
                    if isnan(dataSize(idx))
                        if idx > numel(unknownDimLetters)
                            % Array known to be 15-dimensional, but 15th (or higher) dimension is not
                            % known. Not sure how you'd ever hit this.
                            dimStrs{idx} = '?';
                        else
                            dimStrs{idx} = unknownDimLetters(idx);
                        end
                    else
                        dimStrs{idx} = matlab.bigdata.internal.util.formatBigSize(dataSize(idx));
                    end
                end
            end

            % Join together dimensions using the TIMES character.
            szStr = strjoin(dimStrs, getTimesCharacter());
        end
        
        function printXEqualsLine(obj, dataClass, dataNDims, dataSize)
        % Print the "x = " line and also the array type/size line as appropriate.
            
            [arrayType, showSize, emptyStr] = calculateArrayType(obj, dataClass, dataNDims, dataSize);
            if showSize
                sizeStr = calculateSizeStr(obj, dataNDims, dataSize);
            else
                sizeStr = '';
            end
            
            obj.blankLine();
            fprintf('%s =\n', obj.Name);
            obj.blankLine();

            % Prepend a space to dataClass if it is non-empty.
            dataClassWithSpace = regexprep(dataClass, '(.+)', ' $0');
            
            % Prepend a space to emptyStr if it is non-empty
            emptyStrWithSpace = regexprep(emptyStr, '(.+)', ' $0');
            
            if obj.IsHot
                fprintf('  %s%s <a href="matlab:helpPopup tall" style="font-weight:bold">tall</a>%s %s\n', ...
                        sizeStr, emptyStrWithSpace, dataClassWithSpace, arrayType);
            else
                fprintf('  %s%s tall%s %s\n', ...
                        sizeStr, emptyStrWithSpace, dataClassWithSpace, arrayType);
            end
            obj.blankLine();
        end
        
        function displayPreviewData(obj, previewData, isTruncated)
        % Print out the preview data, adding the continuation characters as required.

            if isempty(previewData)
                return
            end
            
            % Start with the builtin DISP version
            previewText = evalc('disp(previewData)');

            % Keep from the first to the last non-empty lines
            previewLines  = strsplit(previewText, sprintf('\n'), ...
                'CollapseDelimiters', false);
            nonEmptyLines = ~cellfun(@isempty, previewLines);
            previewLines  = previewLines(find(nonEmptyLines, 1, 'first'):find(nonEmptyLines, 1, 'last'));
           
            % Remove any <strong></strong> tags from the display 
            if ~obj.IsHot
                previewLines = regexprep(previewLines, '</?strong>', '');
            end
            
            if ~ismatrix(previewData) && ~ischar(previewData)
                % For >2D data, prepend the variable name to the lines like "x(:,:,1) =" - but
                % not for CHAR data as a perverse string could foil us. Also
                % note that some data type displays (e.g. datetime) miss pieces
                % out, and string adds extra whitespace.
                previewLines = regexprep(previewLines, '^(\(.*\))( =)?( *)$', [obj.Name, '$1$2$3']);
            end

            if isTruncated
                if istable(previewData)
                    % Table display never wraps, so we can do something relatively simple here.
                    iDisplayTablePreviewLinesWithContinuation(previewLines);
                else
                    iDisplayTruncatedPreviewLines(obj.Name, previewData, previewLines);
                end
            else
                fprintf('%s\n', previewLines{:});
            end
            obj.blankLine();
        end
        
        function displayQueries(obj, dataNDims, dataSize)
        % Print a matrix of ? characters to indicate we don't know what's going on.
            if isnan(dataNDims) || dataNDims > 2 || all(isnan(dataSize)) || all(dataSize > 3)
                % Print a matrix of ? for cases:
                % 1. NDims unknown
                % 2. NDims > 2
                % 3. NDims known, but all sizes unknown
                % 4. All dims > 3
                txt = [repmat(sprintf('    ?    ?    ?    ...\n'), 1, 3), ...
                       repmat(sprintf('    :    :    :\n'), 1, 2)];
                fprintf('%s', txt);
            else
                % Try and make the shape of the matrix reflect the known dimensions. Here, we
                % can assume 2-D. Treat unknown sizes as Inf, and then clamp to 3.
                dataSize(isnan(dataSize)) = Inf;
                numQueries = min(3, dataSize);
                extend = dataSize > 3;
                
                normalRow = repmat('    ?', 1, numQueries(2));
                if extend(2)
                    normalRow = [normalRow, '   ...'];
                end
                textRows = repmat({normalRow}, numQueries(1), 1);
                fprintf('%s\n', textRows{:});
                if extend(1)
                    extendRow = repmat('    :', 1, numQueries(2));
                    fprintf('%s\n%s\n', extendRow, extendRow);
                end
            end
            obj.blankLine();
        end
        
        function displayHint(obj)
            if obj.IsHot
                % Only display the hint in 'hot' mode where the hyperlink can function.
                fprintf('%s\n', getString(message('MATLAB:bigdata:array:UnevaluatedArrayDisplayFooter')));
                obj.blankLine();
            end
        end
    end
    
    methods
        function obj = DisplayInfo(name, arrayInfo)
            obj.Name = name;
            formatSpacing = get(0,'FormatSpacing');
            obj.IsHot = matlab.internal.display.isHot;
            if isequal(formatSpacing,'compact')
                obj.BlankLineFcn = @()[];
            else
                obj.BlankLineFcn = @() fprintf('\n');
            end
            obj.IsPreviewAvailable = arrayInfo.IsPreviewAvailable;
            obj.ArrayInfo = arrayInfo;
        end
        function blankLine(obj)
            feval(obj.BlankLineFcn);
        end
        function doDisplay(obj)
            printXEqualsLine(obj, obj.ArrayInfo.Class, obj.ArrayInfo.Ndims, obj.ArrayInfo.Size);
            if obj.IsPreviewAvailable
                displayPreviewData(obj, obj.ArrayInfo.PreviewData, obj.ArrayInfo.IsPreviewTruncated);
            else
                displayQueries(obj, obj.ArrayInfo.Ndims, obj.ArrayInfo.Size);
                displayHint(obj);
            end
        end
        function doDisplayWithFabricatedPreview(obj, fabricatedPreview, dataNDims, dataSize)
        % Call this to apply a fabricated preview array. The fabricated preview is
        % presumed to be truncated.
            printXEqualsLine(obj, class(fabricatedPreview), dataNDims, dataSize);
            isPreviewTruncated = isnan(dataNDims) || size(fabricatedPreview, 1) ~= dataSize(1);
            displayPreviewData(obj, fabricatedPreview, isPreviewTruncated);
            displayHint(obj);
        end
    end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function vals = iNumericTypeClasses()
    integerTypeNames = strsplit(strtrim(sprintf('int%d uint%d ', ...
                                                repmat([8, 16, 32, 64], 2, 1))));
    vals  = ['single', 'double', 'logical', integerTypeNames];
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Given a line of display content, generate a line of continuation indicators
function contLine = iGetContinuationLineFromContentLine(txtLine)
% Find starts of words - i.e. change from space character to non-space. Note
% this is easily foiled by e.g. strings containing spaces.
    firstNonSpaces = regexp(txtLine, '(^|(?<=\s))\S');
    if isempty(firstNonSpaces)
        % Get here if txtLine is completely empty (don't think that can happen) or
        % contains only whitespace (can happen for char
        % display). Either way, treat first column as
        % non-whitespace.
        firstNonSpaces = 1;
    end
    
    contLine = repmat(' ', 1, max(firstNonSpaces));
    % Place continuation indicators in those places
    contLine(firstNonSpaces) = ':';
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function iDisplayTablePreviewLinesWithContinuation(previewLines)
% We're looking for the table display '___' lines, here
% we always need to remove the <strong> tags first
    previewLinesNoEmph = regexprep(previewLines, '</?strong>', '');
    linesMatch         = regexp(previewLinesNoEmph, '^(_|\s)+$');
    lineIdx            = find(~cellfun(@isempty, linesMatch), 1, 'first');
    txtLine            = previewLinesNoEmph{lineIdx};
    contLine           = iGetContinuationLineFromContentLine(txtLine);
    fprintf('%s\n', previewLines{:}, contLine, contLine);
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% For display purposes, this divides a cell array of lines into chunks delimited
% by the supplied regular expression. Because of the way the display stuff
% works, the first chunk returned contains all lines preceding the first
% occurence of the regular expression, at most one instance of that regular
% expression, and then a bunch of lines up to but not including the next
% instance of the regular expression. For example, given output like this:
%
% 1
% 1 Columns 1 through 3
% 1
% 1   0.7742    0.4527    0.8970
% 1   0.0822    0.1448    0.4540
% 1   0.7278    0.0879    0.8887
% 1
% 2 Column 4
% 2
% 2   0.4053
% 2   0.5513
% 2   0.0864
% 2
%
% The preceding digits indicate which chunk the line would count as, presuming a
% delimiter of '^\s*(Columns \d+ through \d+|Column \d+)$'.
function chunks = iDivideLinesIntoChunksByRegexp(allLines, delimiterRegexp)
    matchingLines = find(~cellfun(@isempty, regexp(allLines, delimiterRegexp)));
    if numel(matchingLines) < 1
        % Either zero or one delimiters - return all output as a single chunk.
        chunks = {allLines};
    else
        chunks = cell(1, numel(matchingLines));
        startIdx = [1, matchingLines(2:end)];
        endIdx = [matchingLines(2:end) - 1, numel(allLines)];
        for idx = 1:numel(matchingLines)
            chunks{idx} = allLines(startIdx(idx):endIdx(idx));
        end
    end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function iDisplayTruncatedPreviewLinesOneSetOfColumns(linesOneSetOfColumns)
    nonEmptyLines = ~cellfun(@isempty, linesOneSetOfColumns);
    firstNonBlank = find(nonEmptyLines, 1, 'first');
    lastNonBlank  = find(nonEmptyLines, 1, 'last');
    linesOneSetOfColumnsTrimmed  = linesOneSetOfColumns(firstNonBlank:lastNonBlank);
    contLine = iGetContinuationLineFromContentLine(linesOneSetOfColumnsTrimmed{end});
    fprintf('%s\n', linesOneSetOfColumnsTrimmed{:}, contLine, contLine, ...
            linesOneSetOfColumns{lastNonBlank+1:end});
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function expression = iGetColumnDelimiterRegexp()
    str1 = getString(message('MATLAB:services:printmat:Columns',999,999));
    str2 = getString(message('MATLAB:services:printmat:Column',999));
    expression = ['^\s*(', strrep(str1, '999', '\d+'), '|', ...
                  strrep(str2, '999', '\d+'), ')$'];
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function iDisplayTruncatedPreviewLinesOnePage(linesOnePage)
% On this page, find the last non-blank line and use that to generate
% continuations.
    
    columnDelimiterRegexp = iGetColumnDelimiterRegexp();
    columnChunks = iDivideLinesIntoChunksByRegexp(linesOnePage, columnDelimiterRegexp);
    cellfun(@iDisplayTruncatedPreviewLinesOneSetOfColumns, columnChunks);
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function iDisplayTruncatedPreviewLines(varName, ~, previewLines)
% First, split into pages
    pageDelimiterRegexp = ['^', varName, '\([^\)]+\)( =)? *$'];
    pageChunks = iDivideLinesIntoChunksByRegexp(previewLines,pageDelimiterRegexp);
    cellfun(@iDisplayTruncatedPreviewLinesOnePage, pageChunks);
end