Use C# compiler's static data support in Encoding.Preamble (dotnet/coreclr#20768)
authorStephen Toub <stoub@microsoft.com>
Sat, 3 Nov 2018 02:08:35 +0000 (22:08 -0400)
committerGitHub <noreply@github.com>
Sat, 3 Nov 2018 02:08:35 +0000 (22:08 -0400)
* Use C# compiler's static data support in Encoding.Preamble

Also avoid Array.Empty and just use default span for an empty preamble.

* Address PR feedback

Commit migrated from https://github.com/dotnet/coreclr/commit/faa4c87ff3e025c9bed978522f3fe4c85ceecb60

src/libraries/System.Private.CoreLib/src/System/Text/UTF32Encoding.cs
src/libraries/System.Private.CoreLib/src/System/Text/UTF8Encoding.cs
src/libraries/System.Private.CoreLib/src/System/Text/UnicodeEncoding.cs

index 39bc3f5..d579cc9 100644 (file)
@@ -39,9 +39,6 @@ namespace System.Text
         internal static readonly UTF32Encoding s_default = new UTF32Encoding(bigEndian: false, byteOrderMark: true);
         internal static readonly UTF32Encoding s_bigEndianDefault = new UTF32Encoding(bigEndian: true, byteOrderMark: true);
 
-        private static readonly byte[] s_bigEndianPreamble = new byte[4] { 0x00, 0x00, 0xFE, 0xFF };
-        private static readonly byte[] s_littleEndianPreamble = new byte[4] { 0xFF, 0xFE, 0x00, 0x00 };
-
         private readonly bool _emitUTF32ByteOrderMark = false;
         private readonly bool _isThrowException = false;
         private readonly bool _bigEndian = false;
@@ -1155,9 +1152,10 @@ namespace System.Text
         }
 
         public override ReadOnlySpan<byte> Preamble =>
-            GetType() != typeof(UTF32Encoding) ? GetPreamble() : // in case a derived UTF32Encoding overrode GetPreamble
-            _emitUTF32ByteOrderMark ? (_bigEndian ? s_bigEndianPreamble : s_littleEndianPreamble) :
-            Array.Empty<byte>();
+            GetType() != typeof(UTF32Encoding) ? new ReadOnlySpan<byte>(GetPreamble()) : // in case a derived UTF32Encoding overrode GetPreamble
+            !_emitUTF32ByteOrderMark ? default :
+            _bigEndian ? (ReadOnlySpan<byte>)new byte[4] { 0x00, 0x00, 0xFE, 0xFF } : // uses C# compiler's optimization for static byte[] data
+            (ReadOnlySpan<byte>)new byte[4] { 0xFF, 0xFE, 0x00, 0x00 };      
 
         public override bool Equals(object value)
         {
index 672d235..426835e 100644 (file)
@@ -55,14 +55,14 @@ namespace System.Text
         {
             public UTF8EncodingSealed(bool encoderShouldEmitUTF8Identifier) : base(encoderShouldEmitUTF8Identifier) { }
 
-            public override ReadOnlySpan<byte> Preamble => _emitUTF8Identifier ? s_preamble : Array.Empty<byte>();
+            public override ReadOnlySpan<byte> Preamble => _emitUTF8Identifier ? PreambleSpan : default;
         }
 
         // Used by Encoding.UTF8 for lazy initialization
         // The initialization code will not be run until a static member of the class is referenced
         internal static readonly UTF8EncodingSealed s_default = new UTF8EncodingSealed(encoderShouldEmitUTF8Identifier: true);
 
-        internal static readonly byte[] s_preamble = new byte[3] { 0xEF, 0xBB, 0xBF };
+        internal static ReadOnlySpan<byte> PreambleSpan => new byte[3] { 0xEF, 0xBB, 0xBF }; // uses C# compiler's optimization for static byte[] data
 
         // Yes, the idea of emitting U+FEFF as a UTF-8 identifier has made it into
         // the standard.
@@ -2549,9 +2549,9 @@ namespace System.Text
         }
 
         public override ReadOnlySpan<byte> Preamble =>
-            GetType() != typeof(UTF8Encoding) ? GetPreamble() : // in case a derived UTF8Encoding overrode GetPreamble
-            _emitUTF8Identifier ? s_preamble :
-            Array.Empty<byte>();
+            GetType() != typeof(UTF8Encoding) ? new ReadOnlySpan<byte>(GetPreamble()) : // in case a derived UTF8Encoding overrode GetPreamble
+            _emitUTF8Identifier ? PreambleSpan :
+            default;
 
         public override bool Equals(object value)
         {
index 0e4ff65..d80c229 100644 (file)
@@ -26,9 +26,6 @@ namespace System.Text
         internal static readonly UnicodeEncoding s_bigEndianDefault = new UnicodeEncoding(bigEndian: true, byteOrderMark: true);
         internal static readonly UnicodeEncoding s_littleEndianDefault = new UnicodeEncoding(bigEndian: false, byteOrderMark: true);
 
-        private static readonly byte[] s_bigEndianPreamble = new byte[2] { 0xfe, 0xff };
-        private static readonly byte[] s_littleEndianPreamble = new byte[2] { 0xff, 0xfe };
-
         private readonly bool isThrowException = false;
 
         private readonly bool bigEndian = false;
@@ -1793,9 +1790,10 @@ namespace System.Text
         }
 
         public override ReadOnlySpan<byte> Preamble =>
-            GetType() != typeof(UnicodeEncoding) ? GetPreamble() : // in case a derived UnicodeEncoding overrode GetPreamble
-            byteOrderMark ? (bigEndian ? s_bigEndianPreamble : s_littleEndianPreamble) :
-            Array.Empty<byte>();
+            GetType() != typeof(UnicodeEncoding) ? new ReadOnlySpan<byte>(GetPreamble()) : // in case a derived UnicodeEncoding overrode GetPreamble
+            !byteOrderMark ? default :
+            bigEndian ? (ReadOnlySpan<byte>)new byte[2] { 0xfe, 0xff } : // uses C# compiler's optimization for static byte[] data
+            (ReadOnlySpan<byte>)new byte[2] { 0xff, 0xfe };
 
         public override int GetMaxByteCount(int charCount)
         {