From 4c94875aac1ab362e8916de8826031b2904aa2ce Mon Sep 17 00:00:00 2001 From: BDisp Date: Fri, 16 Sep 2022 14:22:50 +0000 Subject: [PATCH] Fixes #61. ustring.IsNullOrEmpty doesn't work the same way as the string.IsNullOrEmpty method. (#62) * Added .editorconfig to the solution files. * Fixes #61. ustring.IsNullOrEmpty doesn't work the same way as the string.IsNullOrEmpty method. * Fixing format. * Change the indent and tab length to 4. * Updated nuget packages. * Improves the Substring unit test. --- .editorconfig | 23 +++++- NStack.sln | 1 + NStack/strings/ustring.cs | 97 ++++++++++++------------- NStackTests/NStackTests.csproj | 4 +- NStackTests/ustringTest.cs | 125 +++++++++++++++++++++++---------- 5 files changed, 161 insertions(+), 89 deletions(-) diff --git a/.editorconfig b/.editorconfig index 765b22f..ad6f1d6 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,2 +1,23 @@ [*.cs] -indent_style = tab \ No newline at end of file +indent_style = tab +indent_size = 4 +tab_width = 4 +csharp_new_line_before_open_brace = methods,local_functions +csharp_new_line_before_else = false +csharp_new_line_before_catch = false +csharp_new_line_before_finally = false +end_of_line = crlf + +csharp_indent_case_contents = true +csharp_indent_switch_labels = false +csharp_indent_labels = flush_left +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_preserve_single_line_blocks = true +dotnet_style_require_accessibility_modifiers = never +csharp_style_var_when_type_is_apparent = true +csharp_prefer_braces = false +csharp_space_before_open_square_brackets = true +csharp_space_between_method_call_name_and_opening_parenthesis = true +csharp_space_between_method_declaration_name_and_open_parenthesis = true \ No newline at end of file diff --git a/NStack.sln b/NStack.sln index 5df5d18..43ed1a6 100644 --- a/NStack.sln +++ b/NStack.sln @@ -8,6 +8,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NStackTests", "NStackTests\ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Files", "Solution Files", "{760C271D-E55A-4F44-BE2C-9B476D310CAC}" ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig .github\workflows\build.yml = .github\workflows\build.yml .github\workflows\publish.yml = .github\workflows\publish.yml README.md = README.md diff --git a/NStack/strings/ustring.cs b/NStack/strings/ustring.cs index ab8f969..edbf9d4 100644 --- a/NStack/strings/ustring.cs +++ b/NStack/strings/ustring.cs @@ -155,8 +155,7 @@ public IntPtrUString (IntPtr block, int size, bool copy, Action releaseF if (size == 0) size = 1; this.block = Marshal.AllocHGlobal (size); - unsafe - { + unsafe { Buffer.MemoryCopy ((void*)block, (void*)this.block, size, size); } } else { @@ -182,8 +181,7 @@ public override void CopyTo (int fromOffset, byte [] target, int targetOffset, i throw new ArgumentException (nameof (count)); if (fromOffset + count > size) throw new ArgumentException (nameof (count)); - unsafe - { + unsafe { byte* p = ((byte*)block) + fromOffset; for (int i = 0; i < count; i++, p++) @@ -193,16 +191,14 @@ public override void CopyTo (int fromOffset, byte [] target, int targetOffset, i public override string ToString () { - unsafe - { + unsafe { return Encoding.UTF8.GetString ((byte*)block, size); } } protected internal override ustring GetRange (int start, int end) { - unsafe - { + unsafe { return new IntPtrSubUString (this, (IntPtr)((byte*)block + start), size: end - start); } } @@ -210,8 +206,7 @@ protected internal override ustring GetRange (int start, int end) internal override int RealIndexByte (byte b, int offset) { var t = size - offset; - unsafe - { + unsafe { byte* p = (byte*)block + offset; for (int i = 0; i < t; i++) { if (p [i] == b) @@ -307,8 +302,7 @@ public override string ToString () internal override int RealIndexByte (byte b, int offset) { var t = Length - offset; - unsafe - { + unsafe { fixed (byte* p = &buffer [offset]) { for (int i = 0; i < t; i++) if (p [i] == b) @@ -376,8 +370,7 @@ public override string ToString () internal override int RealIndexByte (byte b, int offset) { var t = count - offset; - unsafe - { + unsafe { fixed (byte* p = &buffer [start + offset]) { for (int i = 0; i < t; i++) if (p [i] == b) @@ -429,7 +422,7 @@ public static ustring Make (params byte [] buffer) /// Rune (short name for Unicode code point). public static ustring Make (Rune rune) { - return new ByteBufferUString ((uint) rune); + return new ByteBufferUString ((uint)rune); } /// @@ -630,8 +623,7 @@ unsafe static bool EqualsHelper (byte* a, byte* b, int length) static bool EqualsHelper (ustring a, ustring b) { // If both string are identical, return true. - if (a.SequenceEqual(b)) - { + if (a.SequenceEqual (b)) { return true; } @@ -644,8 +636,7 @@ static bool EqualsHelper (ustring a, ustring b) var abs = a as ByteBufferUString; var bbs = b as ByteBufferUString; if ((object)abs != null && (object)bbs != null) { - unsafe - { + unsafe { fixed (byte* ap = &abs.buffer [0]) fixed (byte* bp = &bbs.buffer [0]) { return EqualsHelper (ap, bp, alen); } @@ -654,8 +645,7 @@ static bool EqualsHelper (ustring a, ustring b) var aip = a as IntPtrUString; var bip = b as IntPtrUString; if ((object)aip != null && (object)bip != null) { - unsafe - { + unsafe { return EqualsHelper ((byte*)aip.block, (byte*)bip.block, alen); } } @@ -719,6 +709,9 @@ static bool EqualsHelper (ustring a, ustring b) /// public static implicit operator ustring (string str) { + if (str == null) + return null; + return new ByteBufferUString (str); } @@ -946,7 +939,7 @@ public static ustring Make (byte [] buffer, int start, int count) int size = Length; if (end < 0) end = size + end; - + if (start < 0) start = size + start; @@ -1042,11 +1035,10 @@ public ustring RuneSubstring (int runeStart, int length = 0) if (runeStart < 0) runeStart = 0; - var runes = this.ToRunes(); + var runes = this.ToRunes (); ustring usRange = ""; - for (int i = runeStart; i < runeStart + length; i++) - { - usRange += ustring.Make(runes [i]); + for (int i = runeStart; i < runeStart + length; i++) { + usRange += ustring.Make (runes [i]); } return usRange; } @@ -1073,7 +1065,7 @@ public int ConsoleWidth { for (int i = 0; i < blen;) { (var rune, var size) = Utf8.DecodeRune (this, i, i - blen); i += size; - total += Rune.ColumnWidth(rune); + total += Rune.ColumnWidth (rune); } return total; } @@ -1261,7 +1253,7 @@ public List ToRuneList (int limit) /// Substr. public int Count (ustring substr) { - if ((object) substr == null) + if ((object)substr == null) throw new ArgumentNullException (nameof (substr)); int n = 0; if (substr.Length == 0) @@ -1349,7 +1341,7 @@ public int IndexOf (ustring substr, int offset = 0) { if ((object)substr == null) throw new ArgumentNullException (nameof (substr)); - + var n = substr.Length; if (n == 0) return offset; @@ -1388,7 +1380,7 @@ public int IndexOf (ustring substr, int offset = 0) if (h == hashss && CompareStringRange (this, offset, n, substr)) return offset; - + for (int i = n; i < blen;) { var reali = offset + i; h *= primeRK; @@ -1419,7 +1411,7 @@ public int LastIndexOf (ustring substr) if (n == 1) return LastIndexByte (substr [0]); if (n == Length) { - if (((object)substr == (object) this)) + if (((object)substr == (object)this)) return 0; if (CompareStringRange (substr, 0, n, this)) @@ -1521,7 +1513,7 @@ public int IndexOfAny (ustring chars) for (int i = 0; i < blen;) { (var rune, var size) = Utf8.DecodeRune (this, i, i - blen); - for (int j = 0; j < clen; ) { + for (int j = 0; j < clen;) { (var crune, var csize) = Utf8.DecodeRune (chars, j, j - clen); if (crune == rune) return i; @@ -1583,7 +1575,7 @@ public int LastIndexOfAny (ustring chars) if (AsciiSet.MakeAsciiSet (ref aset, chars)) { for (int i = blen - 1; i >= 0; i--) if (AsciiSet.Contains (ref aset, this [i])) - return i; + return i; return -1; } } @@ -1665,7 +1657,7 @@ ustring [] GenSplit (ustring sep, int sepSave, int n = -1) var m = IndexOf (sep, offset); if (m < 0) break; - result [i] = this [offset, m+sepSave]; + result [i] = this [offset, m + sepSave]; offset = m + sepLen; i++; } @@ -1698,7 +1690,7 @@ public bool StartsWith (ustring prefix) throw new ArgumentNullException (nameof (prefix)); if (Length < prefix.Length) return false; - return CompareStringRange (this, 0, prefix.Length, prefix); + return CompareStringRange (this, 0, prefix.Length, prefix); } /// @@ -1763,15 +1755,13 @@ public static ustring Join (ustring separator, params ustring [] values) // most-significant bit of the highest word, map to the full range of all // 128 ASCII characters. The 128-bits of the upper 16 bytes will be zeroed, // ensuring that any non-ASCII character will be reported as not in the set. - struct AsciiSet - { + struct AsciiSet { unsafe internal fixed uint ascii [8]; public static bool MakeAsciiSet (ref AsciiSet aset, ustring chars) { var n = chars.Length; - unsafe - { + unsafe { fixed (uint* ascii = aset.ascii) { for (int i = 0; i < n; i++) { var c = chars [i]; @@ -1789,8 +1779,7 @@ public static bool MakeAsciiSet (ref AsciiSet aset, ustring chars) public static bool MakeAsciiSet (ref AsciiSet aset, uint [] runes) { var n = runes.Length; - unsafe - { + unsafe { fixed (uint* ascii = aset.ascii) { for (int i = 0; i < n; i++) { var r = runes [i]; @@ -1806,8 +1795,7 @@ public static bool MakeAsciiSet (ref AsciiSet aset, uint [] runes) } public static bool Contains (ref AsciiSet aset, byte b) { - unsafe - { + unsafe { fixed (uint* ascii = aset.ascii) { return (ascii [b >> 5] & (1 << (b & 31))) != 0; } @@ -1833,6 +1821,19 @@ public static bool Contains (ref AsciiSet aset, byte b) return new ByteBufferUString (copy); } + /// + /// Convert from to + /// or to null if the is null. + /// + /// The ustring. + public static explicit operator string (ustring v) + { + if (v == null) + return null; + + return v.ToString (); + } + /// /// An enumerator that returns the index within the string, and the rune found at that location /// @@ -1927,7 +1928,7 @@ static ustring Map (Func mapping, ustring s, Action scanReset = null var mapped = mapping (rune); // common case - if (0 < mapped && mapped <= Utf8.RuneSelf){ + if (0 < mapped && mapped <= Utf8.RuneSelf) { result [targetOffset] = (byte)mapped; targetOffset++; continue; @@ -2165,7 +2166,7 @@ int FlexIndexOf (RunePredicate matchFunc, bool expected) int FlexLastIndexOf (RunePredicate matchFunc, bool expected) { int blen = Length; - for (int i = blen; i > 0; ){ + for (int i = blen; i > 0;) { (var rune, var size) = Utf8.DecodeLastRune (this, i); i -= size; if (matchFunc (rune) == expected) @@ -2206,8 +2207,8 @@ public ustring Replace (ustring oldValue, ustring newValue, int maxReplacements (_, var wid) = Utf8.DecodeRune (this, start); j += wid; } - } else - j += IndexOf (oldValue, start)-start; + } else + j += IndexOf (oldValue, start) - start; var copyCount = j - start; if (copyCount > 0) { CopyTo (fromOffset: start, target: result, targetOffset: w, count: copyCount); @@ -2304,7 +2305,7 @@ string IConvertible.ToString (IFormatProvider provider) object IConvertible.ToType (Type conversionType, IFormatProvider provider) { if (conversionType == typeof (string)) - return ToString (); + return ToString (); return Convert.ChangeType (ToString (), conversionType); } diff --git a/NStackTests/NStackTests.csproj b/NStackTests/NStackTests.csproj index 156d7c3..125f663 100644 --- a/NStackTests/NStackTests.csproj +++ b/NStackTests/NStackTests.csproj @@ -10,8 +10,8 @@ 0.20.0 - - + + all diff --git a/NStackTests/ustringTest.cs b/NStackTests/ustringTest.cs index 269f125..23d0cc4 100644 --- a/NStackTests/ustringTest.cs +++ b/NStackTests/ustringTest.cs @@ -103,12 +103,12 @@ public void Equals () var cp = ustring.Make (c1, len); var apalias = ap; - Assert.IsTrue(ap.Equals(bp)); + Assert.IsTrue (ap.Equals (bp)); Assert.IsTrue (ap == bp); string arefMod = "asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdy$"; - Assert.IsFalse(ap.Equals(arefMod)); - Assert.IsFalse(ap == arefMod); + Assert.IsFalse (ap.Equals (arefMod)); + Assert.IsFalse (ap == arefMod); Assert.IsTrue (ap == apalias); Assert.IsTrue (ap != cp); @@ -142,7 +142,6 @@ public void Equals () ("abc", "bcd", false), ("abc", "", true), ("", "a", false), - // 2-byte needle ("xxxxxx", "01", false), ("01xxxx", "01", true), @@ -592,7 +591,6 @@ public void TestIndex () ("foo", "o", 2), ("abcABCabc", "A", 3), ("abcABCabc", "a", 6), - }; [Test] @@ -716,61 +714,112 @@ public void TestIndexRune () } [Test] - public void TestConsoleWidth() + public void TestConsoleWidth () { - var sc = new Rune(0xd83d); - var r = new Rune(0xdd2e); - Assert.AreEqual(1, Rune.ColumnWidth(sc)); - Assert.False(Rune.IsNonSpacingChar(r)); - Assert.AreEqual(1, Rune.ColumnWidth(r)); - var fr = new Rune(sc, r); - Assert.False(Rune.IsNonSpacingChar(fr)); - Assert.AreEqual(1, Rune.ColumnWidth(fr)); - var us = ustring.Make(fr); - Assert.AreEqual(1, us.ConsoleWidth); + var sc = new Rune (0xd83d); + var r = new Rune (0xdd2e); + Assert.AreEqual (1, Rune.ColumnWidth (sc)); + Assert.False (Rune.IsNonSpacingChar (r)); + Assert.AreEqual (1, Rune.ColumnWidth (r)); + var fr = new Rune (sc, r); + Assert.False (Rune.IsNonSpacingChar (fr)); + Assert.AreEqual (1, Rune.ColumnWidth (fr)); + var us = ustring.Make (fr); + Assert.AreEqual (1, us.ConsoleWidth); } [Test] - public void Test_Substring() + public void Test_Substring () { ustring us = "This a test to return a substring"; - Assert.AreEqual("test to return a substring", us.Substring(7)); - Assert.AreEqual("test to return", us.Substring(7, 14)); + Assert.AreEqual ("test to return a substring", us.Substring (7)); + Assert.AreEqual ("test to return", us.Substring (7, 14)); } [Test] - public void Test_RuneSubstring() + public void Test_RuneSubstring () { ustring us = "This a test to return a substring"; - Assert.AreEqual("test to return a substring", us.RuneSubstring(7)); - Assert.AreEqual("test to return", us.RuneSubstring(7, 14)); + Assert.AreEqual ("test to return a substring", us.RuneSubstring (7)); + Assert.AreEqual ("test to return", us.RuneSubstring (7, 14)); } [Test] - public void Test_ToRunes() + public void Test_ToRunes () { ustring us = "Some long text that 🤖🧠 is super cool"; - uint[] runesArray = us.ToRunes(); - Assert.AreEqual(us, runesArray); + uint [] runesArray = us.ToRunes (); + Assert.AreEqual (us, runesArray); } [Test] - public void Make_Environment_NewLine() + public void Make_Environment_NewLine () { - var us = ustring.Make(Environment.NewLine); - if (Environment.NewLine.Length == 1) - { - Assert.AreEqual('\n', us[0]); - Assert.AreEqual(10, us[0]); + var us = ustring.Make (Environment.NewLine); + if (Environment.NewLine.Length == 1) { + Assert.AreEqual ('\n', us [0]); + Assert.AreEqual (10, us [0]); + } else { + Assert.AreEqual ('\r', us [0]); + Assert.AreEqual (13, us [0]); + + Assert.AreEqual ('\n', us [1]); + Assert.AreEqual (10, us [1]); } - else - { - Assert.AreEqual('\r', us[0]); - Assert.AreEqual(13, us[0]); + } - Assert.AreEqual('\n', us[1]); - Assert.AreEqual(10, us[1]); - } + [Test] + public void Substring_Same_As_String_Substring () + { + ustring ustrText = "Check this out 你"; + string str = (string)ustrText.Substring (0, ustrText.Length); + Assert.AreEqual (16, str.Length); + ustring ustr = ustrText.Substring (0, ustrText.Length); + Assert.AreEqual (18, ustr.Length); + Assert.AreEqual (str, ustr); + Assert.AreEqual (str, ustrText); + Assert.AreEqual (ustr, ustrText); + + string strText = "Check this out 你"; + str = strText.Substring (0, strText.Length); + Assert.AreEqual (16, str.Length); + ustr = strText.Substring (0, strText.Length); + Assert.AreEqual (18, ustr.Length); + Assert.AreEqual (str, ustr); + Assert.AreEqual (str, strText); + Assert.AreEqual (ustr, strText); + } + + [Test] + public void IsNullOrEmpty_Accept_Null_String_Arg () + { + string? str = null; + Assert.True (string.IsNullOrEmpty (str)); + Assert.True (ustring.IsNullOrEmpty (str)); + + str = ""; + Assert.True (string.IsNullOrEmpty (str)); + Assert.True (ustring.IsNullOrEmpty (str)); + + str = " "; + Assert.False (string.IsNullOrEmpty (str)); + Assert.False (ustring.IsNullOrEmpty (str)); + } + + [Test] + public void IsNullOrEmpty_Accept_Null_Ustring_Arg () + { + ustring? ustr = null; + Assert.True (string.IsNullOrEmpty ((string)ustr)); + Assert.True (ustring.IsNullOrEmpty (ustr)); + + ustr = ""; + Assert.True (string.IsNullOrEmpty (ustr.ToString ())); + Assert.True (ustring.IsNullOrEmpty (ustr)); + + ustr = " "; + Assert.False (string.IsNullOrEmpty (ustr.ToString ())); + Assert.False (ustring.IsNullOrEmpty (ustr)); } } }