diff --git a/src/Markdig.Tests/Markdig.Tests.csproj b/src/Markdig.Tests/Markdig.Tests.csproj
index 949c757e8..281fdf292 100644
--- a/src/Markdig.Tests/Markdig.Tests.csproj
+++ b/src/Markdig.Tests/Markdig.Tests.csproj
@@ -1,7 +1,7 @@
- net451;netcoreapp2.1
+ netcoreapp2.1;netcoreapp3.1
Library
false
diff --git a/src/Markdig.Tests/TestDescendantsOrder.cs b/src/Markdig.Tests/TestDescendantsOrder.cs
index 2f82bf5cb..996e6b838 100644
--- a/src/Markdig.Tests/TestDescendantsOrder.cs
+++ b/src/Markdig.Tests/TestDescendantsOrder.cs
@@ -1,9 +1,9 @@
using NUnit.Framework;
using Markdig.Syntax;
using Markdig.Syntax.Inlines;
+using System;
using System.Linq;
using System.Collections.Generic;
-using Markdig.Helpers;
namespace Markdig.Tests
{
@@ -33,9 +33,9 @@ public void TestSchemas()
foreach (LiteralInline literalInline in syntaxTree.Descendants())
{
- Assert.AreSame(ArrayHelper.Empty, literalInline.Descendants());
- Assert.AreSame(ArrayHelper.Empty, literalInline.Descendants());
- Assert.AreSame(ArrayHelper.Empty, literalInline.Descendants());
+ Assert.AreSame(Array.Empty(), literalInline.Descendants());
+ Assert.AreSame(Array.Empty(), literalInline.Descendants());
+ Assert.AreSame(Array.Empty(), literalInline.Descendants());
}
foreach (ContainerInline containerInline in syntaxTree.Descendants())
@@ -50,13 +50,13 @@ public void TestSchemas()
if (containerInline.FirstChild is null)
{
- Assert.AreSame(ArrayHelper.Empty, containerInline.Descendants());
- Assert.AreSame(ArrayHelper.Empty, containerInline.FindDescendants());
- Assert.AreSame(ArrayHelper.Empty, (containerInline as MarkdownObject).Descendants());
+ Assert.AreSame(Array.Empty(), containerInline.Descendants());
+ Assert.AreSame(Array.Empty(), containerInline.FindDescendants());
+ Assert.AreSame(Array.Empty(), (containerInline as MarkdownObject).Descendants());
}
- Assert.AreSame(ArrayHelper.Empty, containerInline.Descendants());
- Assert.AreSame(ArrayHelper.Empty, containerInline.Descendants());
+ Assert.AreSame(Array.Empty(), containerInline.Descendants());
+ Assert.AreSame(Array.Empty(), containerInline.Descendants());
}
foreach (ParagraphBlock paragraphBlock in syntaxTree.Descendants())
@@ -65,7 +65,7 @@ public void TestSchemas()
(paragraphBlock as MarkdownObject).Descendants(),
paragraphBlock.Descendants());
- Assert.AreSame(ArrayHelper.Empty, paragraphBlock.Descendants());
+ Assert.AreSame(Array.Empty(), paragraphBlock.Descendants());
}
foreach (ContainerBlock containerBlock in syntaxTree.Descendants())
@@ -80,9 +80,9 @@ public void TestSchemas()
if (containerBlock.Count == 0)
{
- Assert.AreSame(ArrayHelper.Empty, containerBlock.Descendants());
- Assert.AreSame(ArrayHelper.Empty, (containerBlock as Block).Descendants());
- Assert.AreSame(ArrayHelper.Empty, (containerBlock as MarkdownObject).Descendants());
+ Assert.AreSame(Array.Empty(), containerBlock.Descendants());
+ Assert.AreSame(Array.Empty(), (containerBlock as Block).Descendants());
+ Assert.AreSame(Array.Empty(), (containerBlock as MarkdownObject).Descendants());
}
}
}
diff --git a/src/Markdig/Extensions/Abbreviations/AbbreviationHelper.cs b/src/Markdig/Extensions/Abbreviations/AbbreviationHelper.cs
index faed08a5e..b8a92e480 100644
--- a/src/Markdig/Extensions/Abbreviations/AbbreviationHelper.cs
+++ b/src/Markdig/Extensions/Abbreviations/AbbreviationHelper.cs
@@ -1,8 +1,9 @@
-// Copyright (c) Alexandre Mutel. All rights reserved.
+// Copyright (c) Alexandre Mutel. All rights reserved.
// This file is licensed under the BSD-Clause 2 license.
// See the license.txt file in the project root for more information.
using System;
using System.Collections.Generic;
+using Markdig.Helpers;
using Markdig.Syntax;
namespace Markdig.Extensions.Abbreviations
@@ -21,9 +22,9 @@ public static bool HasAbbreviations(this MarkdownDocument document)
public static void AddAbbreviation(this MarkdownDocument document, string label, Abbreviation abbr)
{
- if (document == null) throw new ArgumentNullException(nameof(document));
- if (label == null) throw new ArgumentNullException(nameof(label));
- if (abbr == null) throw new ArgumentNullException(nameof(abbr));
+ if (document == null) ThrowHelper.ArgumentNullException(nameof(document));
+ if (label == null) ThrowHelper.ArgumentNullException_label();
+ if (abbr == null) ThrowHelper.ArgumentNullException(nameof(abbr));
var map = document.GetAbbreviations();
if (map == null)
diff --git a/src/Markdig/Extensions/Abbreviations/AbbreviationParser.cs b/src/Markdig/Extensions/Abbreviations/AbbreviationParser.cs
index fefe87ccc..213d1c9c4 100644
--- a/src/Markdig/Extensions/Abbreviations/AbbreviationParser.cs
+++ b/src/Markdig/Extensions/Abbreviations/AbbreviationParser.cs
@@ -1,6 +1,7 @@
// Copyright (c) Alexandre Mutel. All rights reserved.
// This file is licensed under the BSD-Clause 2 license.
// See the license.txt file in the project root for more information.
+using System;
using System.Collections.Generic;
using Markdig.Helpers;
using Markdig.Parsers;
@@ -115,7 +116,7 @@ private void DocumentOnProcessInlinesBegin(InlineProcessor inlineProcessor, Inli
ValidAbbreviationStart:;
- if (prefixTree.TryMatchLongest(text, i, content.End - i + 1, out KeyValuePair abbreviationMatch))
+ if (prefixTree.TryMatchLongest(text.AsSpan(i, content.End - i + 1), out KeyValuePair abbreviationMatch))
{
var match = abbreviationMatch.Key;
if (!IsValidAbbreviationEnding(match, content, i))
diff --git a/src/Markdig/Extensions/Emoji/EmojiMapping.cs b/src/Markdig/Extensions/Emoji/EmojiMapping.cs
index 0f4fc1c29..11232a94c 100644
--- a/src/Markdig/Extensions/Emoji/EmojiMapping.cs
+++ b/src/Markdig/Extensions/Emoji/EmojiMapping.cs
@@ -1747,10 +1747,10 @@ public EmojiMapping(bool enableSmileys = true)
public EmojiMapping(IDictionary shortcodeToUnicode, IDictionary smileyToShortcode)
{
if (shortcodeToUnicode == null)
- throw new ArgumentNullException(nameof(shortcodeToUnicode));
+ ThrowHelper.ArgumentNullException(nameof(shortcodeToUnicode));
if (smileyToShortcode == null)
- throw new ArgumentNullException(nameof(smileyToShortcode));
+ ThrowHelper.ArgumentNullException(nameof(smileyToShortcode));
// Build emojis and smileys CompactPrefixTree
@@ -1768,7 +1768,7 @@ public EmojiMapping(IDictionary shortcodeToUnicode, IDictionary<
foreach (var shortcode in shortcodeToUnicode)
{
if (string.IsNullOrEmpty(shortcode.Key) || string.IsNullOrEmpty(shortcode.Value))
- throw new ArgumentException("The dictionaries cannot contain null or empty keys/values", nameof(shortcodeToUnicode));
+ ThrowHelper.ArgumentException("The dictionaries cannot contain null or empty keys/values", nameof(shortcodeToUnicode));
firstChars.Add(shortcode.Key[0]);
PrefixTree.Add(shortcode);
@@ -1777,15 +1777,15 @@ public EmojiMapping(IDictionary shortcodeToUnicode, IDictionary<
foreach (var smiley in smileyToShortcode)
{
if (string.IsNullOrEmpty(smiley.Key) || string.IsNullOrEmpty(smiley.Value))
- throw new ArgumentException("The dictionaries cannot contain null or empty keys/values", nameof(smileyToShortcode));
+ ThrowHelper.ArgumentException("The dictionaries cannot contain null or empty keys/values", nameof(smileyToShortcode));
if (!shortcodeToUnicode.TryGetValue(smiley.Value, out string unicode))
- throw new ArgumentException(string.Format("Invalid smiley target: {0} is not present in the emoji shortcodes dictionary", smiley.Value));
+ ThrowHelper.ArgumentException(string.Format("Invalid smiley target: {0} is not present in the emoji shortcodes dictionary", smiley.Value));
firstChars.Add(smiley.Key[0]);
if (!PrefixTree.TryAdd(smiley.Key, unicode))
- throw new ArgumentException(string.Format("Smiley {0} is already present in the emoji mapping", smiley.Key));
+ ThrowHelper.ArgumentException(string.Format("Smiley {0} is already present in the emoji mapping", smiley.Key));
}
OpeningCharacters = new List(firstChars).ToArray();
diff --git a/src/Markdig/Extensions/Emoji/EmojiParser.cs b/src/Markdig/Extensions/Emoji/EmojiParser.cs
index 444fa5cbd..72cb10217 100644
--- a/src/Markdig/Extensions/Emoji/EmojiParser.cs
+++ b/src/Markdig/Extensions/Emoji/EmojiParser.cs
@@ -2,6 +2,7 @@
// This file is licensed under the BSD-Clause 2 license.
// See the license.txt file in the project root for more information.
+using System;
using System.Collections.Generic;
using Markdig.Helpers;
using Markdig.Parsers;
@@ -34,7 +35,7 @@ public override bool Match(InlineProcessor processor, ref StringSlice slice)
}
// Try to match an emoji shortcode or smiley
- if (!_emojiMapping.PrefixTree.TryMatchLongest(slice.Text, slice.Start, slice.Length, out KeyValuePair match))
+ if (!_emojiMapping.PrefixTree.TryMatchLongest(slice.Text.AsSpan(slice.Start, slice.Length), out KeyValuePair match))
{
return false;
}
diff --git a/src/Markdig/Extensions/ListExtras/ListExtraItemParser.cs b/src/Markdig/Extensions/ListExtras/ListExtraItemParser.cs
index e19590297..74d308878 100644
--- a/src/Markdig/Extensions/ListExtras/ListExtraItemParser.cs
+++ b/src/Markdig/Extensions/ListExtras/ListExtraItemParser.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Alexandre Mutel. All rights reserved.
+// Copyright (c) Alexandre Mutel. All rights reserved.
// This file is licensed under the BSD-Clause 2 license.
// See the license.txt file in the project root for more information.
@@ -45,16 +45,16 @@ public override bool TryParse(BlockProcessor state, char pendingBulletType, out
if ((isRomanLow || isRomanUp) && (pendingBulletType == '\0' || pendingBulletType == 'i' || pendingBulletType == 'I'))
{
int startChar = state.Start;
- int endChar = 0;
// With a roman, we can have multiple characters
// Note that we don't validate roman numbers
- while (isRomanLow ? CharHelper.IsRomanLetterLowerPartial(c) : CharHelper.IsRomanLetterUpperPartial(c))
+ do
{
- endChar = state.Start;
c = state.NextChar();
}
+ while (isRomanLow ? CharHelper.IsRomanLetterLowerPartial(c) : CharHelper.IsRomanLetterUpperPartial(c));
- result.OrderedStart = CharHelper.RomanToArabic(state.Line.Text.Substring(startChar, endChar - startChar + 1)).ToString();
+ int orderValue = CharHelper.RomanToArabic(state.Line.Text.AsSpan(startChar, state.Start - startChar));
+ result.OrderedStart = CharHelper.SmallNumberToString(orderValue);
result.BulletType = isRomanLow ? 'i' : 'I';
result.DefaultOrderedStart = isRomanLow ? "i" : "I";
}
@@ -62,7 +62,7 @@ public override bool TryParse(BlockProcessor state, char pendingBulletType, out
{
// otherwise we expect a regular alpha lettered list with a single character.
var isUpper = c.IsAlphaUpper();
- result.OrderedStart = (Char.ToUpperInvariant(c) - 64).ToString();
+ result.OrderedStart = CharHelper.SmallNumberToString((c | 0x20) - 'a' + 1);
result.BulletType = isUpper ? 'A' : 'a';
result.DefaultOrderedStart = isUpper ? "A" : "a";
state.NextChar();
diff --git a/src/Markdig/Extensions/MediaLinks/HostProviderBuilder.cs b/src/Markdig/Extensions/MediaLinks/HostProviderBuilder.cs
index 9a1f35b1c..71d99aabc 100644
--- a/src/Markdig/Extensions/MediaLinks/HostProviderBuilder.cs
+++ b/src/Markdig/Extensions/MediaLinks/HostProviderBuilder.cs
@@ -2,6 +2,7 @@
// This file is licensed under the BSD-Clause 2 license.
// See the license.txt file in the project root for more information.
+using Markdig.Helpers;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -40,9 +41,10 @@ public bool TryHandle(Uri mediaUri, bool isSchemaRelative, out string iframeUrl)
public static IHostProvider Create(string hostPrefix, Func handler, bool allowFullScreen = true, string iframeClass = null)
{
if (string.IsNullOrEmpty(hostPrefix))
- throw new ArgumentException("hostPrefix is null or empty.", nameof(hostPrefix));
+ ThrowHelper.ArgumentException("hostPrefix is null or empty.", nameof(hostPrefix));
if (handler == null)
- throw new ArgumentNullException(nameof(handler));
+ ThrowHelper.ArgumentNullException(nameof(handler));
+
return new DelegateProvider { HostPrefix = hostPrefix, Delegate = handler, AllowFullScreen = allowFullScreen, Class = iframeClass };
}
diff --git a/src/Markdig/Extensions/SelfPipeline/SelfPipelineExtension.cs b/src/Markdig/Extensions/SelfPipeline/SelfPipelineExtension.cs
index f3bc18808..d99e70e0c 100644
--- a/src/Markdig/Extensions/SelfPipeline/SelfPipelineExtension.cs
+++ b/src/Markdig/Extensions/SelfPipeline/SelfPipelineExtension.cs
@@ -1,8 +1,9 @@
-// Copyright (c) Alexandre Mutel. All rights reserved.
+// Copyright (c) Alexandre Mutel. All rights reserved.
// This file is licensed under the BSD-Clause 2 license.
// See the license.txt file in the project root for more information.
using System;
+using Markdig.Helpers;
using Markdig.Renderers;
namespace Markdig.Extensions.SelfPipeline
@@ -29,7 +30,7 @@ public SelfPipelineExtension(string tag = null, string defaultExtensions = null)
tag = string.IsNullOrEmpty(tag) ? DefaultTag : tag;
if (tag.IndexOfAny(new []{'<', '>'}) >= 0)
{
- throw new ArgumentException("Tag cannot contain `<` or `>` characters", nameof(tag));
+ ThrowHelper.ArgumentException("Tag cannot contain `<` or `>` characters", nameof(tag));
}
if (defaultExtensions != null)
@@ -57,7 +58,7 @@ public void Setup(MarkdownPipelineBuilder pipeline)
// Make sure that this pipeline has only one extension (itself)
if (pipeline.Extensions.Count > 1)
{
- throw new InvalidOperationException(
+ ThrowHelper.InvalidOperationException(
"The SelfPipeline extension cannot be configured with other extensions");
}
}
@@ -74,7 +75,7 @@ public void Setup(MarkdownPipeline pipeline, IMarkdownRenderer renderer)
///
public MarkdownPipeline CreatePipelineFromInput(string inputText)
{
- if (inputText == null) throw new ArgumentNullException(nameof(inputText));
+ if (inputText == null) ThrowHelper.ArgumentNullException(nameof(inputText));
var builder = new MarkdownPipelineBuilder();
string defaultConfig = DefaultExtensions;
diff --git a/src/Markdig/Extensions/Tables/PipeTableParser.cs b/src/Markdig/Extensions/Tables/PipeTableParser.cs
index 88f1a878b..b02abe9c8 100644
--- a/src/Markdig/Extensions/Tables/PipeTableParser.cs
+++ b/src/Markdig/Extensions/Tables/PipeTableParser.cs
@@ -30,8 +30,7 @@ public class PipeTableParser : InlineParser, IPostInlineProcessor
/// The options.
public PipeTableParser(LineBreakInlineParser lineBreakParser, PipeTableOptions options = null)
{
- if (lineBreakParser == null) throw new ArgumentNullException(nameof(lineBreakParser));
- this.lineBreakParser = lineBreakParser;
+ this.lineBreakParser = lineBreakParser ?? throw new ArgumentNullException(nameof(lineBreakParser));
OpeningCharacters = new[] { '|', '\n' };
Options = options ?? new PipeTableOptions();
}
diff --git a/src/Markdig/Helpers/ArrayHelper.cs b/src/Markdig/Helpers/ArrayHelper.cs
deleted file mode 100644
index 9ec8ff0f1..000000000
--- a/src/Markdig/Helpers/ArrayHelper.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright (c) Alexandre Mutel. All rights reserved.
-// This file is licensed under the BSD-Clause 2 license.
-// See the license.txt file in the project root for more information.
-namespace Markdig.Helpers
-{
- ///
- /// Helper class for defining Empty arrays.
- ///
- /// Type of an element of the array
- public static class ArrayHelper
- {
- ///
- /// An empty array.
- ///
- public static readonly T[] Empty = new T[0];
- }
-}
\ No newline at end of file
diff --git a/src/Markdig/Helpers/CharHelper.cs b/src/Markdig/Helpers/CharHelper.cs
index fc97bc15e..31f5cd10e 100644
--- a/src/Markdig/Helpers/CharHelper.cs
+++ b/src/Markdig/Helpers/CharHelper.cs
@@ -2,36 +2,6 @@
// This file is licensed under the BSD-Clause 2 license.
// See the license.txt file in the project root for more information.
-
-// The IsHighSurrogate, IsLowSurrogate and ConvertToUtf32 methods are copied from
-// .Net Core source code which is under MIT license. They are copied here because
-// they don't exist in `portable40-net40+sl5+win8+wp8+wpa81`, We probably should remove them
-// once we dropped support for that target platform and use the official .Net methods.
-
-//The MIT License(MIT)
-
-//Copyright(c) .NET Foundation and Contributors
-
-//All rights reserved.
-
-//Permission is hereby granted, free of charge, to any person obtaining a copy
-//of this software and associated documentation files (the "Software"), to deal
-//in the Software without restriction, including without limitation the rights
-//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-//copies of the Software, and to permit persons to whom the Software is
-//furnished to do so, subject to the following conditions:
-
-//The above copyright notice and this permission notice shall be included in all
-//copies or substantial portions of the Software.
-
-//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-//SOFTWARE.
-
using System;
using System.Globalization;
using System.Collections.Generic;
@@ -47,20 +17,20 @@ public static class CharHelper
{
public const int TabSize = 4;
- public const char ZeroSafeChar = '\uFFFD';
+ public const char ReplacementChar = '\uFFFD';
- public const string ZeroSafeString = "\uFFFD";
+ public const string ReplacementCharString = "\uFFFD";
private const char HighSurrogateStart = '\ud800';
private const char HighSurrogateEnd = '\udbff';
private const char LowSurrogateStart = '\udc00';
private const char LowSurrogateEnd = '\udfff';
- // The starting codepoint for Unicode plane 1. Plane 1 contains 0x010000 ~ 0x01ffff.
- private const int UnicodePlane01Start = 0x10000;
-
// We don't support LCDM
- private static readonly Dictionary romanMap = new Dictionary { { 'I', 1 }, { 'V', 5 }, { 'X', 10 } };
+ private static readonly Dictionary romanMap = new Dictionary(6) {
+ { 'i', 1 }, { 'v', 5 }, { 'x', 10 },
+ { 'I', 1 }, { 'V', 5 }, { 'X', 10 }
+ };
private static readonly char[] punctuationExceptions = { '−', '-', '†', '‡' };
@@ -104,36 +74,35 @@ public static void CheckOpenCloseDelimiter(char pc, char c, bool enableWithinWor
}
}
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsRomanLetterPartial(char c)
{
// We don't support LCDM
return IsRomanLetterLowerPartial(c) || IsRomanLetterUpperPartial(c);
}
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsRomanLetterLowerPartial(char c)
{
// We don't support LCDM
return c == 'i' || c == 'v' || c == 'x';
}
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsRomanLetterUpperPartial(char c)
{
// We don't support LCDM
return c == 'I' || c == 'V' || c == 'X';
}
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
- public static int RomanToArabic(string text)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static int RomanToArabic(ReadOnlySpan text)
{
int result = 0;
for (int i = 0; i < text.Length; i++)
{
- var character = char.ToUpperInvariant(text[i]);
- var candidate = romanMap[character];
- if (i + 1 < text.Length && candidate < romanMap[char.ToUpperInvariant(text[i + 1])])
+ var candidate = romanMap[text[i]];
+ if ((uint)(i + 1) < text.Length && candidate < romanMap[text[i + 1]])
{
result -= candidate;
}
@@ -145,7 +114,7 @@ public static int RomanToArabic(string text)
return result;
}
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int AddTab(int column)
{
// return ((column + TabSize) / TabSize) * TabSize;
@@ -153,18 +122,18 @@ public static int AddTab(int column)
return TabSize + (column & ~(TabSize - 1));
}
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsAcrossTab(int column)
{
return (column & (TabSize - 1)) != 0;
}
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool Contains(this char[] charList, char c)
{
- for (int i = 0; i < charList.Length; i++)
+ foreach (char ch in charList)
{
- if (charList[i] == c)
+ if (ch == c)
{
return true;
}
@@ -172,7 +141,7 @@ public static bool Contains(this char[] charList, char c)
return false;
}
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsWhitespace(this char c)
{
// 2.1 Characters and lines
@@ -180,20 +149,20 @@ public static bool IsWhitespace(this char c)
return c <= ' ' && (c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r');
}
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsControl(this char c)
{
return c < ' ' || char.IsControl(c);
}
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsEscapableSymbol(this char c)
{
// char.IsSymbol also works with Unicode symbols that cannot be escaped based on the specification.
return (c > ' ' && c < '0') || (c > '9' && c < 'A') || (c > 'Z' && c < 'a') || (c > 'z' && c < 127) || c == '•';
}
- //[MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ //[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsWhiteSpaceOrZero(this char c)
{
return IsZero(c) || IsWhitespace(c);
@@ -253,19 +222,19 @@ internal static bool IsSpaceOrPunctuation(this char c)
}
}
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsNewLine(this char c)
{
return c == '\n';
}
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsZero(this char c)
{
return c == '\0';
}
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsSpace(this char c)
{
// 2.1 Characters and lines
@@ -273,7 +242,7 @@ public static bool IsSpace(this char c)
return c == ' ';
}
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsTab(this char c)
{
// 2.1 Characters and lines
@@ -281,13 +250,13 @@ public static bool IsTab(this char c)
return c == '\t';
}
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsSpaceOrTab(this char c)
{
return IsSpace(c) || IsTab(c);
}
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static char EscapeInsecure(this char c)
{
// 2.3 Insecure characters
@@ -295,25 +264,25 @@ public static char EscapeInsecure(this char c)
return c == '\0' ? '\ufffd' : c;
}
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsAlphaUpper(this char c)
{
return (uint)(c - 'A') <= ('Z' - 'A');
}
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsAlpha(this char c)
{
return (uint)((c - 'A') & ~0x20) <= ('Z' - 'A');
}
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsAlphaNumeric(this char c)
{
return IsAlpha(c) || IsDigit(c);
}
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsDigit(this char c)
{
return (uint)(c - '0') <= ('9' - '0');
@@ -362,40 +331,31 @@ public static bool IsAsciiPunctuation(this char c)
return false;
}
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsEmailUsernameSpecialChar(char c)
{
return ".!#$%&'*+/=?^_`{|}~-+.~".IndexOf(c) >= 0;
}
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsHighSurrogate(char c)
{
return IsInInclusiveRange(c, HighSurrogateStart, HighSurrogateEnd);
}
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsLowSurrogate(char c)
{
return IsInInclusiveRange(c, LowSurrogateStart, LowSurrogateEnd);
}
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool IsInInclusiveRange(char c, char min, char max)
- => (uint) (c - min) <= (uint) (max - min);
+ => (uint)(c - min) <= (uint)(max - min);
- public static int ConvertToUtf32(char highSurrogate, char lowSurrogate)
- {
- if (!IsHighSurrogate(highSurrogate))
- {
- throw new ArgumentOutOfRangeException(nameof(highSurrogate), "Invalid high surrogate");
- }
- if (!IsLowSurrogate(lowSurrogate))
- {
- throw new ArgumentOutOfRangeException(nameof(lowSurrogate), "Invalid low surrogate");
- }
- return (((highSurrogate - HighSurrogateStart) * 0x400) + (lowSurrogate - LowSurrogateStart) + UnicodePlane01Start);
- }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static bool IsInInclusiveRange(int value, uint min, uint max)
+ => ((uint)value - min) <= (max - min);
public static IEnumerable ToUtf32(StringSlice text)
{
@@ -785,6 +745,24 @@ public static bool IsLeftToRight(int c)
c == 0x002128 || c == 0x002395 ||
c == 0x01D4A2 || c == 0x01D4BB ||
c == 0x01D546;
+ }
+
+ // Used by ListExtraItemParser to format numbers from 1 - 26
+ private static readonly string[] smallNumberStringCache = {
+ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
+ "10", "11", "12", "13", "14", "15", "16", "17", "18", "19",
+ "20", "21", "22", "23", "24", "25", "26",
+ };
+
+ internal static string SmallNumberToString(int number)
+ {
+ string[] cache = smallNumberStringCache;
+ if ((uint)number < (uint)cache.Length)
+ {
+ return cache[number];
+ }
+
+ return number.ToString();
}
}
}
\ No newline at end of file
diff --git a/src/Markdig/Helpers/CharacterMap.cs b/src/Markdig/Helpers/CharacterMap.cs
index f618981a5..edff79eeb 100644
--- a/src/Markdig/Helpers/CharacterMap.cs
+++ b/src/Markdig/Helpers/CharacterMap.cs
@@ -17,8 +17,8 @@ namespace Markdig.Helpers
public class CharacterMap where T : class
{
private readonly T[] asciiMap;
- private readonly Dictionary nonAsciiMap;
- private readonly BitVector128 isOpeningCharacter;
+ private readonly Dictionary nonAsciiMap;
+ private readonly BoolVector128 isOpeningCharacter;
///
/// Initializes a new instance of the class.
@@ -27,56 +27,43 @@ public class CharacterMap where T : class
///
public CharacterMap(IEnumerable> maps)
{
- if (maps == null) throw new ArgumentNullException(nameof(maps));
+ if (maps == null) ThrowHelper.ArgumentNullException(nameof(maps));
var charSet = new HashSet();
int maxChar = 0;
foreach (var map in maps)
{
var openingChar = map.Key;
-
charSet.Add(openingChar);
- if (openingChar < 128 && openingChar > maxChar)
+ if (openingChar < 128)
{
- maxChar = openingChar;
+ maxChar = Math.Max(maxChar, openingChar);
}
- else if (openingChar >= 128 && nonAsciiMap == null)
+ else
{
- // Initialize only if with have an actual non-ASCII opening character
- nonAsciiMap = new Dictionary();
+ nonAsciiMap ??= new Dictionary();
}
}
+
OpeningCharacters = charSet.ToArray();
Array.Sort(OpeningCharacters);
asciiMap = new T[maxChar + 1];
- var isOpeningCharacter = new BitVector128();
foreach (var state in maps)
{
- var openingChar = state.Key;
- T stateByChar;
+ char openingChar = state.Key;
if (openingChar < 128)
{
- stateByChar = asciiMap[openingChar];
-
- if (stateByChar == null)
- {
- asciiMap[openingChar] = state.Value;
- }
+ asciiMap[openingChar] ??= state.Value;
isOpeningCharacter.Set(openingChar);
}
- else
+ else if (!nonAsciiMap.ContainsKey(openingChar))
{
- if (!nonAsciiMap.TryGetValue(openingChar, out stateByChar))
- {
- nonAsciiMap[openingChar] = state.Value;
- }
+ nonAsciiMap[openingChar] = state.Value;
}
}
-
- this.isOpeningCharacter = isOpeningCharacter;
}
///
@@ -89,24 +76,26 @@ public CharacterMap(IEnumerable> maps)
///
/// The opening character.
/// A list of parsers valid for the specified opening character or null if no parsers registered.
- public T this[char openingChar]
+ public T this[uint openingChar]
{
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
- T map = null;
- if (openingChar < asciiMap.Length)
+ T[] asciiMap = this.asciiMap;
+ if (openingChar < (uint)asciiMap.Length)
{
- map = asciiMap[openingChar];
+ return asciiMap[openingChar];
}
- else if (nonAsciiMap != null)
+ else
{
- nonAsciiMap.TryGetValue(openingChar, out map);
+ T map = null;
+ nonAsciiMap?.TryGetValue(openingChar, out map);
+ return map;
}
- return map;
}
}
+
///
/// Searches for an opening character from a registered parser in the specified string.
///
@@ -116,57 +105,111 @@ public T this[char openingChar]
/// Index position within the string of the first opening character found in the specified text; if not found, returns -1
public int IndexOfOpeningCharacter(string text, int start, int end)
{
- var openingChars = isOpeningCharacter;
-
- unsafe
+ if (nonAsciiMap is null)
{
- fixed (char* pText = text)
+#if NETCOREAPP3_1
+ ref char textRef = ref Unsafe.AsRef(in text.GetPinnableReference());
+ for (; start <= end; start++)
{
- if (nonAsciiMap == null)
+ if (IntPtr.Size == 4)
{
- for (int i = start; i <= end; i++)
+ uint c = Unsafe.Add(ref textRef, start);
+ if (c < 128 && isOpeningCharacter[c])
{
- var c = pText[i];
- if (c < 128 && openingChars[c])
- {
- return i;
- }
+ return start;
}
}
else
+ {
+ ulong c = Unsafe.Add(ref textRef, start);
+ if (c < 128 && isOpeningCharacter[c])
+ {
+ return start;
+ }
+ }
+ }
+#else
+ unsafe
+ {
+ fixed (char* pText = text)
{
for (int i = start; i <= end; i++)
{
- var c = pText[i];
- if (c < 128 ? openingChars[c] : nonAsciiMap.ContainsKey(c))
+ char c = pText[i];
+ if (c < 128 && isOpeningCharacter[c])
{
return i;
}
}
}
}
+#endif
+ return -1;
}
+ else
+ {
+ return IndexOfOpeningCharacterNonAscii(text, start, end);
+ }
+ }
+
+ private int IndexOfOpeningCharacterNonAscii(string text, int start, int end)
+ {
+#if NETCOREAPP3_1
+ ref char textRef = ref Unsafe.AsRef(in text.GetPinnableReference());
+ for (int i = start; i <= end; i++)
+ {
+ char c = Unsafe.Add(ref textRef, i);
+ if (c < 128 ? isOpeningCharacter[c] : nonAsciiMap.ContainsKey(c))
+ {
+ return i;
+ }
+ }
+#else
+ unsafe
+ {
+ fixed (char* pText = text)
+ {
+ for (int i = start; i <= end; i++)
+ {
+ char c = pText[i];
+ if (c < 128 ? isOpeningCharacter[c] : nonAsciiMap.ContainsKey(c))
+ {
+ return i;
+ }
+ }
+ }
+ }
+#endif
return -1;
}
+ }
- internal unsafe struct BitVector128
+ internal unsafe struct BoolVector128
+ {
+ private fixed bool values[128];
+
+ public void Set(char c)
{
- fixed uint values[4];
+ Debug.Assert(c < 128);
+ values[c] = true;
+ }
- public void Set(char c)
+ public readonly bool this[uint c]
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get
{
Debug.Assert(c < 128);
- values[c >> 5] |= (uint)1 << c;
+ return values[c];
}
-
- public readonly bool this[char c]
+ }
+ public readonly bool this[ulong c]
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get
{
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
- get
- {
- Debug.Assert(c < 128);
- return (values[c >> 5] & (uint)1 << c) != 0;
- }
+ Debug.Assert(c < 128 && IntPtr.Size == 8);
+ return values[c];
}
}
}
diff --git a/src/Markdig/Helpers/CompactPrefixTree.cs b/src/Markdig/Helpers/CompactPrefixTree.cs
index 8c6e067f8..207a1b866 100644
--- a/src/Markdig/Helpers/CompactPrefixTree.cs
+++ b/src/Markdig/Helpers/CompactPrefixTree.cs
@@ -27,10 +27,7 @@ namespace Markdig.Helpers
///
/// The value associated with the key
[ExcludeFromCodeCoverage]
- internal sealed class CompactPrefixTree
-//#if !LEGACY
-// : IReadOnlyDictionary, IReadOnlyList>
-//#endif
+ internal sealed class CompactPrefixTree : IReadOnlyDictionary, IReadOnlyList>
{
///
/// Used internally to control behavior of insertion
@@ -120,7 +117,7 @@ public int TreeCapacity
}
}
}
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
private void EnsureTreeCapacity(int min)
{
if (_tree.Length < min)
@@ -169,7 +166,7 @@ public int Capacity
}
}
}
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
private void EnsureCapacity(int min)
{
// Expansion logic as in System.Collections.Generic.List
@@ -227,7 +224,7 @@ public int ChildrenCapacity
}
}
}
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
private void EnsureChildrenCapacity(int min)
{
if (_children.Length < min)
@@ -254,7 +251,7 @@ private void EnsureChildrenCapacityRare(int min)
// Inspired by Markdig's CharacterMap
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
private bool TryGetRoot(char rootChar, out int rootNodeIndex)
{
if (rootChar < 128)
@@ -338,7 +335,7 @@ public CompactPrefixTree(ICollection> input)
/// The key/value pair of the element at the specified index
public KeyValuePair this[int index]
{
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
if ((uint)index >= (uint)Count) ThrowHelper.ThrowIndexOutOfRangeException();
@@ -355,7 +352,7 @@ public TValue this[string key]
{
get
{
- if (TryMatchExact(key, out KeyValuePair match))
+ if (TryMatchExact(key.AsSpan(), out KeyValuePair match))
return match.Value;
throw new KeyNotFoundException(key);
}
@@ -367,7 +364,6 @@ public TValue this[string key]
}
} // Get, Set
-#if NETCORE
///
/// Gets the value associated with the specified key
///
@@ -382,7 +378,6 @@ public KeyValuePair this[ReadOnlySpan key]
throw new KeyNotFoundException(key.ToString());
}
} // Get only
-#endif
#endregion this[] accessors
@@ -713,50 +708,6 @@ private void InsertLeafNode(in KeyValuePair pair, char nodeChar)
#region TryMatch longest
- ///
- /// Tries to find the longest prefix of text, starting at offset, that is contained in this
- ///
- /// The text in which to search for the prefix
- /// Index of the character at which to start searching
- /// The found prefix and the corresponding value
- /// True if a match was found, false otherwise
- public bool TryMatchLongest(string text, int offset, out KeyValuePair match)
- {
-#if NETCORE
- return TryMatchLongest(text.AsSpan(offset), out match);
-#else
- return TryMatchLongest(text, offset, text.Length - offset, out match);
-#endif
- }
-
- ///
- /// Tries to find the longest prefix of text, that is contained in this
- ///
- /// The text in which to search for the prefix
- /// The found prefix and the corresponding value
- /// True if a match was found, false otherwise
- public bool TryMatchLongest(string text, out KeyValuePair match)
- {
- if (text == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.text);
-#if NETCORE
- return TryMatchLongest(text.AsSpan(), out match);
-#else
- return TryMatchLongest(text, 0, text.Length, out match);
-#endif
- }
-
- ///
- /// Tries to find the longest prefix of text, starting at offset, that is contained in this
- ///
- /// The text in which to search for the prefix
- /// The offset in text at which to start looking for the prefix
- /// The longest prefix allowed to match
- /// The found prefix and the corresponding value
- /// True if a match was found, false otherwise
-#if NETCORE
- public bool TryMatchLongest(string text, int offset, int length, out KeyValuePair match)
- => TryMatchLongest(text.AsSpan(offset, length), out match);
-
///
/// Tries to find the longest prefix of text, that is contained in this
///
@@ -768,20 +719,6 @@ public bool TryMatchLongest(ReadOnlySpan text, out KeyValuePair match)
- {
- int limit = offset + length;
- if (text == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.text);
-
- if (offset < 0 || length < 0 || text.Length < limit)
- ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.offsetLength, ExceptionReason.InvalidOffsetLength);
-
- match = default;
- if (length == 0 || !TryGetRoot(text[offset], out int nodeIndex))
- return false;
-#endif
int matchIndex = -1;
int depth = 1;
@@ -790,11 +727,7 @@ public bool TryMatchLongest(string text, int offset, int length, out KeyValuePai
if (node.ChildChar == 0) goto LeafNodeFound;
if (node.MatchIndex != -1) matchIndex = node.MatchIndex;
-#if NETCORE
for (int i = 1; i < text.Length; i++)
-#else
- for (int i = offset + 1; i < limit; i++)
-#endif
{
char c = text[i];
@@ -826,7 +759,6 @@ public bool TryMatchLongest(string text, int offset, int length, out KeyValuePai
LeafNodeFound:;
ref KeyValuePair possibleMatch = ref _matches[node.MatchIndex];
-#if NETCORE
if (possibleMatch.Key.Length <= text.Length)
{
// Check that the rest of the strings match
@@ -835,18 +767,6 @@ public bool TryMatchLongest(string text, int offset, int length, out KeyValuePai
matchIndex = node.MatchIndex;
}
}
-#else
- if (possibleMatch.Key.Length <= length)
- {
- // Check that the rest of the strings match
- for (int i = offset + depth, j = depth; j < possibleMatch.Key.Length; i++, j++)
- {
- if (text[i] != possibleMatch.Key[j])
- goto Return;
- }
- matchIndex = node.MatchIndex;
- }
-#endif
Return:;
if (matchIndex != -1)
@@ -861,50 +781,6 @@ public bool TryMatchLongest(string text, int offset, int length, out KeyValuePai
#region TryMatch exact
- ///
- /// Tries to find a suffix of text, starting at offset, that is contained in this and is exactly (text.Length - offset) characters long
- ///
- /// The text in which to search for the prefix
- /// Index of the character at which to start searching
- /// The found prefix and the corresponding value
- /// True if a match was found, false otherwise
- public bool TryMatchExact(string text, int offset, out KeyValuePair match)
- {
-#if NETCORE
- return TryMatchExact(text.AsSpan(offset), out match);
-#else
- return TryMatchExact(text, offset, text.Length - offset, out match);
-#endif
- }
-
- ///
- /// Tries to find a prefix of text, that is contained in this and is exactly text.Length characters long
- ///
- /// The text in which to search for the prefix
- /// The found prefix and the corresponding value
- /// True if a match was found, false otherwise
- public bool TryMatchExact(string text, out KeyValuePair match)
- {
- if (text == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.text);
-#if NETCORE
- return TryMatchExact(text.AsSpan(), out match);
-#else
- return TryMatchExact(text, 0, text.Length, out match);
-#endif
- }
-
- ///
- /// Tries to find a prefix of text, starting at offset, that is contained in this and is exactly length characters long
- ///
- /// The text in which to search for the prefix
- /// The offset in text at which to start looking for the prefix
- /// The longest prefix allowed to match
- /// The found prefix and the corresponding value
- /// True if a match was found, false otherwise
-#if NETCORE
- public bool TryMatchExact(string text, int offset, int length, out KeyValuePair match)
- => TryMatchExact(text.AsSpan(offset, length), out match);
-
///
/// Tries to find a prefix of text, that is contained in this and is exactly text.Length characters long
///
@@ -916,39 +792,18 @@ public bool TryMatchExact(ReadOnlySpan text, out KeyValuePair match)
- {
- int limit = offset + length;
- if (text == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.text);
-
- if (offset < 0 || length < 0 || text.Length < limit)
- ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.offsetLength, ExceptionReason.InvalidOffsetLength);
- match = default;
- if (length == 0 || !TryGetRoot(text[offset], out int nodeIndex))
- return false;
-#endif
int depth = 1;
ref Node node = ref _tree[nodeIndex];
if (node.ChildChar == 0) goto LeafNodeFound;
-#if NETCORE
if (node.MatchIndex != -1 && text.Length == 1)
-#else
- if (node.MatchIndex != -1 && length == 1)
-#endif
{
match = _matches[node.MatchIndex];
return true;
}
-#if NETCORE
for (int i = 1; i < text.Length; i++)
-#else
- for (int i = offset + 1; i < limit; i++)
-#endif
{
char c = text[i];
@@ -977,81 +832,20 @@ public bool TryMatchExact(string text, int offset, int length, out KeyValuePair<
if (node.MatchIndex == -1) return false;
match = _matches[node.MatchIndex];
-#if NETCORE
Debug.Assert(match.Key.Length == text.Length);
-#else
- Debug.Assert(match.Key.Length == length);
-#endif
return true;
LeafNodeFound:;
match = _matches[node.MatchIndex];
-#if NETCORE
+
return match.Key.Length == text.Length &&
text.Slice(depth).Equals(match.Key.AsSpan(depth), StringComparison.Ordinal);
-#else
- if (match.Key.Length == length)
- {
- // Check that the rest of the strings match
- for (int i = offset + depth, j = depth; j < match.Key.Length; i++, j++)
- {
- if (text[i] != match.Key[j])
- return false;
- }
- return true;
- }
- return false;
-#endif
}
#endregion TryMatch exact
#region TryMatch shortest
- ///
- /// Tries to find the shortest prefix of text, starting at offset, that is contained in this
- ///
- /// The text in which to search for the prefix
- /// Index of the character at which to start searching
- /// The found prefix and the corresponding value
- /// True if a match was found, false otherwise
- public bool TryMatchShortest(string text, int offset, out KeyValuePair match)
- {
-#if NETCORE
- return TryMatchShortest(text.AsSpan(offset), out match);
-#else
- return TryMatchShortest(text, offset, text.Length - offset, out match);
-#endif
- }
-
- ///
- /// Tries to find the shortest prefix of text, that is contained in this
- ///
- /// The text in which to search for the prefix
- /// The found prefix and the corresponding value
- /// True if a match was found, false otherwise
- public bool TryMatchShortest(string text, out KeyValuePair match)
- {
- if (text == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.text);
-#if NETCORE
- return TryMatchShortest(text.AsSpan(), out match);
-#else
- return TryMatchShortest(text, 0, text.Length, out match);
-#endif
- }
-
- ///
- /// Tries to find the shortest prefix of text, starting at offset, that is contained in this
- ///
- /// The text in which to search for the prefix
- /// The offset in text at which to start looking for the prefix
- /// The longest prefix allowed to match
- /// The found prefix and the corresponding value
- /// True if a match was found, false otherwise
-#if NETCORE
- public bool TryMatchShortest(string text, int offset, int length, out KeyValuePair match)
- => TryMatchShortest(text.AsSpan(offset, length), out match);
-
///
/// Tries to find the shortest prefix of text, that is contained in this
///
@@ -1063,20 +857,7 @@ public bool TryMatchShortest(ReadOnlySpan text, out KeyValuePair match)
- {
- int limit = offset + length;
- if (text == null)
- ThrowHelper.ThrowArgumentNullException(ExceptionArgument.text);
-
- if (offset < 0 || length < 0 || text.Length < limit)
- ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.offsetLength, ExceptionReason.InvalidOffsetLength);
- match = default;
- if (length == 0 || !TryGetRoot(text[offset], out int nodeIndex))
- return false;
-#endif
ref Node node = ref _tree[nodeIndex];
if (node.MatchIndex != -1)
{
@@ -1084,11 +865,7 @@ public bool TryMatchShortest(string text, int offset, int length, out KeyValuePa
return true;
}
-#if NETCORE
for (int i = 1; i < text.Length; i++)
-#else
- for (int i = offset + 1; i < limit; i++)
-#endif
{
char c = text[i];
@@ -1131,7 +908,7 @@ public bool TryMatchShortest(string text, int offset, int length, out KeyValuePa
/// The key to locate in this
/// True if the key is contained in this PrefixTree, false otherwise.
public bool ContainsKey(string key)
- => TryMatchExact(key, out _);
+ => TryMatchExact(key.AsSpan(), out _);
///
/// Gets the value associated with the specified key
@@ -1141,7 +918,7 @@ public bool ContainsKey(string key)
/// True if the key is contained in this PrefixTree, false otherwise.
public bool TryGetValue(string key, out TValue value)
{
- bool ret = TryMatchExact(key, out KeyValuePair match);
+ bool ret = TryMatchExact(key.AsSpan(), out KeyValuePair match);
value = match.Value;
return ret;
}
@@ -1175,9 +952,8 @@ public IEnumerable Values
///
///
public IEnumerator> GetEnumerator() => new Enumerator(_matches);
-//#if !LEGACY
- //IEnumerator IEnumerable.GetEnumerator() => new Enumerator(_matches);
-//#endif
+
+ IEnumerator IEnumerable.GetEnumerator() => new Enumerator(_matches);
///
/// Enumerates the elements of a
diff --git a/src/Markdig/Helpers/EntityHelper.cs b/src/Markdig/Helpers/EntityHelper.cs
index 2f1c648fe..4fd7f328a 100644
--- a/src/Markdig/Helpers/EntityHelper.cs
+++ b/src/Markdig/Helpers/EntityHelper.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Alexandre Mutel. All rights reserved.
+// Copyright (c) Alexandre Mutel. All rights reserved.
// This file is licensed under the BSD-Clause 2 license.
// See the license.txt file in the project root for more information.
@@ -33,6 +33,7 @@
using System;
using System.Collections.Generic;
+using System.Text;
namespace Markdig.Helpers
{
@@ -46,11 +47,10 @@ public static class EntityHelper
///
/// The entity without & and ; symbols, for example, copy.
/// The unicode character set or null if the entity was not recognized.
- public static string DecodeEntity(string entity)
+ public static string DecodeEntity(ReadOnlySpan entity)
{
- string result;
- if (EntityMap.TryGetValue(entity, out result))
- return result;
+ if (EntityMap.TryMatchExact(entity, out KeyValuePair result))
+ return result.Value;
return null;
}
@@ -61,25 +61,49 @@ public static string DecodeEntity(string entity)
/// The unicode character set or null if the entity was not recognized.
public static string DecodeEntity(int utf32)
{
- if (utf32 < 0 || utf32 > 1114111 || (utf32 >= 55296 && utf32 <= 57343))
- return null;
+ if (!CharHelper.IsInInclusiveRange(utf32, 1, 1114111) || CharHelper.IsInInclusiveRange(utf32, 55296, 57343))
+ return CharHelper.ReplacementCharString;
if (utf32 < 65536)
return char.ToString((char)utf32);
utf32 -= 65536;
- return new string(new char[]
+ return new string(
+#if NETCORE
+ stackalloc
+#else
+ new
+#endif
+ char[]
{
- (char)(utf32 / 1024 + 55296),
- (char)(utf32 % 1024 + 56320)
+ (char)((uint)utf32 / 1024 + 55296),
+ (char)((uint)utf32 % 1024 + 56320)
});
}
- #region [ EntityMap ]
+ public static void DecodeEntity(int utf32, StringBuilder sb)
+ {
+ if (!CharHelper.IsInInclusiveRange(utf32, 1, 1114111) || CharHelper.IsInInclusiveRange(utf32, 55296, 57343))
+ {
+ sb.Append(CharHelper.ReplacementChar);
+ }
+ else if (utf32 < 65536)
+ {
+ sb.Append((char)utf32);
+ }
+ else
+ {
+ utf32 -= 65536;
+ sb.Append((char)((uint)utf32 / 1024 + 55296));
+ sb.Append((char)((uint)utf32 % 1024 + 56320));
+ }
+ }
+
+#region [ EntityMap ]
///
/// Source: http://www.w3.org/html/wg/drafts/html/master/syntax.html#named-character-references
///
- private static readonly Dictionary EntityMap = new Dictionary(2125, StringComparer.Ordinal)
+ private static readonly CompactPrefixTree EntityMap = new CompactPrefixTree(2125, 3385, 3510)
{
{ "Aacute", "\u00C1" },
{ "aacute", "\u00E1" },
@@ -2207,6 +2231,6 @@ public static string DecodeEntity(int utf32)
{ "zwj", "\u200D" },
{ "zwnj", "\u200C" }
};
- #endregion
+#endregion
}
}
\ No newline at end of file
diff --git a/src/Markdig/Helpers/ExcludeFromCodeCoverageAttribute.cs b/src/Markdig/Helpers/ExcludeFromCodeCoverageAttribute.cs
deleted file mode 100644
index ac185b74c..000000000
--- a/src/Markdig/Helpers/ExcludeFromCodeCoverageAttribute.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-#if NET35
-namespace System.Diagnostics.CodeAnalysis
-{
- [AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = false)]
- internal class ExcludeFromCodeCoverageAttribute : Attribute
- {
-
- }
-}
-#endif
\ No newline at end of file
diff --git a/src/Markdig/Helpers/HtmlHelper.cs b/src/Markdig/Helpers/HtmlHelper.cs
index d46ac3b39..4d385ad30 100644
--- a/src/Markdig/Helpers/HtmlHelper.cs
+++ b/src/Markdig/Helpers/HtmlHelper.cs
@@ -51,7 +51,7 @@ public static bool TryParseHtmlTag(ref StringSlice text, out string htmlTag)
public static bool TryParseHtmlTag(ref StringSlice text, StringBuilder builder)
{
- if (builder == null) throw new ArgumentNullException(nameof(builder));
+ if (builder == null) ThrowHelper.ArgumentNullException(nameof(builder));
var c = text.CurrentChar;
if (c != '<')
{
@@ -450,11 +450,7 @@ public static string Unescape(string text, bool removeBackSlash = true)
while ((searchPos = text.IndexOfAny(search, searchPos)) != -1)
{
- if (sb == null)
- {
- sb = StringBuilderCache.Local();
- sb.Length = 0;
- }
+ sb ??= StringBuilderCache.Local();
c = text[searchPos];
if (removeBackSlash && c == '\\')
{
@@ -472,10 +468,7 @@ public static string Unescape(string text, bool removeBackSlash = true)
}
else if (c == '&')
{
- int entityNameStart;
- int entityNameLength;
- int numericEntity;
- var match = ScanEntity(new StringSlice(text, searchPos, text.Length - 1), out numericEntity, out entityNameStart, out entityNameLength);
+ var match = ScanEntity(new StringSlice(text, searchPos, text.Length - 1), out int numericEntity, out int entityNameStart, out int entityNameLength);
if (match == 0)
{
searchPos++;
@@ -486,8 +479,7 @@ public static string Unescape(string text, bool removeBackSlash = true)
if (entityNameLength > 0)
{
- var namedEntity = new StringSlice(text, entityNameStart, entityNameStart + entityNameLength - 1);
- var decoded = EntityHelper.DecodeEntity(namedEntity.ToString());
+ var decoded = EntityHelper.DecodeEntity(text.AsSpan(entityNameStart, entityNameLength));
if (decoded != null)
{
sb.Append(text, lastPos, searchPos - match - lastPos);
@@ -498,36 +490,18 @@ public static string Unescape(string text, bool removeBackSlash = true)
else if (numericEntity >= 0)
{
sb.Append(text, lastPos, searchPos - match - lastPos);
- if (numericEntity == 0)
- {
- sb.Append('\0'.EscapeInsecure());
- }
- else
- {
- var decoded = EntityHelper.DecodeEntity(numericEntity);
- if (decoded != null)
- {
- sb.Append(decoded);
- }
- else
- {
- sb.Append('\uFFFD');
- }
- }
-
+ EntityHelper.DecodeEntity(numericEntity, sb);
lastPos = searchPos;
}
}
}
}
- if (sb == null)
+ if (sb == null || lastPos == 0)
return text;
sb.Append(text, lastPos, text.Length - lastPos);
- var result = sb.ToString();
- sb.Length = 0;
- return result;
+ return sb.GetStringAndReset();
}
///
diff --git a/src/Markdig/Helpers/LineReader.cs b/src/Markdig/Helpers/LineReader.cs
index bc4db7f61..362eb9622 100644
--- a/src/Markdig/Helpers/LineReader.cs
+++ b/src/Markdig/Helpers/LineReader.cs
@@ -21,7 +21,10 @@ public struct LineReader
/// bufferSize cannot be <= 0
public LineReader(string text)
{
- _text = text ?? throw new ArgumentNullException(nameof(text));
+ if (text is null)
+ ThrowHelper.ArgumentNullException_text();
+
+ _text = text;
SourcePosition = 0;
}
diff --git a/src/Markdig/Helpers/LinkHelper.cs b/src/Markdig/Helpers/LinkHelper.cs
index 76190154e..7ad4ad9f0 100644
--- a/src/Markdig/Helpers/LinkHelper.cs
+++ b/src/Markdig/Helpers/LinkHelper.cs
@@ -110,7 +110,7 @@ public static string UrilizeAsGfm(string headingText)
return headingBuffer.GetStringAndReset();
}
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool IsReservedPunctuation(char c)
{
return c == '_' || c == '-' || c == '.';
@@ -652,14 +652,14 @@ public static bool TryParseUrl(ref T text, out string link, bool isAutoLink =
return isValid;
}
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool IsTrailingUrlStopCharacter(char c)
{
// Trailing punctuation (specifically, ?, !, ., ,, :, *, _, and ~) will not be considered part of the autolink, though they may be included in the interior of the link:
return c == '?' || c == '!' || c == '.' || c == ',' || c == ':' || c == '*' || c == '*' || c == '_' || c == '~';
}
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool IsEndOfUri(char c, bool isAutoLink)
{
return c == '\0' || c.IsSpaceOrTab() || c.IsControl() || (isAutoLink && c == '<'); // TODO: specs unclear. space is strict or relaxed? (includes tabs?)
diff --git a/src/Markdig/Helpers/MethodImplOptionPortable.cs b/src/Markdig/Helpers/MethodImplOptionPortable.cs
deleted file mode 100644
index ff65e0a91..000000000
--- a/src/Markdig/Helpers/MethodImplOptionPortable.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright (c) Alexandre Mutel. All rights reserved.
-// This file is licensed under the BSD-Clause 2 license.
-// See the license.txt file in the project root for more information.
-using System.Runtime.CompilerServices;
-
-namespace Markdig.Helpers
-{
- ///
- /// Internal helper to allow to declare a method using AggressiveInlining without being .NET 4.0+
- ///
- internal static class MethodImplOptionPortable
- {
- public const MethodImplOptions AggressiveInlining = (MethodImplOptions)256;
- }
-}
\ No newline at end of file
diff --git a/src/Markdig/Helpers/ObjectCache.cs b/src/Markdig/Helpers/ObjectCache.cs
index 5f7878f4c..998cb48d3 100644
--- a/src/Markdig/Helpers/ObjectCache.cs
+++ b/src/Markdig/Helpers/ObjectCache.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Alexandre Mutel. All rights reserved.
+// Copyright (c) Alexandre Mutel. All rights reserved.
// This file is licensed under the BSD-Clause 2 license.
// See the license.txt file in the project root for more information.
using System;
@@ -57,7 +57,7 @@ public T Get()
/// if instance is null
public void Release(T instance)
{
- if (instance == null) throw new ArgumentNullException(nameof(instance));
+ if (instance == null) ThrowHelper.ArgumentNullException(nameof(instance));
Reset(instance);
lock (builders)
{
diff --git a/src/Markdig/Helpers/OrderedList.cs b/src/Markdig/Helpers/OrderedList.cs
index 3e3663d70..4aa547b68 100644
--- a/src/Markdig/Helpers/OrderedList.cs
+++ b/src/Markdig/Helpers/OrderedList.cs
@@ -22,85 +22,85 @@ public OrderedList(IEnumerable collection) : base(collection)
{
}
- public bool InsertBefore(T element) where TElement : T
+ public bool InsertBefore(T item) where TItem : T
{
- if (element == null) throw new ArgumentNullException(nameof(element));
+ if (item == null) ThrowHelper.ArgumentNullException_item();
for (int i = 0; i < Count; i++)
{
- if (this[i] is TElement)
+ if (this[i] is TItem)
{
- Insert(i, element);
+ Insert(i, item);
return true;
}
}
return false;
}
- public TElement Find() where TElement : T
+ public TItem Find() where TItem : T
{
for (int i = 0; i < Count; i++)
{
- if (this[i] is TElement)
+ if (this[i] is TItem)
{
- return (TElement)this[i];
+ return (TItem)this[i];
}
}
return default;
}
- public bool TryFind(out TElement element) where TElement : T
+ public bool TryFind(out TItem item) where TItem : T
{
- element = Find();
- return element != null;
+ item = Find();
+ return item != null;
}
- public TElement FindExact() where TElement : T
+ public TItem FindExact() where TItem : T
{
for (int i = 0; i < Count; i++)
{
- if (this[i].GetType() == typeof(TElement))
+ if (this[i].GetType() == typeof(TItem))
{
- return (TElement)this[i];
+ return (TItem)this[i];
}
}
return default;
}
- public void AddIfNotAlready() where TElement : class, T, new()
+ public void AddIfNotAlready() where TItem : class, T, new()
{
- if (!Contains())
+ if (!Contains())
{
- Add(new TElement());
+ Add(new TItem());
}
}
- public void AddIfNotAlready(TElement telement) where TElement : T
+ public void AddIfNotAlready(TItem item) where TItem : T
{
- if (!Contains())
+ if (!Contains())
{
- Add(telement);
+ Add(item);
}
}
- public bool InsertAfter(T element) where TElement : T
+ public bool InsertAfter(T item) where TItem : T
{
- if (element == null) throw new ArgumentNullException(nameof(element));
+ if (item == null) ThrowHelper.ArgumentNullException_item();
for (int i = 0; i < Count; i++)
{
- if (this[i] is TElement)
+ if (this[i] is TItem)
{
- Insert(i + 1, element);
+ Insert(i + 1, item);
return true;
}
}
return false;
}
- public bool Contains() where TElement : T
+ public bool Contains() where TItem : T
{
for (int i = 0; i < Count; i++)
{
- if (this[i] is TElement)
+ if (this[i] is TItem)
{
return true;
}
@@ -109,16 +109,16 @@ public bool Contains() where TElement : T
}
///
- /// Replaces with .
+ /// Replaces with .
///
- /// Element type to find in the list
- /// Object to replace this element with
+ /// Item type to find in the list
+ /// Object to replace this item with
/// true if a replacement was made; otherwise false.
- public bool Replace(T replacement) where TElement : T
+ public bool Replace(T replacement) where TItem : T
{
for (var i = 0; i < Count; i++)
{
- if (this[i] is TElement)
+ if (this[i] is TItem)
{
RemoveAt(i);
Insert(i, replacement);
@@ -129,28 +129,28 @@ public bool Replace(T replacement) where TElement : T
}
///
- /// Replaces with or adds .
+ /// Replaces with or adds .
///
- /// Element type to find in the list
- /// Object to add/replace the found element with
+ /// Item type to find in the list
+ /// Object to add/replace the found item with
/// true if a replacement was made; otherwise false.
- public bool ReplaceOrAdd(T newElement) where TElement : T
+ public bool ReplaceOrAdd(T newItem) where TItem : T
{
- if (Replace(newElement))
+ if (Replace(newItem))
return true;
- Add(newElement);
+ Add(newItem);
return false;
}
///
- /// Removes the first occurrence of
+ /// Removes the first occurrence of
///
- public bool TryRemove() where TElement : T
+ public bool TryRemove() where TItem : T
{
for (int i = 0; i < Count; i++)
{
- if (this[i] is TElement)
+ if (this[i] is TItem)
{
RemoveAt(i);
return true;
diff --git a/src/Markdig/Helpers/StringLineGroup.cs b/src/Markdig/Helpers/StringLineGroup.cs
index 6752dc978..18a2486bc 100644
--- a/src/Markdig/Helpers/StringLineGroup.cs
+++ b/src/Markdig/Helpers/StringLineGroup.cs
@@ -26,7 +26,7 @@ private static readonly CustomArrayPool _pool
///
public StringLineGroup(int capacity, bool willRelease = false)
{
- if (capacity <= 0) throw new ArgumentOutOfRangeException(nameof(capacity));
+ if (capacity <= 0) ThrowHelper.ArgumentOutOfRangeException(nameof(capacity));
Lines = _pool.Rent(willRelease ? Math.Max(8, capacity) : capacity);
Count = 0;
}
@@ -38,7 +38,7 @@ public StringLineGroup(int capacity, bool willRelease = false)
///
public StringLineGroup(string text)
{
- if (text == null) throw new ArgumentNullException(nameof(text));
+ if (text == null) ThrowHelper.ArgumentNullException_text();
Lines = new StringLine[1];
Count = 0;
Add(new StringSlice(text));
@@ -82,7 +82,7 @@ public void RemoveAt(int index)
/// Adds the specified line to this instance.
///
/// The line.
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Add(ref StringLine line)
{
if (Count == Lines.Length) IncreaseCapacity();
@@ -93,7 +93,7 @@ public void Add(ref StringLine line)
/// Adds the specified slice to this instance.
///
/// The slice.
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Add(StringSlice slice)
{
if (Count == Lines.Length) IncreaseCapacity();
@@ -283,7 +283,7 @@ public char NextChar()
public readonly char PeekChar(int offset = 1)
{
- if (offset < 0) throw new ArgumentOutOfRangeException("Negative offset are not supported for StringLineGroup", nameof(offset));
+ if (offset < 0) ThrowHelper.ArgumentOutOfRangeException("Negative offset are not supported for StringLineGroup", nameof(offset));
if (Start + offset > End)
{
diff --git a/src/Markdig/Helpers/StringSlice.cs b/src/Markdig/Helpers/StringSlice.cs
index 28a96b1f5..1b07e7ea1 100644
--- a/src/Markdig/Helpers/StringSlice.cs
+++ b/src/Markdig/Helpers/StringSlice.cs
@@ -38,7 +38,10 @@ public StringSlice(string text)
///
public StringSlice(string text, int start, int end)
{
- Text = text ?? throw new ArgumentNullException(nameof(text));
+ if (text is null)
+ ThrowHelper.ArgumentNullException_text();
+
+ Text = text;
Start = start;
End = end;
}
@@ -51,12 +54,12 @@ public StringSlice(string text, int start, int end)
///
/// Gets or sets the start position within .
///
- public int Start { get; set; }
+ public int Start { readonly get; set; }
///
/// Gets or sets the end position (inclusive) within .
///
- public int End { get; set; }
+ public int End { readonly get; set; }
///
/// Gets the length.
@@ -80,7 +83,7 @@ public readonly char CurrentChar
///
public readonly bool IsEmpty
{
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
get => Start > End;
}
@@ -91,7 +94,7 @@ public readonly bool IsEmpty
/// A character in the slice at the specified index (not from but from the begining of the slice)
public readonly char this[int index]
{
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
get => Text[index];
}
@@ -102,7 +105,7 @@ public readonly char this[int index]
///
/// The next character. `\0` is end of the iteration.
///
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public char NextChar()
{
int start = Start;
@@ -121,7 +124,7 @@ public char NextChar()
/// inside the range and , returns `\0` if outside this range.
///
/// The character at offset, returns `\0` if none.
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly char PeekChar()
{
int index = Start + 1;
@@ -134,7 +137,7 @@ public readonly char PeekChar()
///
/// The offset.
/// The character at offset, returns `\0` if none.
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly char PeekChar(int offset)
{
var index = Start + offset;
@@ -145,7 +148,7 @@ public readonly char PeekChar(int offset)
/// Peeks a character at the specified offset from the current beginning of the string, without taking into account and
///
/// The character at offset, returns `\0` if none.
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly char PeekCharAbsolute(int index)
{
string text = Text;
@@ -158,7 +161,7 @@ public readonly char PeekCharAbsolute(int index)
///
/// The offset.
/// The character at offset, returns `\0` if none.
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly char PeekCharExtra(int offset)
{
var index = Start + offset;
@@ -275,13 +278,7 @@ public readonly int IndexOf(string text, int offset = 0, bool ignoreCase = false
if (length <= 0)
return -1;
-#if NETCORE
- var span = Text.AsSpan(offset, length);
- int index = ignoreCase ? span.IndexOf(text, StringComparison.OrdinalIgnoreCase) : span.IndexOf(text);
- return index == -1 ? index : index + offset;
-#else
return Text.IndexOf(text, offset, length, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal);
-#endif
}
///
@@ -296,12 +293,7 @@ public readonly int IndexOf(char c)
if (length <= 0)
return -1;
-#if NETCORE
- int index = Text.AsSpan(start, length).IndexOf(c);
- return index == -1 ? index : index + start;
-#else
return Text.IndexOf(c, start, length);
-#endif
}
///
@@ -312,16 +304,15 @@ public readonly int IndexOf(char c)
///
public bool TrimStart()
{
- // Strip leading spaces
- for (; Start <= End; Start++)
- {
- if (Start < Text.Length
- && !Text[Start].IsWhitespace())
- {
- break;
- }
- }
- return IsEmpty;
+ string text = Text;
+ int end = End;
+ int i = Start;
+
+ while (i <= end && (uint)i < (uint)text.Length && text[i].IsWhitespace())
+ i++;
+
+ Start = i;
+ return i > end;
}
///
@@ -330,16 +321,15 @@ public bool TrimStart()
/// The number of spaces trimmed.
public void TrimStart(out int spaceCount)
{
- spaceCount = 0;
- // Strip leading spaces
- for (; Start <= End; Start++)
- {
- if (!Text[Start].IsWhitespace())
- {
- break;
- }
- spaceCount++;
- }
+ string text = Text;
+ int end = End;
+ int i = Start;
+
+ while (i <= end && (uint)i < (uint)text.Length && text[i].IsWhitespace())
+ i++;
+
+ spaceCount = i - Start;
+ Start = i;
}
///
@@ -348,15 +338,15 @@ public void TrimStart(out int spaceCount)
///
public bool TrimEnd()
{
- for (; Start <= End; End--)
- {
- if (End < Text.Length
- && !Text[End].IsWhitespace())
- {
- break;
- }
- }
- return IsEmpty;
+ string text = Text;
+ int start = Start;
+ int i = End;
+
+ while (start <= i && (uint)i < (uint)text.Length && text[i].IsWhitespace())
+ i--;
+
+ End = i;
+ return start > i;
}
///
@@ -364,8 +354,18 @@ public bool TrimEnd()
///
public void Trim()
{
- TrimStart();
- TrimEnd();
+ string text = Text;
+ int start = Start;
+ int end = End;
+
+ while (start <= end && (uint)start < (uint)text.Length && text[start].IsWhitespace())
+ start++;
+
+ while (start <= end && (uint)end < (uint)text.Length && text[end].IsWhitespace())
+ end--;
+
+ Start = start;
+ End = end;
}
///
@@ -393,9 +393,12 @@ public readonly override string ToString()
/// true if this slice is empty or made only of whitespaces; false otherwise
public readonly bool IsEmptyOrWhitespace()
{
- for (int i = Start; i <= End; i++)
+ string text = Text;
+ int end = End;
+
+ for (int i = Start; i <= end && (uint)i < (uint)text.Length; i++)
{
- if (!Text[i].IsWhitespace())
+ if (!text[i].IsWhitespace())
{
return false;
}
diff --git a/src/Markdig/Helpers/ThrowHelper.cs b/src/Markdig/Helpers/ThrowHelper.cs
index d3b884abf..84e509c84 100644
--- a/src/Markdig/Helpers/ThrowHelper.cs
+++ b/src/Markdig/Helpers/ThrowHelper.cs
@@ -10,19 +10,39 @@ namespace Markdig.Helpers
[ExcludeFromCodeCoverage]
internal static class ThrowHelper
{
+ public static void ArgumentNullException(string paramName) => throw new ArgumentNullException(paramName);
+ public static void ArgumentNullException_item() => throw new ArgumentNullException("item");
+ public static void ArgumentNullException_text() => throw new ArgumentNullException("text");
+ public static void ArgumentNullException_label() => throw new ArgumentNullException("label");
+ public static void ArgumentNullException_key() => throw new ArgumentNullException("key");
+ public static void ArgumentNullException_name() => throw new ArgumentNullException("name");
+ public static void ArgumentNullException_markdown() => throw new ArgumentNullException("markdown");
+ public static void ArgumentNullException_writer() => throw new ArgumentNullException("writer");
+ public static void ArgumentNullException_leafBlock() => throw new ArgumentNullException("leafBlock");
+ public static void ArgumentNullException_markdownObject() => throw new ArgumentNullException("markdownObject");
+
+ public static void ArgumentException(string message) => throw new ArgumentException(message);
+ public static void ArgumentException(string message, string paramName) => throw new ArgumentException(message, paramName);
+
+ public static void ArgumentOutOfRangeException(string paramName) => throw new ArgumentOutOfRangeException(paramName);
+ public static void ArgumentOutOfRangeException(string message, string paramName) => throw new ArgumentOutOfRangeException(message, paramName);
+ public static void ArgumentOutOfRangeException_index() => throw new ArgumentOutOfRangeException("index");
+
+ public static void InvalidOperationException(string message) => throw new InvalidOperationException(message);
+
public static void ThrowArgumentNullException(ExceptionArgument argument)
{
- throw new ArgumentNullException(GetArgumentName(argument));
+ throw new ArgumentNullException(argument.ToString());
}
public static void ThrowArgumentException(ExceptionArgument argument, ExceptionReason reason)
{
- throw new ArgumentException(GetArgumentName(argument), GetExceptionReason(reason));
+ throw new ArgumentException(argument.ToString(), GetExceptionReason(reason));
}
public static void ThrowArgumentOutOfRangeException(ExceptionArgument argument, ExceptionReason reason)
{
- throw new ArgumentOutOfRangeException(GetArgumentName(argument), GetExceptionReason(reason));
+ throw new ArgumentOutOfRangeException(argument.ToString(), GetExceptionReason(reason));
}
public static void ThrowIndexOutOfRangeException()
@@ -30,25 +50,6 @@ public static void ThrowIndexOutOfRangeException()
throw new IndexOutOfRangeException();
}
- private static string GetArgumentName(ExceptionArgument argument)
- {
- switch (argument)
- {
- case ExceptionArgument.key:
- case ExceptionArgument.input:
- case ExceptionArgument.value:
- case ExceptionArgument.length:
- case ExceptionArgument.text:
- return argument.ToString();
-
- case ExceptionArgument.offsetLength:
- return "offset and length";
-
- default:
- Debug.Assert(false, "The enum value is not defined, please check the ExceptionArgument Enum.");
- return "";
- }
- }
private static string GetExceptionReason(ExceptionReason reason)
{
switch (reason)
diff --git a/src/Markdig/Markdig.targets b/src/Markdig/Markdig.targets
index 4b8472f92..d77f45a11 100644
--- a/src/Markdig/Markdig.targets
+++ b/src/Markdig/Markdig.targets
@@ -6,7 +6,7 @@
en-US
0.18.3
Alexandre Mutel
- net35;net40;netstandard2.0;netcoreapp2.1
+ netstandard2.0;netstandard2.1;netcoreapp2.1;netcoreapp3.1
Markdown CommonMark md html md2html
https://github.com/lunet-io/markdig/blob/master/changelog.md
BSD-2-Clause
@@ -20,14 +20,21 @@
snupkg
+
+
+
+
+
+ $(DefineConstants);NETCORE
+
+
$(DefineConstants);NETCORE
-
-
-
-
+
+ $(DefineConstants);NETCORE
+
$(NoWarn);CS1591
@@ -37,4 +44,5 @@
+
diff --git a/src/Markdig/Markdown.cs b/src/Markdig/Markdown.cs
index e6f2660fd..71fa084a4 100644
--- a/src/Markdig/Markdown.cs
+++ b/src/Markdig/Markdown.cs
@@ -5,6 +5,7 @@
using System.IO;
using System.Reflection;
using Markdig.Extensions.SelfPipeline;
+using Markdig.Helpers;
using Markdig.Parsers;
using Markdig.Renderers;
using Markdig.Renderers.Normalize;
@@ -68,8 +69,8 @@ public static MarkdownDocument Normalize(string markdown, TextWriter writer, Nor
/// if markdown variable is null
public static string ToHtml(string markdown, MarkdownPipeline pipeline = null)
{
- if (markdown == null) throw new ArgumentNullException(nameof(markdown));
- pipeline = pipeline ?? new MarkdownPipelineBuilder().Build();
+ if (markdown == null) ThrowHelper.ArgumentNullException_markdown();
+ pipeline ??= new MarkdownPipelineBuilder().Build();
pipeline = CheckForSelfPipeline(pipeline, markdown);
var renderer = pipeline.GetCacheableHtmlRenderer();
@@ -94,9 +95,9 @@ public static string ToHtml(string markdown, MarkdownPipeline pipeline = null)
/// if reader or writer variable are null
public static MarkdownDocument ToHtml(string markdown, TextWriter writer, MarkdownPipeline pipeline = null, MarkdownParserContext context = null)
{
- if (markdown == null) throw new ArgumentNullException(nameof(markdown));
- if (writer == null) throw new ArgumentNullException(nameof(writer));
- pipeline = pipeline ?? new MarkdownPipelineBuilder().Build();
+ if (markdown == null) ThrowHelper.ArgumentNullException_markdown();
+ if (writer == null) ThrowHelper.ArgumentNullException_writer();
+ pipeline ??= new MarkdownPipelineBuilder().Build();
pipeline = CheckForSelfPipeline(pipeline, markdown);
// We override the renderer with our own writer
@@ -120,9 +121,9 @@ public static MarkdownDocument ToHtml(string markdown, TextWriter writer, Markdo
/// if markdown or writer variable are null
public static object Convert(string markdown, IMarkdownRenderer renderer, MarkdownPipeline pipeline = null, MarkdownParserContext context = null)
{
- if (markdown == null) throw new ArgumentNullException(nameof(markdown));
- if (renderer == null) throw new ArgumentNullException(nameof(renderer));
- pipeline = pipeline ?? new MarkdownPipelineBuilder().Build();
+ if (markdown == null) ThrowHelper.ArgumentNullException_markdown();
+ if (renderer == null) ThrowHelper.ArgumentNullException(nameof(renderer));
+ pipeline ??= new MarkdownPipelineBuilder().Build();
pipeline = CheckForSelfPipeline(pipeline, markdown);
var document = Parse(markdown, pipeline, context);
@@ -138,7 +139,7 @@ public static object Convert(string markdown, IMarkdownRenderer renderer, Markdo
/// if markdown variable is null
public static MarkdownDocument Parse(string markdown)
{
- if (markdown == null) throw new ArgumentNullException(nameof(markdown));
+ if (markdown == null) ThrowHelper.ArgumentNullException_markdown();
return Parse(markdown, null);
}
@@ -152,8 +153,8 @@ public static MarkdownDocument Parse(string markdown)
/// if markdown variable is null
public static MarkdownDocument Parse(string markdown, MarkdownPipeline pipeline, MarkdownParserContext context = null)
{
- if (markdown == null) throw new ArgumentNullException(nameof(markdown));
- pipeline = pipeline ?? new MarkdownPipelineBuilder().Build();
+ if (markdown == null) ThrowHelper.ArgumentNullException_markdown();
+ pipeline ??= new MarkdownPipelineBuilder().Build();
pipeline = CheckForSelfPipeline(pipeline, markdown);
return MarkdownParser.Parse(markdown, pipeline, context);
@@ -180,9 +181,9 @@ private static MarkdownPipeline CheckForSelfPipeline(MarkdownPipeline pipeline,
/// if reader or writer variable are null
public static MarkdownDocument ToPlainText(string markdown, TextWriter writer, MarkdownPipeline pipeline = null, MarkdownParserContext context = null)
{
- if (markdown == null) throw new ArgumentNullException(nameof(markdown));
- if (writer == null) throw new ArgumentNullException(nameof(writer));
- pipeline = pipeline ?? new MarkdownPipelineBuilder().Build();
+ if (markdown == null) ThrowHelper.ArgumentNullException_markdown();
+ if (writer == null) ThrowHelper.ArgumentNullException_writer();
+ pipeline ??= new MarkdownPipelineBuilder().Build();
pipeline = CheckForSelfPipeline(pipeline, markdown);
// We override the renderer with our own writer
@@ -211,7 +212,7 @@ public static MarkdownDocument ToPlainText(string markdown, TextWriter writer, M
/// if markdown variable is null
public static string ToPlainText(string markdown, MarkdownPipeline pipeline = null, MarkdownParserContext context = null)
{
- if (markdown == null) throw new ArgumentNullException(nameof(markdown));
+ if (markdown == null) ThrowHelper.ArgumentNullException_markdown();
var writer = new StringWriter();
ToPlainText(markdown, writer, pipeline, context);
return writer.ToString();
diff --git a/src/Markdig/MarkdownExtensions.cs b/src/Markdig/MarkdownExtensions.cs
index f038bdf02..831008fe0 100644
--- a/src/Markdig/MarkdownExtensions.cs
+++ b/src/Markdig/MarkdownExtensions.cs
@@ -34,7 +34,8 @@
using Markdig.Parsers;
using Markdig.Parsers.Inlines;
using Markdig.Extensions.Globalization;
-
+using Markdig.Helpers;
+
namespace Markdig
{
///
@@ -138,7 +139,7 @@ public static MarkdownPipelineBuilder UseSelfPipeline(this MarkdownPipelineBuild
{
if (pipeline.Extensions.Count != 0)
{
- throw new InvalidOperationException("The SelfPipeline extension cannot be used with other extensions");
+ ThrowHelper.InvalidOperationException("The SelfPipeline extension cannot be used with other extensions");
}
pipeline.Extensions.Add(new SelfPipelineExtension(defaultTag, defaultExtensions));
diff --git a/src/Markdig/MarkdownParserContext.cs b/src/Markdig/MarkdownParserContext.cs
index aa326ee17..c8d50d842 100644
--- a/src/Markdig/MarkdownParserContext.cs
+++ b/src/Markdig/MarkdownParserContext.cs
@@ -5,7 +5,7 @@ namespace Markdig
///
/// Provides a context that can be used as part of parsing Markdown documents.
///
- public sealed class MarkdownParserContext
+ public class MarkdownParserContext
{
///
/// Gets or sets the context property collection.
diff --git a/src/Markdig/MarkdownPipeline.cs b/src/Markdig/MarkdownPipeline.cs
index 757d0ff4d..2ef66bc6f 100644
--- a/src/Markdig/MarkdownPipeline.cs
+++ b/src/Markdig/MarkdownPipeline.cs
@@ -22,8 +22,8 @@ public class MarkdownPipeline
///
internal MarkdownPipeline(OrderedList extensions, BlockParserList blockParsers, InlineParserList inlineParsers, StringBuilderCache cache, TextWriter debugLog, ProcessDocumentDelegate documentProcessed)
{
- if (blockParsers == null) throw new ArgumentNullException(nameof(blockParsers));
- if (inlineParsers == null) throw new ArgumentNullException(nameof(inlineParsers));
+ if (blockParsers == null) ThrowHelper.ArgumentNullException(nameof(blockParsers));
+ if (inlineParsers == null) ThrowHelper.ArgumentNullException(nameof(inlineParsers));
// Add all default parsers
Extensions = extensions;
BlockParsers = blockParsers;
@@ -57,7 +57,7 @@ internal MarkdownPipeline(OrderedList extensions, BlockParse
/// The markdown renderer to setup
public void Setup(IMarkdownRenderer renderer)
{
- if (renderer == null) throw new ArgumentNullException(nameof(renderer));
+ if (renderer == null) ThrowHelper.ArgumentNullException(nameof(renderer));
foreach (var extension in Extensions)
{
extension.Setup(this, renderer);
diff --git a/src/Markdig/MarkdownPipelineBuilder.cs b/src/Markdig/MarkdownPipelineBuilder.cs
index 8bfb596be..5574342b5 100644
--- a/src/Markdig/MarkdownPipelineBuilder.cs
+++ b/src/Markdig/MarkdownPipelineBuilder.cs
@@ -111,7 +111,7 @@ public MarkdownPipeline Build()
{
if (extension == null)
{
- throw new InvalidOperationException("An extension cannot be null");
+ ThrowHelper.InvalidOperationException("An extension cannot be null");
}
extension.Setup(this);
}
diff --git a/src/Markdig/Parsers/BlockParser.cs b/src/Markdig/Parsers/BlockParser.cs
index 010a28824..9aba31523 100644
--- a/src/Markdig/Parsers/BlockParser.cs
+++ b/src/Markdig/Parsers/BlockParser.cs
@@ -25,9 +25,9 @@ public bool HasOpeningCharacter(char c)
{
if (OpeningCharacters != null)
{
- for (int i = 0; i < OpeningCharacters.Length; i++)
+ foreach (char openingChar in OpeningCharacters)
{
- if (OpeningCharacters[i] == c)
+ if (openingChar == c)
{
return true;
}
diff --git a/src/Markdig/Parsers/BlockProcessor.cs b/src/Markdig/Parsers/BlockProcessor.cs
index 02e74713b..a22af1dde 100644
--- a/src/Markdig/Parsers/BlockProcessor.cs
+++ b/src/Markdig/Parsers/BlockProcessor.cs
@@ -43,9 +43,9 @@ private BlockProcessor(BlockProcessor root)
///
public BlockProcessor(StringBuilderCache stringBuilders, MarkdownDocument document, BlockParserList parsers, MarkdownParserContext context)
{
- if (stringBuilders == null) throw new ArgumentNullException(nameof(stringBuilders));
- if (document == null) throw new ArgumentNullException(nameof(document));
- if (parsers == null) throw new ArgumentNullException(nameof(parsers));
+ if (stringBuilders == null) ThrowHelper.ArgumentNullException(nameof(stringBuilders));
+ if (document == null) ThrowHelper.ArgumentNullException(nameof(document));
+ if (parsers == null) ThrowHelper.ArgumentNullException(nameof(parsers));
parserStateCache = new BlockParserStateCache(this);
StringBuilders = stringBuilders;
Document = document;
@@ -400,8 +400,8 @@ public void GoToCodeIndent(int columnOffset = 0)
/// The block must be opened
public void Open(Block block)
{
- if (block == null) throw new ArgumentNullException(nameof(block));
- if (!block.IsOpen) throw new ArgumentException("The block must be opened", nameof(block));
+ if (block == null) ThrowHelper.ArgumentNullException(nameof(block));
+ if (!block.IsOpen) ThrowHelper.ArgumentException("The block must be opened", nameof(block));
OpenedBlocks.Add(block);
}
@@ -477,7 +477,7 @@ public void ReleaseChild()
{
if (this == root)
{
- throw new InvalidOperationException("Cannot release the root parser state");
+ ThrowHelper.InvalidOperationException("Cannot release the root parser state");
}
parserStateCache.Release(this);
}
@@ -633,7 +633,7 @@ private void TryContinueBlocks()
// If a parser is adding a block, it must be the last of the list
if ((i + 1) < OpenedBlocks.Count && NewBlocks.Count > 0)
{
- throw new InvalidOperationException("A pending parser cannot add a new block when it is not the last pending block");
+ ThrowHelper.InvalidOperationException("A pending parser cannot add a new block when it is not the last pending block");
}
// If we have a leaf block
@@ -680,7 +680,7 @@ private void TryOpenBlocks()
// Security check so that the parser can't go into a crazy infinite loop if one extension is messing
if (previousStart == Start)
{
- throw new InvalidOperationException($"The parser is in an invalid infinite loop while trying to parse blocks at line [{LineIndex}] with line [{Line}]");
+ ThrowHelper.InvalidOperationException($"The parser is in an invalid infinite loop while trying to parse blocks at line [{LineIndex}] with line [{Line}]");
}
previousStart = Start;
@@ -810,7 +810,7 @@ private void ProcessNewBlocks(BlockState result, bool allowClosing)
if (block.Parser == null)
{
- throw new InvalidOperationException($"The new block [{block.GetType()}] must have a valid Parser property");
+ ThrowHelper.InvalidOperationException($"The new block [{block.GetType()}] must have a valid Parser property");
}
block.Line = LineIndex;
@@ -826,7 +826,7 @@ private void ProcessNewBlocks(BlockState result, bool allowClosing)
if (newBlocks.Count > 0)
{
- throw new InvalidOperationException(
+ ThrowHelper.InvalidOperationException(
"The NewBlocks is not empty. This is happening if a LeafBlock is not the last to be pushed");
}
}
diff --git a/src/Markdig/Parsers/BlockStateExtensions.cs b/src/Markdig/Parsers/BlockStateExtensions.cs
index ee0e796ea..4e99d7829 100644
--- a/src/Markdig/Parsers/BlockStateExtensions.cs
+++ b/src/Markdig/Parsers/BlockStateExtensions.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Alexandre Mutel. All rights reserved.
+// Copyright (c) Alexandre Mutel. All rights reserved.
// This file is licensed under the BSD-Clause 2 license.
// See the license.txt file in the project root for more information.
using System.Runtime.CompilerServices;
@@ -16,7 +16,7 @@ public static class BlockStateExtensions
///
/// State of the block.
/// true if the block state is in discard state
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsDiscard(this BlockState blockState)
{
return blockState == BlockState.ContinueDiscard || blockState == BlockState.BreakDiscard;
@@ -27,7 +27,7 @@ public static bool IsDiscard(this BlockState blockState)
///
/// State of the block.
/// true if the block state is in continue state
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsContinue(this BlockState blockState)
{
return blockState == BlockState.Continue || blockState == BlockState.ContinueDiscard;
@@ -38,7 +38,7 @@ public static bool IsContinue(this BlockState blockState)
///
/// State of the block.
/// true if the block state is in break state
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsBreak(this BlockState blockState)
{
return blockState == BlockState.Break || blockState == BlockState.BreakDiscard;
diff --git a/src/Markdig/Parsers/InlineProcessor.cs b/src/Markdig/Parsers/InlineProcessor.cs
index 0eed5035c..ac3405bb1 100644
--- a/src/Markdig/Parsers/InlineProcessor.cs
+++ b/src/Markdig/Parsers/InlineProcessor.cs
@@ -38,9 +38,9 @@ public class InlineProcessor
///
public InlineProcessor(StringBuilderCache stringBuilders, MarkdownDocument document, InlineParserList parsers, bool preciseSourcelocation, MarkdownParserContext context)
{
- if (stringBuilders == null) throw new ArgumentNullException(nameof(stringBuilders));
- if (document == null) throw new ArgumentNullException(nameof(document));
- if (parsers == null) throw new ArgumentNullException(nameof(parsers));
+ if (stringBuilders == null) ThrowHelper.ArgumentNullException(nameof(stringBuilders));
+ if (document == null) ThrowHelper.ArgumentNullException(nameof(document));
+ if (parsers == null) ThrowHelper.ArgumentNullException(nameof(parsers));
StringBuilders = stringBuilders;
Document = document;
Parsers = parsers;
@@ -176,7 +176,7 @@ public int GetSourcePosition(int sliceOffset, out int lineIndex, out int column)
/// The leaf block.
public void ProcessInlineLeaf(LeafBlock leafBlock)
{
- if (leafBlock == null) throw new ArgumentNullException(nameof(leafBlock));
+ if (leafBlock == null) ThrowHelper.ArgumentNullException_leafBlock();
// clear parser states
Array.Clear(ParserStates, 0, ParserStates.Length);
@@ -201,7 +201,7 @@ public void ProcessInlineLeaf(LeafBlock leafBlock)
// Security check so that the parser can't go into a crazy infinite loop if one extension is messing
if (previousStart == text.Start)
{
- throw new InvalidOperationException($"The parser is in an invalid infinite loop while trying to parse inlines for block [{leafBlock.GetType().Name}] at position ({leafBlock.ToPositionText()}");
+ ThrowHelper.InvalidOperationException($"The parser is in an invalid infinite loop while trying to parse inlines for block [{leafBlock.GetType().Name}] at position ({leafBlock.ToPositionText()}");
}
previousStart = text.Start;
diff --git a/src/Markdig/Parsers/Inlines/EmphasisDescriptor.cs b/src/Markdig/Parsers/Inlines/EmphasisDescriptor.cs
index 3b2f6dd2b..9cd4011f6 100644
--- a/src/Markdig/Parsers/Inlines/EmphasisDescriptor.cs
+++ b/src/Markdig/Parsers/Inlines/EmphasisDescriptor.cs
@@ -2,6 +2,7 @@
// This file is licensed under the BSD-Clause 2 license.
// See the license.txt file in the project root for more information.
+using Markdig.Helpers;
using System;
namespace Markdig.Parsers.Inlines
@@ -20,9 +21,9 @@ public class EmphasisDescriptor
/// if set to true the emphasis can be used inside a word.
public EmphasisDescriptor(char character, int minimumCount, int maximumCount, bool enableWithinWord)
{
- if (minimumCount < 1) throw new ArgumentOutOfRangeException(nameof(minimumCount), "minimumCount must be >= 1");
- if (maximumCount < 1) throw new ArgumentOutOfRangeException(nameof(maximumCount), "maximumCount must be >= 1");
- if (minimumCount > maximumCount) throw new ArgumentOutOfRangeException(nameof(minimumCount), "minimumCount must be <= maximumCount");
+ if (minimumCount < 1) ThrowHelper.ArgumentOutOfRangeException(nameof(minimumCount), "minimumCount must be >= 1");
+ if (maximumCount < 1) ThrowHelper.ArgumentOutOfRangeException(nameof(maximumCount), "maximumCount must be >= 1");
+ if (minimumCount > maximumCount) ThrowHelper.ArgumentOutOfRangeException(nameof(minimumCount), "minimumCount must be <= maximumCount");
Character = character;
MinimumCount = minimumCount;
diff --git a/src/Markdig/Parsers/Inlines/EmphasisInlineParser.cs b/src/Markdig/Parsers/Inlines/EmphasisInlineParser.cs
index aef22033a..98a2c1e0f 100644
--- a/src/Markdig/Parsers/Inlines/EmphasisInlineParser.cs
+++ b/src/Markdig/Parsers/Inlines/EmphasisInlineParser.cs
@@ -77,7 +77,7 @@ public override void Initialize()
var emphasis = EmphasisDescriptors[i];
if (Array.IndexOf(OpeningCharacters, emphasis.Character) >= 0)
{
- throw new InvalidOperationException(
+ ThrowHelper.InvalidOperationException(
$"The character `{emphasis.Character}` is already used by another emphasis descriptor");
}
diff --git a/src/Markdig/Parsers/Inlines/HtmlEntityParser.cs b/src/Markdig/Parsers/Inlines/HtmlEntityParser.cs
index c1fe9c763..3b423664c 100644
--- a/src/Markdig/Parsers/Inlines/HtmlEntityParser.cs
+++ b/src/Markdig/Parsers/Inlines/HtmlEntityParser.cs
@@ -2,7 +2,7 @@
// This file is licensed under the BSD-Clause 2 license.
// See the license.txt file in the project root for more information.
-using System.Text;
+using System;
using Markdig.Helpers;
using Markdig.Syntax;
using Markdig.Syntax.Inlines;
@@ -27,10 +27,7 @@ public HtmlEntityParser()
public static bool TryParse(ref StringSlice slice, out string literal, out int match)
{
literal = null;
- int entityNameStart;
- int entityNameLength;
- int entityValue;
- match = HtmlHelper.ScanEntity(slice, out entityValue, out entityNameStart, out entityNameLength);
+ match = HtmlHelper.ScanEntity(slice, out int entityValue, out int entityNameStart, out int entityNameLength);
if (match == 0)
{
return false;
@@ -38,11 +35,11 @@ public static bool TryParse(ref StringSlice slice, out string literal, out int m
if (entityNameLength > 0)
{
- literal = EntityHelper.DecodeEntity(new StringSlice(slice.Text, entityNameStart, entityNameStart + entityNameLength - 1).ToString());
+ literal = EntityHelper.DecodeEntity(slice.Text.AsSpan(entityNameStart, entityNameLength));
}
else if (entityValue >= 0)
{
- literal = (entityValue == 0 ? null : EntityHelper.DecodeEntity(entityValue)) ?? CharHelper.ZeroSafeString;
+ literal = EntityHelper.DecodeEntity(entityValue);
}
return literal != null;
}
diff --git a/src/Markdig/Parsers/Inlines/LinkInlineParser.cs b/src/Markdig/Parsers/Inlines/LinkInlineParser.cs
index fdcae31d0..e4dc405cb 100644
--- a/src/Markdig/Parsers/Inlines/LinkInlineParser.cs
+++ b/src/Markdig/Parsers/Inlines/LinkInlineParser.cs
@@ -300,19 +300,19 @@ private bool TryProcessLinkOrImage(InlineProcessor inlineState, ref StringSlice
private void MarkParentAsInactive(Inline inline)
{
- if (inline == null)
+ while (inline != null)
{
- return;
- }
-
- foreach (var parent in inline.FindParentOfType())
- {
- if (parent.IsImage)
+ if (inline is LinkDelimiterInline linkInline)
{
- break;
+ if (linkInline.IsImage)
+ {
+ break;
+ }
+
+ linkInline.IsActive = false;
}
- parent.IsActive = false;
+ inline = inline.Parent;
}
}
}
diff --git a/src/Markdig/Parsers/ListBlockParser.cs b/src/Markdig/Parsers/ListBlockParser.cs
index 240eb5433..61ebf84e9 100644
--- a/src/Markdig/Parsers/ListBlockParser.cs
+++ b/src/Markdig/Parsers/ListBlockParser.cs
@@ -41,14 +41,14 @@ public override void Initialize()
{
if (itemParser.OpeningCharacters == null)
{
- throw new InvalidOperationException($"The list item parser of type [{itemParser.GetType()}] cannot have OpeningCharacters to null. It must define a list of valid opening characters");
+ ThrowHelper.InvalidOperationException($"The list item parser of type [{itemParser.GetType()}] cannot have OpeningCharacters to null. It must define a list of valid opening characters");
}
foreach (var openingCharacter in itemParser.OpeningCharacters)
{
if (tempMap.ContainsKey(openingCharacter))
{
- throw new InvalidOperationException(
+ ThrowHelper.InvalidOperationException(
$"A list item parser with the same opening character `{openingCharacter}` is already registered");
}
tempMap.Add(openingCharacter, itemParser);
diff --git a/src/Markdig/Parsers/MarkdownParser.cs b/src/Markdig/Parsers/MarkdownParser.cs
index 6bffeb238..011e98d92 100644
--- a/src/Markdig/Parsers/MarkdownParser.cs
+++ b/src/Markdig/Parsers/MarkdownParser.cs
@@ -42,8 +42,8 @@ public sealed class MarkdownParser
///
private MarkdownParser(string text, MarkdownPipeline pipeline, MarkdownParserContext context)
{
- if (text == null) throw new ArgumentNullException(nameof(text));
- if (pipeline == null) throw new ArgumentNullException(nameof(pipeline));
+ if (text == null) ThrowHelper.ArgumentNullException_text();
+ if (pipeline == null) ThrowHelper.ArgumentNullException(nameof(pipeline));
roughLineCountEstimate = text.Length / 40;
text = FixupZero(text);
@@ -77,8 +77,8 @@ private MarkdownParser(string text, MarkdownPipeline pipeline, MarkdownParserCon
/// if reader variable is null
public static MarkdownDocument Parse(string text, MarkdownPipeline pipeline = null, MarkdownParserContext context = null)
{
- if (text == null) throw new ArgumentNullException(nameof(text));
- pipeline = pipeline ?? new MarkdownPipelineBuilder().Build();
+ if (text == null) ThrowHelper.ArgumentNullException_text();
+ pipeline ??= new MarkdownPipelineBuilder().Build();
// Perform the parsing
var markdownParser = new MarkdownParser(text, pipeline, context);
@@ -131,7 +131,7 @@ private void ProcessBlocks()
/// The text to secure.
private string FixupZero(string text)
{
- return text.Replace('\0', CharHelper.ZeroSafeChar);
+ return text.Replace('\0', CharHelper.ReplacementChar);
}
private sealed class ContainerItemCache : DefaultObjectCache
diff --git a/src/Markdig/Parsers/OrderedListItemParser.cs b/src/Markdig/Parsers/OrderedListItemParser.cs
index 20c57d1a8..cca05de6d 100644
--- a/src/Markdig/Parsers/OrderedListItemParser.cs
+++ b/src/Markdig/Parsers/OrderedListItemParser.cs
@@ -33,9 +33,9 @@ protected bool TryParseDelimiter(BlockProcessor state, out char orderedDelimiter
{
// Check if we have an ordered delimiter
orderedDelimiter = state.CurrentChar;
- for (int i = 0; i < OrderedDelimiters.Length; i++)
+ foreach (char delimiter in OrderedDelimiters)
{
- if (OrderedDelimiters[i] == orderedDelimiter)
+ if (delimiter == orderedDelimiter)
{
state.NextChar();
return true;
diff --git a/src/Markdig/Parsers/ParserList.cs b/src/Markdig/Parsers/ParserList.cs
index fcbbfa0fa..e63b5f392 100644
--- a/src/Markdig/Parsers/ParserList.cs
+++ b/src/Markdig/Parsers/ParserList.cs
@@ -29,7 +29,7 @@ protected ParserList(IEnumerable parsersArg) : base(parsersArg)
var parser = this[i];
if (parser == null)
{
- throw new InvalidOperationException("Unexpected null parser found");
+ ThrowHelper.InvalidOperationException("Unexpected null parser found");
}
parser.Initialize();
@@ -100,8 +100,8 @@ protected ParserList(IEnumerable parsersArg) : base(parsersArg)
///
/// The opening character.
/// A list of parsers valid for the specified opening character or null if no parsers registered.
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
- public T[] GetParsersForOpeningCharacter(char openingChar)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public T[] GetParsersForOpeningCharacter(uint openingChar)
{
return charMap[openingChar];
}
@@ -113,7 +113,7 @@ public T[] GetParsersForOpeningCharacter(char openingChar)
/// The start.
/// The end.
/// Index position within the string of the first opening character found in the specified text; if not found, returns -1
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public int IndexOfOpeningCharacter(string text, int start, int end)
{
return charMap.IndexOfOpeningCharacter(text, start, end);
diff --git a/src/Markdig/Renderers/Html/HtmlAttributes.cs b/src/Markdig/Renderers/Html/HtmlAttributes.cs
index c9765d0f8..9613a60d7 100644
--- a/src/Markdig/Renderers/Html/HtmlAttributes.cs
+++ b/src/Markdig/Renderers/Html/HtmlAttributes.cs
@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Globalization;
+using Markdig.Helpers;
using Markdig.Syntax;
namespace Markdig.Renderers.Html
@@ -41,7 +42,7 @@ public HtmlAttributes()
/// The css class name.
public void AddClass(string name)
{
- if (name == null) throw new ArgumentNullException(nameof(name));
+ if (name == null) ThrowHelper.ArgumentNullException_name();
if (Classes == null)
{
Classes = new List(2);
@@ -61,7 +62,7 @@ public void AddClass(string name)
/// The value.
public void AddProperty(string name, string value)
{
- if (name == null) throw new ArgumentNullException(nameof(name));
+ if (name == null) ThrowHelper.ArgumentNullException_name();
if (Properties == null)
{
Properties = new List>(2); // Use half list compare to default capacity (4), as we don't expect lots of classes
@@ -76,7 +77,7 @@ public void AddProperty(string name, string value)
/// The value.
public void AddPropertyIfNotExist(string name, object value)
{
- if (name == null) throw new ArgumentNullException(nameof(name));
+ if (name == null) ThrowHelper.ArgumentNullException_name();
if (Properties == null)
{
Properties = new List>(4);
@@ -104,7 +105,7 @@ public void AddPropertyIfNotExist(string name, object value)
///
public void CopyTo(HtmlAttributes htmlAttributes, bool mergeIdAndProperties = false, bool shared = true)
{
- if (htmlAttributes == null) throw new ArgumentNullException(nameof(htmlAttributes));
+ if (htmlAttributes == null) ThrowHelper.ArgumentNullException(nameof(htmlAttributes));
// Add html htmlAttributes to the object
if (!mergeIdAndProperties || Id != null)
{
diff --git a/src/Markdig/Renderers/HtmlRenderer.cs b/src/Markdig/Renderers/HtmlRenderer.cs
index 22f1ae6e6..befe55013 100644
--- a/src/Markdig/Renderers/HtmlRenderer.cs
+++ b/src/Markdig/Renderers/HtmlRenderer.cs
@@ -91,7 +91,7 @@ public HtmlRenderer(TextWriter writer) : base(writer)
///
/// The content.
/// This instance
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public HtmlRenderer WriteEscape(string content)
{
if (string.IsNullOrEmpty(content))
@@ -107,7 +107,7 @@ public HtmlRenderer WriteEscape(string content)
/// The slice.
/// Only escape < and &
/// This instance
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public HtmlRenderer WriteEscape(ref StringSlice slice, bool softEscape = false)
{
if (slice.Start > slice.End)
@@ -123,7 +123,7 @@ public HtmlRenderer WriteEscape(ref StringSlice slice, bool softEscape = false)
/// The slice.
/// Only escape < and &
/// This instance
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public HtmlRenderer WriteEscape(StringSlice slice, bool softEscape = false)
{
return WriteEscape(ref slice, softEscape);
@@ -318,12 +318,12 @@ public HtmlRenderer WriteEscapeUrl(string content)
///
/// Writes the attached on the specified .
///
- /// The object.
+ /// The object.
///
- public HtmlRenderer WriteAttributes(MarkdownObject obj)
+ public HtmlRenderer WriteAttributes(MarkdownObject markdownObject)
{
- if (obj == null) throw new ArgumentNullException(nameof(obj));
- return WriteAttributes(obj.TryGetAttributes());
+ if (markdownObject == null) ThrowHelper.ArgumentNullException_markdownObject();
+ return WriteAttributes(markdownObject.TryGetAttributes());
}
///
@@ -383,7 +383,7 @@ public HtmlRenderer WriteAttributes(HtmlAttributes attributes, FuncThis instance
public HtmlRenderer WriteLeafRawLines(LeafBlock leafBlock, bool writeEndOfLines, bool escape, bool softEscape = false)
{
- if (leafBlock == null) throw new ArgumentNullException(nameof(leafBlock));
+ if (leafBlock == null) ThrowHelper.ArgumentNullException_leafBlock();
if (leafBlock.Lines.Lines != null)
{
var lines = leafBlock.Lines;
diff --git a/src/Markdig/Renderers/Normalize/NormalizeRenderer.cs b/src/Markdig/Renderers/Normalize/NormalizeRenderer.cs
index dcb364362..d8e460b00 100644
--- a/src/Markdig/Renderers/Normalize/NormalizeRenderer.cs
+++ b/src/Markdig/Renderers/Normalize/NormalizeRenderer.cs
@@ -6,6 +6,7 @@
using System.IO;
using Markdig.Syntax;
using Markdig.Renderers.Normalize.Inlines;
+using Markdig.Helpers;
namespace Markdig.Renderers.Normalize
{
@@ -130,7 +131,7 @@ public void FinishBlock(bool emptyLine)
/// This instance
public NormalizeRenderer WriteLeafRawLines(LeafBlock leafBlock, bool writeEndOfLines, bool indent = false)
{
- if (leafBlock == null) throw new ArgumentNullException(nameof(leafBlock));
+ if (leafBlock == null) ThrowHelper.ArgumentNullException_leafBlock();
if (leafBlock.Lines.Lines != null)
{
var lines = leafBlock.Lines;
diff --git a/src/Markdig/Renderers/TextRendererBase.cs b/src/Markdig/Renderers/TextRendererBase.cs
index c4eb973b8..42d609f1a 100644
--- a/src/Markdig/Renderers/TextRendererBase.cs
+++ b/src/Markdig/Renderers/TextRendererBase.cs
@@ -26,7 +26,7 @@ public abstract class TextRendererBase : RendererBase
///
protected TextRendererBase(TextWriter writer)
{
- if (writer == null) throw new ArgumentNullException(nameof(writer));
+ if (writer == null) ThrowHelper.ArgumentNullException_writer();
this.Writer = writer;
// By default we output a newline with '\n' only even on Windows platforms
Writer.NewLine = "\n";
@@ -43,7 +43,7 @@ public TextWriter Writer
{
if (value == null)
{
- throw new ArgumentNullException(nameof(value));
+ ThrowHelper.ArgumentNullException(nameof(value));
}
writer = value;
@@ -97,7 +97,7 @@ internal void Reset()
}
else
{
- throw new InvalidOperationException("Cannot reset this TextWriter instance");
+ ThrowHelper.InvalidOperationException("Cannot reset this TextWriter instance");
}
previousWasLine = true;
@@ -119,7 +119,7 @@ public T EnsureLine()
public void PushIndent(string indent)
{
- if (indent == null) throw new ArgumentNullException(nameof(indent));
+ if (indent == null) ThrowHelper.ArgumentNullException(nameof(indent));
indents.Add(indent);
}
@@ -147,7 +147,7 @@ private void WriteIndent()
///
/// The content.
/// This instance
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public T Write(string content)
{
WriteIndent();
@@ -161,7 +161,7 @@ public T Write(string content)
///
/// The slice.
/// This instance
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public T Write(ref StringSlice slice)
{
if (slice.Start > slice.End)
@@ -176,7 +176,7 @@ public T Write(ref StringSlice slice)
///
/// The slice.
/// This instance
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public T Write(StringSlice slice)
{
return Write(ref slice);
@@ -187,7 +187,7 @@ public T Write(StringSlice slice)
///
/// The content.
/// This instance
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public T Write(char content)
{
WriteIndent();
@@ -241,7 +241,7 @@ public T Write(string content, int offset, int length)
/// Writes a newline.
///
/// This instance
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public T WriteLine()
{
WriteIndent();
@@ -255,7 +255,7 @@ public T WriteLine()
///
/// The content.
/// This instance
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public T WriteLine(string content)
{
WriteIndent();
@@ -269,10 +269,10 @@ public T WriteLine(string content)
///
/// The leaf block.
/// This instance
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public T WriteLeafInline(LeafBlock leafBlock)
{
- if (leafBlock == null) throw new ArgumentNullException(nameof(leafBlock));
+ if (leafBlock == null) ThrowHelper.ArgumentNullException_leafBlock();
var inline = (Inline) leafBlock.Inline;
if (inline != null)
{
diff --git a/src/Markdig/Syntax/ContainerBlock.cs b/src/Markdig/Syntax/ContainerBlock.cs
index a0c8b42b7..3ee68f2ad 100644
--- a/src/Markdig/Syntax/ContainerBlock.cs
+++ b/src/Markdig/Syntax/ContainerBlock.cs
@@ -27,7 +27,7 @@ public abstract class ContainerBlock : Block, IList
/// The parser used to create this block.
protected ContainerBlock(BlockParser parser) : base(parser)
{
- children = ArrayHelper.Empty;
+ children = Array.Empty();
}
///
@@ -56,10 +56,12 @@ IEnumerator IEnumerable.GetEnumerator()
public void Add(Block item)
{
- if (item == null) throw new ArgumentNullException(nameof(item));
+ if (item == null)
+ ThrowHelper.ArgumentNullException_item();
+
if (item.Parent != null)
{
- throw new ArgumentException("Cannot add this block as it as already attached to another container (block.Parent != null)");
+ ThrowHelper.ArgumentException("Cannot add this block as it as already attached to another container (block.Parent != null)");
}
if (Count == children.Length)
@@ -104,7 +106,9 @@ public void Clear()
public bool Contains(Block item)
{
- if (item == null) throw new ArgumentNullException(nameof(item));
+ if (item == null)
+ ThrowHelper.ArgumentNullException_item();
+
for (int i = 0; i < Count; i++)
{
if (children[i] == item)
@@ -122,7 +126,9 @@ public void CopyTo(Block[] array, int arrayIndex)
public bool Remove(Block item)
{
- if (item == null) throw new ArgumentNullException(nameof(item));
+ if (item == null)
+ ThrowHelper.ArgumentNullException_item();
+
for (int i = Count - 1; i >= 0; i--)
{
if (children[i] == item)
@@ -140,7 +146,9 @@ public bool Remove(Block item)
public int IndexOf(Block item)
{
- if (item == null) throw new ArgumentNullException(nameof(item));
+ if (item == null)
+ ThrowHelper.ArgumentNullException_item();
+
for (int i = 0; i < Count; i++)
{
if (children[i] == item)
@@ -153,14 +161,16 @@ public int IndexOf(Block item)
public void Insert(int index, Block item)
{
- if (item == null) throw new ArgumentNullException(nameof(item));
+ if (item == null)
+ ThrowHelper.ArgumentNullException_item();
+
if (item.Parent != null)
{
- throw new ArgumentException("Cannot add this block as it as already attached to another container (block.Parent != null)");
+ ThrowHelper.ArgumentException("Cannot add this block as it as already attached to another container (block.Parent != null)");
}
- if (index < 0 || index > Count)
+ if ((uint)index > (uint)Count)
{
- throw new ArgumentOutOfRangeException(nameof(index));
+ ThrowHelper.ArgumentOutOfRangeException_index();
}
if (Count == children.Length)
{
@@ -177,7 +187,9 @@ public void Insert(int index, Block item)
public void RemoveAt(int index)
{
- if (index < 0 || index >= Count) throw new ArgumentOutOfRangeException(nameof(index));
+ if ((uint)index > (uint)Count)
+ ThrowHelper.ArgumentOutOfRangeException_index();
+
Count--;
// previous children
var item = children[index];
@@ -210,13 +222,13 @@ public Block this[int index]
public void Sort(IComparer comparer)
{
- if (comparer == null) throw new ArgumentNullException(nameof(comparer));
+ if (comparer == null) ThrowHelper.ArgumentNullException(nameof(comparer));
Array.Sort(children, 0, Count, comparer);
}
public void Sort(Comparison comparison)
{
- if (comparison == null) throw new ArgumentNullException(nameof(comparison));
+ if (comparison == null) ThrowHelper.ArgumentNullException(nameof(comparison));
Array.Sort(children, 0, Count, new BlockComparer(comparison));
}
diff --git a/src/Markdig/Syntax/Inlines/ContainerInline.cs b/src/Markdig/Syntax/Inlines/ContainerInline.cs
index 676d057c7..fe27e1acf 100644
--- a/src/Markdig/Syntax/Inlines/ContainerInline.cs
+++ b/src/Markdig/Syntax/Inlines/ContainerInline.cs
@@ -1,6 +1,7 @@
// Copyright (c) Alexandre Mutel. All rights reserved.
// This file is licensed under the BSD-Clause 2 license.
// See the license.txt file in the project root for more information.
+
using Markdig.Helpers;
using System;
using System.Collections;
@@ -50,10 +51,10 @@ public void Clear()
/// Inline has already a parent
public virtual ContainerInline AppendChild(Inline child)
{
- if (child == null) throw new ArgumentNullException(nameof(child));
+ if (child == null) ThrowHelper.ArgumentNullException(nameof(child));
if (child.Parent != null)
{
- throw new ArgumentException("Inline has already a parent", nameof(child));
+ ThrowHelper.ArgumentException("Inline has already a parent", nameof(child));
}
if (FirstChild == null)
@@ -98,7 +99,7 @@ public IEnumerable FindDescendants() where T : Inline
{
if (FirstChild is null)
{
- return ArrayHelper.Empty;
+ return Array.Empty();
}
else
{
@@ -145,7 +146,7 @@ internal IEnumerable FindDescendantsInternal() where T : MarkdownObject
/// The parent.
public void MoveChildrenAfter(Inline parent)
{
- if (parent == null) throw new ArgumentNullException(nameof(parent));
+ if (parent == null) ThrowHelper.ArgumentNullException(nameof(parent));
var child = FirstChild;
var nextSibling = parent;
while (child != null)
@@ -166,7 +167,7 @@ public void MoveChildrenAfter(Inline parent)
/// If the container is null
public void EmbraceChildrenBy(ContainerInline container)
{
- if (container == null) throw new ArgumentNullException(nameof(container));
+ if (container == null) ThrowHelper.ArgumentNullException(nameof(container));
var child = FirstChild;
while (child != null)
{
@@ -238,7 +239,7 @@ public struct Enumerator : IEnumerator
public Enumerator(ContainerInline container) : this()
{
- if (container == null) throw new ArgumentNullException(nameof(container));
+ if (container == null) ThrowHelper.ArgumentNullException(nameof(container));
this.container = container;
currentChild = nextChild = container.FirstChild;
}
diff --git a/src/Markdig/Syntax/Inlines/DelimiterInline.cs b/src/Markdig/Syntax/Inlines/DelimiterInline.cs
index 1e292414f..da59bb916 100644
--- a/src/Markdig/Syntax/Inlines/DelimiterInline.cs
+++ b/src/Markdig/Syntax/Inlines/DelimiterInline.cs
@@ -17,7 +17,7 @@ public abstract class DelimiterInline : ContainerInline
{
protected DelimiterInline(InlineParser parser)
{
- if (parser == null) throw new ArgumentNullException(nameof(parser));
+ if (parser == null) ThrowHelper.ArgumentNullException(nameof(parser));
Parser = parser;
IsActive = true;
}
diff --git a/src/Markdig/Syntax/Inlines/EmphasisDelimiterInline.cs b/src/Markdig/Syntax/Inlines/EmphasisDelimiterInline.cs
index b1e908c67..d6e5ece6e 100644
--- a/src/Markdig/Syntax/Inlines/EmphasisDelimiterInline.cs
+++ b/src/Markdig/Syntax/Inlines/EmphasisDelimiterInline.cs
@@ -23,7 +23,10 @@ public class EmphasisDelimiterInline : DelimiterInline
///
public EmphasisDelimiterInline(InlineParser parser, EmphasisDescriptor descriptor) : base(parser)
{
- Descriptor = descriptor ?? throw new ArgumentNullException(nameof(descriptor));
+ if (descriptor is null)
+ ThrowHelper.ArgumentNullException(nameof(descriptor));
+
+ Descriptor = descriptor;
DelimiterChar = descriptor.Character;
}
diff --git a/src/Markdig/Syntax/Inlines/Inline.cs b/src/Markdig/Syntax/Inlines/Inline.cs
index 99dff49a7..2b79fb337 100644
--- a/src/Markdig/Syntax/Inlines/Inline.cs
+++ b/src/Markdig/Syntax/Inlines/Inline.cs
@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.IO;
+using Markdig.Helpers;
using Markdig.Parsers;
namespace Markdig.Syntax.Inlines
@@ -42,10 +43,10 @@ public abstract class Inline : MarkdownObject, IInline
/// Inline has already a parent
public void InsertAfter(Inline next)
{
- if (next == null) throw new ArgumentNullException(nameof(next));
+ if (next == null) ThrowHelper.ArgumentNullException(nameof(next));
if (next.Parent != null)
{
- throw new ArgumentException("Inline has already a parent", nameof(next));
+ ThrowHelper.ArgumentException("Inline has already a parent", nameof(next));
}
var previousNext = NextSibling;
@@ -73,10 +74,10 @@ public void InsertAfter(Inline next)
/// Inline has already a parent
public void InsertBefore(Inline previous)
{
- if (previous == null) throw new ArgumentNullException(nameof(previous));
+ if (previous == null) ThrowHelper.ArgumentNullException(nameof(previous));
if (previous.Parent != null)
{
- throw new ArgumentException("Inline has already a parent", nameof(previous));
+ ThrowHelper.ArgumentException("Inline has already a parent", nameof(previous));
}
var previousSibling = PreviousSibling;
@@ -129,7 +130,7 @@ public void Remove()
/// If inline is null
public Inline ReplaceBy(Inline inline, bool copyChildren = true)
{
- if (inline == null) throw new ArgumentNullException(nameof(inline));
+ if (inline == null) ThrowHelper.ArgumentNullException(nameof(inline));
// Save sibling
var parent = Parent;
@@ -271,7 +272,7 @@ protected virtual void OnChildInsert(Inline child)
///
public void DumpTo(TextWriter writer)
{
- if (writer == null) throw new ArgumentNullException(nameof(writer));
+ if (writer == null) ThrowHelper.ArgumentNullException_writer();
DumpTo(writer, 0);
}
@@ -283,7 +284,7 @@ public void DumpTo(TextWriter writer)
/// if writer is null
public void DumpTo(TextWriter writer, int level)
{
- if (writer == null) throw new ArgumentNullException(nameof(writer));
+ if (writer == null) ThrowHelper.ArgumentNullException_writer();
for (int i = 0; i < level; i++)
{
writer.Write(' ');
diff --git a/src/Markdig/Syntax/Inlines/LiteralInline.cs b/src/Markdig/Syntax/Inlines/LiteralInline.cs
index 46c4be2a8..5f2171520 100644
--- a/src/Markdig/Syntax/Inlines/LiteralInline.cs
+++ b/src/Markdig/Syntax/Inlines/LiteralInline.cs
@@ -39,7 +39,7 @@ public LiteralInline(StringSlice content)
///
public LiteralInline(string text)
{
- if (text == null) throw new ArgumentNullException(nameof(text));
+ if (text == null) ThrowHelper.ArgumentNullException_text();
Content = new StringSlice(text);
}
diff --git a/src/Markdig/Syntax/LinkReferenceDefinitionExtensions.cs b/src/Markdig/Syntax/LinkReferenceDefinitionExtensions.cs
index abfa3d513..597720672 100644
--- a/src/Markdig/Syntax/LinkReferenceDefinitionExtensions.cs
+++ b/src/Markdig/Syntax/LinkReferenceDefinitionExtensions.cs
@@ -1,6 +1,7 @@
-// Copyright (c) Alexandre Mutel. All rights reserved.
+// Copyright (c) Alexandre Mutel. All rights reserved.
// This file is licensed under the BSD-Clause 2 license.
// See the license.txt file in the project root for more information.
+using Markdig.Helpers;
using System;
using System.Collections.Generic;
@@ -15,7 +16,7 @@ public static class LinkReferenceDefinitionExtensions
public static bool ContainsLinkReferenceDefinition(this MarkdownDocument document, string label)
{
- if (label == null) throw new ArgumentNullException(nameof(label));
+ if (label == null) ThrowHelper.ArgumentNullException_label();
var references = document.GetData(DocumentKey) as LinkReferenceDefinitionGroup;
if (references == null)
{
@@ -26,14 +27,14 @@ public static bool ContainsLinkReferenceDefinition(this MarkdownDocument documen
public static void SetLinkReferenceDefinition(this MarkdownDocument document, string label, LinkReferenceDefinition linkReferenceDefinition)
{
- if (label == null) throw new ArgumentNullException(nameof(label));
+ if (label == null) ThrowHelper.ArgumentNullException_label();
var references = document.GetLinkReferenceDefinitions();
references.Set(label, linkReferenceDefinition);
}
public static bool TryGetLinkReferenceDefinition(this MarkdownDocument document, string label, out LinkReferenceDefinition linkReferenceDefinition)
{
- if (label == null) throw new ArgumentNullException(nameof(label));
+ if (label == null) ThrowHelper.ArgumentNullException_label();
linkReferenceDefinition = null;
var references = document.GetData(DocumentKey) as LinkReferenceDefinitionGroup;
if (references == null)
diff --git a/src/Markdig/Syntax/LinkReferenceDefinitionGroup.cs b/src/Markdig/Syntax/LinkReferenceDefinitionGroup.cs
index e3e8e263c..42da166b4 100644
--- a/src/Markdig/Syntax/LinkReferenceDefinitionGroup.cs
+++ b/src/Markdig/Syntax/LinkReferenceDefinitionGroup.cs
@@ -2,6 +2,7 @@
// This file is licensed under the BSD-Clause 2 license.
// See the license.txt file in the project root for more information.
+using Markdig.Helpers;
using System;
using System.Collections.Generic;
@@ -28,7 +29,7 @@ public LinkReferenceDefinitionGroup() : base(null)
public void Set(string label, LinkReferenceDefinition link)
{
- if (link == null) throw new ArgumentNullException(nameof(link));
+ if (link == null) ThrowHelper.ArgumentNullException(nameof(link));
if (!Contains(link))
{
Add(link);
diff --git a/src/Markdig/Syntax/MarkdownObject.cs b/src/Markdig/Syntax/MarkdownObject.cs
index 484bc404f..710ed4182 100644
--- a/src/Markdig/Syntax/MarkdownObject.cs
+++ b/src/Markdig/Syntax/MarkdownObject.cs
@@ -1,6 +1,7 @@
-// Copyright (c) Alexandre Mutel. All rights reserved.
+// Copyright (c) Alexandre Mutel. All rights reserved.
// This file is licensed under the BSD-Clause 2 license.
// See the license.txt file in the project root for more information.
+using Markdig.Helpers;
using System;
namespace Markdig.Syntax
@@ -55,7 +56,7 @@ public string ToPositionText()
/// if key is null
public void SetData(object key, object value)
{
- if (key == null) throw new ArgumentNullException(nameof(key));
+ if (key == null) ThrowHelper.ArgumentNullException_key();
if (attachedDatas == null)
{
attachedDatas = new DataEntry[1];
@@ -89,7 +90,7 @@ public void SetData(object key, object value)
/// if key is null
public bool ContainsData(object key)
{
- if (key == null) throw new ArgumentNullException(nameof(key));
+ if (key == null) ThrowHelper.ArgumentNullException_key();
if (attachedDatas == null)
{
return false;
@@ -113,7 +114,7 @@ public bool ContainsData(object key)
/// if key is null
public object GetData(object key)
{
- if (key == null) throw new ArgumentNullException(nameof(key));
+ if (key == null) ThrowHelper.ArgumentNullException_key();
if (attachedDatas == null)
{
return null;
@@ -136,7 +137,7 @@ public object GetData(object key)
///
public bool RemoveData(object key)
{
- if (key == null) throw new ArgumentNullException(nameof(key));
+ if (key == null) ThrowHelper.ArgumentNullException_key();
if (attachedDatas == null)
{
return true;
diff --git a/src/Markdig/Syntax/MarkdownObjectExtensions.cs b/src/Markdig/Syntax/MarkdownObjectExtensions.cs
index efb1e44c4..012bfb296 100644
--- a/src/Markdig/Syntax/MarkdownObjectExtensions.cs
+++ b/src/Markdig/Syntax/MarkdownObjectExtensions.cs
@@ -2,9 +2,9 @@
// This file is licensed under the BSD-Clause 2 license.
// See the license.txt file in the project root for more information.
+using System;
using System.Collections.Generic;
using System.Diagnostics;
-using Markdig.Helpers;
using Markdig.Syntax.Inlines;
namespace Markdig.Syntax
@@ -94,7 +94,7 @@ public static IEnumerable Descendants(this MarkdownObject markdownObject)
}
}
- return ArrayHelper.Empty;
+ return Array.Empty();
}
///
@@ -124,7 +124,7 @@ public static IEnumerable Descendants(this ContainerBlock block) where T :
}
else
{
- return ArrayHelper.Empty;
+ return Array.Empty();
}
}