/// <summary> /// Consolidate two string rebuilders, taking advantage of the fact that they have already extracted the line breaks. /// </summary> public static StringRebuilder Consolidate(StringRebuilder left, StringRebuilder right) { Debug.Assert(left.Length > 0); Debug.Assert(right.Length > 0); int length = left.Length + right.Length; char[] result = new char[length]; left.CopyTo(0, result, 0, left.Length); right.CopyTo(0, result, left.Length, right.Length); ILineBreaks lineBreaks; if ((left.LineBreakCount == 0) && (right.LineBreakCount == 0)) { lineBreaks = LineBreakManager.Empty; //_lineBreakSpan defaults to 0, 0 which is what we want } else { ILineBreaksEditor breaks = LineBreakManager.CreateLineBreakEditor(length, left.LineBreakCount + right.LineBreakCount); int offset = 0; if ((result[left.Length] == '\n') && (result[left.Length - 1] == '\r')) { //We have a \r\n spanning the seam ... add that as a special linebreak later. offset = 1; } int leftLines = left.LineBreakCount - offset; for (int i = 0; (i < leftLines); ++i) { Span extent; int lineBreakLength; left.GetLineFromLineNumber(i, out extent, out lineBreakLength); breaks.Add(extent.End, lineBreakLength); } if (offset == 1) { breaks.Add(left.Length - 1, 2); } for (int i = offset; (i < right.LineBreakCount); ++i) { Span extent; int lineBreakLength; right.GetLineFromLineNumber(i, out extent, out lineBreakLength); breaks.Add(extent.End + left.Length, lineBreakLength); } lineBreaks = breaks; } return(StringRebuilderForChars.Create(result, length, lineBreaks)); }
public override StringRebuilder GetSubText(Span span) { if (span.End > this.Length) { throw new ArgumentOutOfRangeException("span"); } if (span.Length == 0) { return(StringRebuilder.Empty); } else if (span.Length == this.Length) { return(this); } else { int firstLineNumber; int lastLineNumber; this.FindFirstAndLastLines(span, out firstLineNumber, out lastLineNumber); return(StringRebuilderForChars.Create(_content, _lineBreaks, span.Start + _textSpanStart, span.Length, firstLineNumber, lastLineNumber - firstLineNumber)); } }
internal static StringRebuilder Load(TextReader reader, long fileSize, out NewlineState newlineState, out LeadingWhitespaceState leadingWhitespaceState, out int longestLineLength, int blockSize = 0, int minCompressedBlockSize = TextImageLoader.BlockSize, // Exposed for unit tests bool throwOnInvalidCharacters = false) { newlineState = new NewlineState(); leadingWhitespaceState = new LeadingWhitespaceState(); int currentLineLength = 0; longestLineLength = 0; char thresholdForInvalidCharacters = throwOnInvalidCharacters ? '\u0001' : '\0'; // Basically the only invalid character is \0, if we are looking for invalid characters. bool useCompressedStringRebuilders = (fileSize >= TextModelOptions.CompressedStorageFileSizeThreshold); if (blockSize == 0) { blockSize = useCompressedStringRebuilders ? TextModelOptions.CompressedStoragePageSize : TextImageLoader.BlockSize; } PageManager pageManager = null; char[] buffer; if (useCompressedStringRebuilders) { pageManager = new PageManager(); buffer = new char[blockSize]; } else { buffer = TextImageLoader.AcquireBuffer(blockSize); } StringRebuilder content = StringRebuilderForChars.Empty; try { bool nextCharIsStartOfLine = true; while (true) { int read = TextImageLoader.LoadNextBlock(reader, buffer); if (read == 0) { break; } var lineBreaks = TextImageLoader.ParseBlock( buffer, read, thresholdForInvalidCharacters, ref newlineState, ref leadingWhitespaceState, ref currentLineLength, ref longestLineLength, ref nextCharIsStartOfLine); char[] bufferForStringBuilder = buffer; if (read < (buffer.Length / 2)) { // We read far less characters than buffer so copy the contents to a new buffer and reuse the original buffer. bufferForStringBuilder = new char[read]; Array.Copy(buffer, bufferForStringBuilder, read); } else { // We're using most of buffer so allocate a new block for the next chunk. buffer = new char[blockSize]; } var newContent = (useCompressedStringRebuilders && (read > minCompressedBlockSize)) ? StringRebuilderForCompressedChars.Create(new Page(pageManager, bufferForStringBuilder, read), lineBreaks) : StringRebuilderForChars.Create(bufferForStringBuilder, read, lineBreaks); content = content.Insert(content.Length, newContent); } longestLineLength = Math.Max(longestLineLength, currentLineLength); } finally { if (!useCompressedStringRebuilders) { TextImageLoader.ReleaseBuffer(buffer); } } return(content); }
internal readonly char[] _content; // Contents should be treated as immutable. internal static StringRebuilder Create(char[] source, int length, ILineBreaks lineBreaks) { return(StringRebuilderForChars.Create(source, lineBreaks, 0, length, 0, lineBreaks.Length)); }
internal static StringRebuilder Load(TextReader reader, long fileSize, string id, out bool hasConsistentLineEndings, out int longestLineLength, int blockSize = 0, int minCompressedBlockSize = TextImageLoader.BlockSize) // Exposed for unit tests { LineEndingState lineEnding = LineEndingState.Unknown; int currentLineLength = 0; longestLineLength = 0; bool useCompressedStringRebuilders = (fileSize >= TextModelOptions.CompressedStorageFileSizeThreshold); if (blockSize == 0) { blockSize = useCompressedStringRebuilders ? TextModelOptions.CompressedStoragePageSize : TextImageLoader.BlockSize; } PageManager pageManager = null; char[] buffer; if (useCompressedStringRebuilders) { pageManager = new PageManager(); buffer = new char[blockSize]; } else { buffer = TextImageLoader.AcquireBuffer(blockSize); } StringRebuilder content = StringRebuilderForChars.Empty; try { while (true) { int read = TextImageLoader.LoadNextBlock(reader, buffer); if (read == 0) { break; } var lineBreaks = LineBreakManager.CreateLineBreakEditor(read); TextImageLoader.ParseBlock(buffer, read, lineBreaks, ref lineEnding, ref currentLineLength, ref longestLineLength); char[] bufferForStringBuilder = buffer; if (read < (buffer.Length / 2)) { // We read far less characters than buffer so copy the contents to a new buffer and reuse the original buffer. bufferForStringBuilder = new char[read]; Array.Copy(buffer, bufferForStringBuilder, read); } else { // We're using most of bufferForStringRebuilder so allocate a new block for the next chunk. buffer = new char[blockSize]; } var newContent = (useCompressedStringRebuilders && (read > minCompressedBlockSize)) ? StringRebuilderForCompressedChars.Create(new Page(pageManager, bufferForStringBuilder, read), lineBreaks) : StringRebuilderForChars.Create(bufferForStringBuilder, read, lineBreaks); content = content.Insert(content.Length, newContent); } longestLineLength = Math.Max(longestLineLength, currentLineLength); hasConsistentLineEndings = lineEnding != LineEndingState.Inconsistent; } finally { if (!useCompressedStringRebuilders) { TextImageLoader.ReleaseBuffer(buffer); } } return(content); }