diff --git a/src/coreclr/clr.featuredefines.props b/src/coreclr/clr.featuredefines.props index 6c4c13243e129..a205c2d280dd1 100644 --- a/src/coreclr/clr.featuredefines.props +++ b/src/coreclr/clr.featuredefines.props @@ -36,12 +36,6 @@ true - - - true - - - $(DefineConstants);FEATURE_ARRAYSTUB_AS_IL $(DefineConstants);FEATURE_MULTICASTSTUB_AS_IL @@ -60,7 +54,6 @@ $(DefineConstants);FEATURE_TYPEEQUIVALENCE $(DefineConstants);FEATURE_BASICFREEZE $(DefineConstants);FEATURE_PORTABLE_SHUFFLE_THUNKS - $(DefineConstants);FEATURE_UTF8STRING $(DefineConstants);PROFILING_SUPPORTED $(DefineConstants);FEATURE_PROFAPI_ATTACH_DETACH diff --git a/src/coreclr/clrdefinitions.cmake b/src/coreclr/clrdefinitions.cmake index eafe212786d85..d22738910023c 100644 --- a/src/coreclr/clrdefinitions.cmake +++ b/src/coreclr/clrdefinitions.cmake @@ -1,11 +1,5 @@ include(clrfeatures.cmake) -# Features we're currently flighting, but don't intend to ship in officially supported releases -if (PRERELEASE) - add_definitions(-DFEATURE_UTF8STRING) - # add_definitions(-DFEATURE_XXX) -endif (PRERELEASE) - add_compile_definitions($<$>:DACCESS_COMPILE>) add_compile_definitions($<$>:CROSSGEN_COMPILE>) add_compile_definitions($<$>:CROSS_COMPILE>) diff --git a/src/coreclr/src/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/coreclr/src/System.Private.CoreLib/System.Private.CoreLib.csproj index 304b50f06676d..1b0204588a2f8 100644 --- a/src/coreclr/src/System.Private.CoreLib/System.Private.CoreLib.csproj +++ b/src/coreclr/src/System.Private.CoreLib/System.Private.CoreLib.csproj @@ -253,9 +253,6 @@ - - - diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Utf8String.CoreCLR.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Utf8String.CoreCLR.cs deleted file mode 100644 index 015f89ee16a01..0000000000000 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Utf8String.CoreCLR.cs +++ /dev/null @@ -1,333 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.ComponentModel; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Text.Unicode; -using Internal.Runtime.CompilerServices; - -namespace System -{ - public sealed partial class Utf8String - { - /* - * INSTANCE FIELDS - * Do not reorder these fields. They must match the layout of Utf8StringObject in object.h. - */ - - private readonly int _length; - private readonly byte _firstByte; - - /* - * INSTANCE PROPERTIES - */ - - /// - /// Returns the length (in UTF-8 code units, or s) of this instance. - /// - public int Length => _length; - - /* - * CONSTRUCTORS - * - * Defining a new constructor for string-like types (like Utf8String) requires changes both - * to the managed code below and to the native VM code. See the comment at the top of - * src/vm/ecall.cpp for instructions on how to add new overloads. - * - * These ctors validate their input, throwing ArgumentException if the input does not represent - * well-formed UTF-8 data. (In the case of transcoding ctors, the ctors throw if the input does - * not represent well-formed UTF-16 data.) There are Create* factory methods which allow the caller - * to control this behavior with finer granularity, including performing U+FFFD replacement instead - * of throwing, or even suppressing validation altogether if the caller knows the input to be well- - * formed. - * - * The reason a throwing behavior was chosen by default is that we don't want to surprise developers - * if ill-formed data loses fidelity while being round-tripped through this type. Developers should - * perform an explicit gesture to opt-in to lossy behavior, such as calling the factories explicitly - * documented as performing such replacement. - */ - - /// - /// Creates a instance from existing UTF-8 data. - /// - /// The existing UTF-8 data from which to create a new . - /// - /// Thrown if does not represent well-formed UTF-8 data. - /// - /// - /// The UTF-8 data in is validated for well-formedness upon construction, - /// and an exception is thrown if the input is ill-formed. To avoid this exception, consider using - /// or . - /// - [MethodImpl(MethodImplOptions.InternalCall)] - public extern Utf8String(ReadOnlySpan value); - -#pragma warning disable CA1822 // Mark members as static - -#if !CORECLR - static -#endif - private Utf8String Ctor(ReadOnlySpan value) - { - if (value.IsEmpty) - { - return Empty; - } - - // Create and populate the Utf8String instance. - - Utf8String newString = FastAllocateSkipZeroInit(value.Length); - Buffer.Memmove(ref newString.DangerousGetMutableReference(), ref MemoryMarshal.GetReference(value), (uint)value.Length); - - // Now perform validation. - // Reminder: Perform validation over the copy, not over the source. - - if (!Utf8Utility.IsWellFormedUtf8(newString.AsBytes())) - { - throw new ArgumentException( - message: SR.Utf8String_InputContainedMalformedUtf8, - paramName: nameof(value)); - } - - return newString; - } - - /// - /// Creates a instance from existing UTF-8 data. - /// - /// - /// Thrown if does not represent well-formed UTF-8 data. - /// - /// - /// The UTF-8 data in is validated for well-formedness upon construction, - /// and an exception is thrown if the input is ill-formed. To avoid this exception, consider using - /// or . - /// - - [MethodImpl(MethodImplOptions.InternalCall)] - public extern Utf8String(byte[] value, int startIndex, int length); - -#if !CORECLR - static -#endif - private Utf8String Ctor(byte[] value, int startIndex, int length) - { - if (value is null) - { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); - } - - return Ctor(new ReadOnlySpan(value, startIndex, length)); - } - - /// - /// Creates a instance from existing null-terminated UTF-8 data. - /// - /// - /// Thrown if does not represent well-formed UTF-8 data. - /// - /// - /// The UTF-8 data in is validated for well-formedness upon construction, - /// and an exception is thrown if the input is ill-formed. To avoid this exception, consider using - /// or . - /// - - [MethodImpl(MethodImplOptions.InternalCall)] - [CLSCompliant(false)] - public extern unsafe Utf8String(byte* value); - -#if !CORECLR - static -#endif - private unsafe Utf8String Ctor(byte* value) - { - if (value is null) - { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); - } - - return Ctor(new ReadOnlySpan(value, string.strlen(value))); - } - - /// - /// Creates a instance from existing UTF-16 data, transcoding the - /// existing data to UTF-8 upon creation. - /// - /// The existing UTF-16 data from which to create a new . - /// - /// Thrown if does not represent well-formed UTF-16 data. - /// - /// - /// The UTF-16 data in is validated for well-formedness upon construction, - /// and an exception is thrown if the input is ill-formed. To avoid this exception, consider using - /// or . - /// - [MethodImpl(MethodImplOptions.InternalCall)] - public extern Utf8String(ReadOnlySpan value); - -#if !CORECLR - static -#endif - private Utf8String Ctor(ReadOnlySpan value) - { - Utf8String? newString = CreateFromUtf16Common(value, replaceInvalidSequences: false); - - if (newString is null) - { - // Input buffer contained invalid UTF-16 data. - - throw new ArgumentException( - message: SR.Utf8String_InputContainedMalformedUtf16, - paramName: nameof(value)); - } - - return newString; - } - - /// - /// Creates a instance from existing UTF-16 data. - /// - /// - /// Thrown if does not represent well-formed UTF-16 data. - /// - /// - /// The UTF-16 data in is validated for well-formedness upon construction, - /// and an exception is thrown if the input is ill-formed. To avoid this exception, consider using - /// or . - /// - [MethodImpl(MethodImplOptions.InternalCall)] - public extern Utf8String(char[] value, int startIndex, int length); - -#if !CORECLR - static -#endif - private Utf8String Ctor(char[] value, int startIndex, int length) - { - if (value is null) - { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); - } - - return Ctor(new ReadOnlySpan(value, startIndex, length)); - } - - /// - /// Creates a instance from existing null-terminated UTF-16 data. - /// - /// - /// Thrown if does not represent well-formed UTF-16 data. - /// - /// - /// The UTF-16 data in is validated for well-formedness upon construction, - /// and an exception is thrown if the input is ill-formed. To avoid this exception, consider using - /// or . - /// - [MethodImpl(MethodImplOptions.InternalCall)] - [CLSCompliant(false)] - public extern unsafe Utf8String(char* value); - -#if !CORECLR - static -#endif - private unsafe Utf8String Ctor(char* value) - { - if (value == null) - { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); - } - - return Ctor(new ReadOnlySpan(value, string.wcslen(value))); - } - - /// - /// Creates a instance from existing UTF-16 data. - /// - /// - /// The UTF-16 data in is validated for well-formedness upon construction, - /// and an exception is thrown if the input is ill-formed. To avoid this exception, consider using - /// or . - /// - [MethodImpl(MethodImplOptions.InternalCall)] - public extern Utf8String(string value); - -#if !CORECLR - static -#endif - private Utf8String Ctor(string value) - { - if (value is null) - { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); - } - - return Ctor(value.AsSpan()); - } - -#pragma warning restore CA1822 - - /* - * METHODS - */ - - /// - /// Similar to , but skips the null check on the input. - /// Throws a if the input is null. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal ReadOnlySpan AsBytesSkipNullCheck() - { - // By dereferencing Length first, the JIT will skip the null check that normally precedes - // most instance method calls, and it'll use the field dereference as the null check. - - int length = Length; - return new ReadOnlySpan(ref DangerousGetMutableReference(), length); - } - - /// - /// Returns a mutable that can be used to populate this - /// instance. Only to be used during construction. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal Span DangerousGetMutableSpan() - { - // By dereferencing Length first, the JIT will skip the null check that normally precedes - // most instance method calls, and it'll use the field dereference as the null check. - - int length = Length; - return new Span(ref DangerousGetMutableReference(), length); - } - - /// - /// Returns a mutable reference to the first byte of this - /// (or the null terminator if the string is empty). - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal ref byte DangerousGetMutableReference() => ref Unsafe.AsRef(in _firstByte); - - /// - /// Gets an immutable reference that can be used in a statement. The resulting - /// reference can be pinned and used as a null-terminated LPCUTF8STR. - /// - /// - /// If this instance is empty, returns a reference to the null terminator. - /// - [EditorBrowsable(EditorBrowsableState.Never)] // for compiler use only - public ref readonly byte GetPinnableReference() => ref _firstByte; - - /* - * HELPER METHODS - */ - - /// - /// Creates a new zero-initialized instance of the specified length. Actual storage allocated is "length + 1" bytes - /// because instances are null-terminated. - /// - /// - /// The implementation of this method checks its input argument for overflow. - /// - [MethodImpl(MethodImplOptions.InternalCall)] - private static extern Utf8String FastAllocate(int length); - } -} diff --git a/src/coreclr/src/classlibnative/bcltype/objectnative.cpp b/src/coreclr/src/classlibnative/bcltype/objectnative.cpp index 7af628a04e5cb..80023e27a9d81 100644 --- a/src/coreclr/src/classlibnative/bcltype/objectnative.cpp +++ b/src/coreclr/src/classlibnative/bcltype/objectnative.cpp @@ -236,9 +236,6 @@ FCIMPL1(Object*, ObjectNative::AllocateUninitializedClone, Object* pObjUNSAFE) // assert that String has overloaded the Clone() method _ASSERTE(pMT != g_pStringClass); -#ifdef FEATURE_UTF8STRING - _ASSERTE(pMT != g_pUtf8StringClass); -#endif // FEATURE_UTF8STRING if (pMT->IsArray()) { refClone = DupArrayForCloning((BASEARRAYREF)refClone); diff --git a/src/coreclr/src/inc/dacvars.h b/src/coreclr/src/inc/dacvars.h index 92f3edf77855b..9f2b5c96fae44 100644 --- a/src/coreclr/src/inc/dacvars.h +++ b/src/coreclr/src/inc/dacvars.h @@ -162,9 +162,6 @@ DEFINE_DACVAR(ULONG, UNKNOWN_POINTER_TYPE, dac__g_pObjectClass, ::g_pObjectClass DEFINE_DACVAR(ULONG, UNKNOWN_POINTER_TYPE, dac__g_pRuntimeTypeClass, ::g_pRuntimeTypeClass) DEFINE_DACVAR(ULONG, UNKNOWN_POINTER_TYPE, dac__g_pCanonMethodTableClass, ::g_pCanonMethodTableClass) DEFINE_DACVAR(ULONG, UNKNOWN_POINTER_TYPE, dac__g_pStringClass, ::g_pStringClass) -#ifdef FEATURE_UTF8STRING -DEFINE_DACVAR(ULONG, UNKNOWN_POINTER_TYPE, dac__g_pUtf8StringClass, ::g_pUtf8StringClass) -#endif // FEATURE_UTF8STRING DEFINE_DACVAR(ULONG, UNKNOWN_POINTER_TYPE, dac__g_pArrayClass, ::g_pArrayClass) DEFINE_DACVAR(ULONG, UNKNOWN_POINTER_TYPE, dac__g_pSZArrayHelperClass, ::g_pSZArrayHelperClass) DEFINE_DACVAR(ULONG, UNKNOWN_POINTER_TYPE, dac__g_pNullableClass, ::g_pNullableClass) diff --git a/src/coreclr/src/vm/appdomain.cpp b/src/coreclr/src/vm/appdomain.cpp index 1ba7c47cd50a1..f703b4214cea6 100644 --- a/src/coreclr/src/vm/appdomain.cpp +++ b/src/coreclr/src/vm/appdomain.cpp @@ -1517,11 +1517,6 @@ void SystemDomain::LoadBaseSystemClasses() // Load String g_pStringClass = CoreLibBinder::LoadPrimitiveType(ELEMENT_TYPE_STRING); -#ifdef FEATURE_UTF8STRING - // Load Utf8String - g_pUtf8StringClass = CoreLibBinder::GetClass(CLASS__UTF8_STRING); -#endif // FEATURE_UTF8STRING - #ifndef CROSSGEN_COMPILE ECall::PopulateManagedStringConstructors(); #endif // CROSSGEN_COMPILE diff --git a/src/coreclr/src/vm/classnames.h b/src/coreclr/src/vm/classnames.h index e2af51817f168..59e516d3e3a42 100644 --- a/src/coreclr/src/vm/classnames.h +++ b/src/coreclr/src/vm/classnames.h @@ -94,10 +94,6 @@ #define g_ThreadClassName "System.Threading.Thread" #define g_TypeClassName "System.Type" -#ifdef FEATURE_UTF8STRING -#define g_Utf8StringName "Utf8String" -#endif // FEATURE_UTF8STRING - #define g_VariantClassName "System.Variant" #define g_GuidClassName "System.Guid" diff --git a/src/coreclr/src/vm/common.h b/src/coreclr/src/vm/common.h index f01ec501bb67e..6694e74d8b485 100644 --- a/src/coreclr/src/vm/common.h +++ b/src/coreclr/src/vm/common.h @@ -162,9 +162,6 @@ typedef DPTR(class ReJitManager) PTR_ReJitManager; typedef DPTR(struct ReJitInfo) PTR_ReJitInfo; typedef DPTR(struct SharedReJitInfo) PTR_SharedReJitInfo; typedef DPTR(class StringObject) PTR_StringObject; -#ifdef FEATURE_UTF8STRING -typedef DPTR(class Utf8StringObject) PTR_Utf8StringObject; -#endif // FEATURE_UTF8STRING typedef DPTR(class TypeHandle) PTR_TypeHandle; typedef VPTR(class VirtualCallStubManager) PTR_VirtualCallStubManager; typedef VPTR(class VirtualCallStubManagerManager) PTR_VirtualCallStubManagerManager; diff --git a/src/coreclr/src/vm/corelib.h b/src/coreclr/src/vm/corelib.h index 21c8a6c4332ff..dbf514748420a 100644 --- a/src/coreclr/src/vm/corelib.h +++ b/src/coreclr/src/vm/corelib.h @@ -318,10 +318,6 @@ DEFINE_CLASS(ENCODING, Text, Encoding) DEFINE_CLASS(RUNE, Text, Rune) -#ifdef FEATURE_UTF8STRING -DEFINE_CLASS(CHAR8, System, Char8) -#endif // FEATURE_UTF8STRING - DEFINE_CLASS(ENUM, System, Enum) DEFINE_CLASS(ENVIRONMENT, System, Environment) @@ -847,17 +843,6 @@ DEFINE_METHOD(STRING, WCSLEN, wcslen, DEFINE_METHOD(STRING, STRLEN, strlen, SM_PtrByte_RetInt) DEFINE_PROPERTY(STRING, LENGTH, Length, Int) -#ifdef FEATURE_UTF8STRING -DEFINE_CLASS(UTF8_STRING, System, Utf8String) -DEFINE_METHOD(UTF8_STRING, CTORF_READONLYSPANOFBYTE,Ctor, IM_ReadOnlySpanOfByte_RetUtf8Str) -DEFINE_METHOD(UTF8_STRING, CTORF_READONLYSPANOFCHAR,Ctor, IM_ReadOnlySpanOfChar_RetUtf8Str) -DEFINE_METHOD(UTF8_STRING, CTORF_BYTEARRAY_START_LEN,Ctor, IM_ArrByte_Int_Int_RetUtf8Str) -DEFINE_METHOD(UTF8_STRING, CTORF_BYTEPTR, Ctor, IM_PtrByte_RetUtf8Str) -DEFINE_METHOD(UTF8_STRING, CTORF_CHARARRAY_START_LEN,Ctor, IM_ArrChar_Int_Int_RetUtf8Str) -DEFINE_METHOD(UTF8_STRING, CTORF_CHARPTR, Ctor, IM_PtrChar_RetUtf8Str) -DEFINE_METHOD(UTF8_STRING, CTORF_STRING, Ctor, IM_String_RetUtf8Str) -#endif // FEATURE_UTF8STRING - DEFINE_CLASS(STRING_BUILDER, Text, StringBuilder) DEFINE_PROPERTY(STRING_BUILDER, LENGTH, Length, Int) DEFINE_PROPERTY(STRING_BUILDER, CAPACITY, Capacity, Int) diff --git a/src/coreclr/src/vm/ecall.cpp b/src/coreclr/src/vm/ecall.cpp index a86d12c4b434a..5daa657f33a4d 100644 --- a/src/coreclr/src/vm/ecall.cpp +++ b/src/coreclr/src/vm/ecall.cpp @@ -84,30 +84,6 @@ static_assert_no_msg(ECallCtor_First + 8 == ECall::CtorSBytePtrStartLengthEncodi #define NumberOfStringConstructors 9 -#ifdef FEATURE_UTF8STRING -// METHOD__UTF8STRING__CTORF_XXX has to be in same order as ECall::Utf8StringCtorCharXxx -#define METHOD__UTF8STRING__CTORF_FIRST METHOD__UTF8_STRING__CTORF_READONLYSPANOFBYTE -static_assert_no_msg(METHOD__UTF8STRING__CTORF_FIRST + 0 == METHOD__UTF8_STRING__CTORF_READONLYSPANOFBYTE); -static_assert_no_msg(METHOD__UTF8STRING__CTORF_FIRST + 1 == METHOD__UTF8_STRING__CTORF_READONLYSPANOFCHAR); -static_assert_no_msg(METHOD__UTF8STRING__CTORF_FIRST + 2 == METHOD__UTF8_STRING__CTORF_BYTEARRAY_START_LEN); -static_assert_no_msg(METHOD__UTF8STRING__CTORF_FIRST + 3 == METHOD__UTF8_STRING__CTORF_BYTEPTR); -static_assert_no_msg(METHOD__UTF8STRING__CTORF_FIRST + 4 == METHOD__UTF8_STRING__CTORF_CHARARRAY_START_LEN); -static_assert_no_msg(METHOD__UTF8STRING__CTORF_FIRST + 5 == METHOD__UTF8_STRING__CTORF_CHARPTR); -static_assert_no_msg(METHOD__UTF8STRING__CTORF_FIRST + 6 == METHOD__UTF8_STRING__CTORF_STRING); - -// ECall::Utf8StringCtorCharXxx has to be in same order as METHOD__UTF8STRING__CTORF_XXX -#define ECallUtf8String_Ctor_First ECall::Utf8StringCtorReadOnlySpanOfByteManaged -static_assert_no_msg(ECallUtf8String_Ctor_First + 0 == ECall::Utf8StringCtorReadOnlySpanOfByteManaged); -static_assert_no_msg(ECallUtf8String_Ctor_First + 1 == ECall::Utf8StringCtorReadOnlySpanOfCharManaged); -static_assert_no_msg(ECallUtf8String_Ctor_First + 2 == ECall::Utf8StringCtorByteArrayStartLengthManaged); -static_assert_no_msg(ECallUtf8String_Ctor_First + 3 == ECall::Utf8StringCtorBytePtrManaged); -static_assert_no_msg(ECallUtf8String_Ctor_First + 4 == ECall::Utf8StringCtorCharArrayStartLengthManaged); -static_assert_no_msg(ECallUtf8String_Ctor_First + 5 == ECall::Utf8StringCtorCharPtrManaged); -static_assert_no_msg(ECallUtf8String_Ctor_First + 6 == ECall::Utf8StringCtorStringManaged); - -#define NumberOfUtf8StringConstructors 7 -#endif // FEATURE_UTF8STRING - void ECall::PopulateManagedStringConstructors() { STANDARD_VM_CONTRACT; @@ -126,19 +102,6 @@ void ECall::PopulateManagedStringConstructors() ECall::DynamicallyAssignFCallImpl(pDest, ECallCtor_First + i); } -#ifdef FEATURE_UTF8STRING - _ASSERTE(g_pUtf8StringClass != NULL); - for (int i = 0; i < NumberOfUtf8StringConstructors; i++) - { - MethodDesc* pMD = CoreLibBinder::GetMethod((BinderMethodID)(METHOD__UTF8STRING__CTORF_FIRST + i)); - _ASSERTE(pMD != NULL); - - PCODE pDest = pMD->GetMultiCallableAddrOfCode(); - - ECall::DynamicallyAssignFCallImpl(pDest, ECallUtf8String_Ctor_First + i); - } -#endif // FEATURE_UTF8STRING - INDEBUG(fInitialized = true); } diff --git a/src/coreclr/src/vm/ecall.h b/src/coreclr/src/vm/ecall.h index 19b8753828709..f1fedf2cbeb4e 100644 --- a/src/coreclr/src/vm/ecall.h +++ b/src/coreclr/src/vm/ecall.h @@ -118,21 +118,7 @@ class ECall DYNAMICALLY_ASSIGNED_FCALL_IMPL(CtorSBytePtrStartLengthEncodingManaged, NULL) \ DYNAMICALLY_ASSIGNED_FCALL_IMPL(InternalGetCurrentThread, NULL) \ -#define _DYNAMICALLY_ASSIGNED_FCALLS_UTF8STRING() \ - DYNAMICALLY_ASSIGNED_FCALL_IMPL(FastAllocateUtf8String, FramedAllocateUtf8String) \ - DYNAMICALLY_ASSIGNED_FCALL_IMPL(Utf8StringCtorReadOnlySpanOfByteManaged, NULL) \ - DYNAMICALLY_ASSIGNED_FCALL_IMPL(Utf8StringCtorReadOnlySpanOfCharManaged, NULL) \ - DYNAMICALLY_ASSIGNED_FCALL_IMPL(Utf8StringCtorByteArrayStartLengthManaged, NULL) \ - DYNAMICALLY_ASSIGNED_FCALL_IMPL(Utf8StringCtorBytePtrManaged, NULL) \ - DYNAMICALLY_ASSIGNED_FCALL_IMPL(Utf8StringCtorCharArrayStartLengthManaged, NULL) \ - DYNAMICALLY_ASSIGNED_FCALL_IMPL(Utf8StringCtorCharPtrManaged, NULL) \ - DYNAMICALLY_ASSIGNED_FCALL_IMPL(Utf8StringCtorStringManaged, NULL) \ - -#ifdef FEATURE_UTF8STRING -#define DYNAMICALLY_ASSIGNED_FCALLS() _DYNAMICALLY_ASSIGNED_FCALLS_BASE() _DYNAMICALLY_ASSIGNED_FCALLS_UTF8STRING() -#else #define DYNAMICALLY_ASSIGNED_FCALLS() _DYNAMICALLY_ASSIGNED_FCALLS_BASE() -#endif // FEATURE_UTF8STRING enum { diff --git a/src/coreclr/src/vm/ecalllist.h b/src/coreclr/src/vm/ecalllist.h index 2c8e41ac831e7..87389732f8d2e 100644 --- a/src/coreclr/src/vm/ecalllist.h +++ b/src/coreclr/src/vm/ecalllist.h @@ -111,19 +111,6 @@ FCFuncStart(gStringFuncs) FCFuncElement("Intern", AppDomainNative::GetOrInternString) FCFuncEnd() -#ifdef FEATURE_UTF8STRING -FCFuncStart(gUtf8StringFuncs) - FCDynamic("FastAllocate", CORINFO_INTRINSIC_Illegal, ECall::FastAllocateUtf8String) - FCDynamicSig(COR_CTOR_METHOD_NAME, &gsig_IM_ReadOnlySpanOfByte_RetVoid, CORINFO_INTRINSIC_Illegal, ECall::Utf8StringCtorReadOnlySpanOfByteManaged) - FCDynamicSig(COR_CTOR_METHOD_NAME, &gsig_IM_ReadOnlySpanOfChar_RetVoid, CORINFO_INTRINSIC_Illegal, ECall::Utf8StringCtorReadOnlySpanOfCharManaged) - FCDynamicSig(COR_CTOR_METHOD_NAME, &gsig_IM_ArrByte_Int_Int_RetVoid, CORINFO_INTRINSIC_Illegal, ECall::Utf8StringCtorByteArrayStartLengthManaged) - FCDynamicSig(COR_CTOR_METHOD_NAME, &gsig_IM_PtrByte_RetVoid, CORINFO_INTRINSIC_Illegal, ECall::Utf8StringCtorBytePtrManaged) - FCDynamicSig(COR_CTOR_METHOD_NAME, &gsig_IM_ArrChar_Int_Int_RetVoid, CORINFO_INTRINSIC_Illegal, ECall::Utf8StringCtorCharArrayStartLengthManaged) - FCDynamicSig(COR_CTOR_METHOD_NAME, &gsig_IM_PtrChar_RetVoid, CORINFO_INTRINSIC_Illegal, ECall::Utf8StringCtorCharPtrManaged) - FCDynamicSig(COR_CTOR_METHOD_NAME, &gsig_IM_Str_RetVoid, CORINFO_INTRINSIC_Illegal, ECall::Utf8StringCtorStringManaged) -FCFuncEnd() -#endif // FEATURE_UTF8STRING - FCFuncStart(gValueTypeFuncs) FCFuncElement("CanCompareBits", ValueTypeHelper::CanCompareBits) FCFuncElement("FastEqualsCheck", ValueTypeHelper::FastEqualsCheck) @@ -1219,9 +1206,6 @@ FCClassElement("TypeLoadException", "System", gTypeLoadExceptionFuncs) FCClassElement("TypeNameParser", "System", gTypeNameParser) FCClassElement("TypedReference", "System", gTypedReferenceFuncs) FCClassElement("UnmanagedThreadPoolWorkItem", "System.Threading", gUnmanagedThreadPoolWorkItemFuncs) -#ifdef FEATURE_UTF8STRING -FCClassElement("Utf8String", "System", gUtf8StringFuncs) -#endif // FEATURE_UTF8STRING FCClassElement("ValueType", "System", gValueTypeFuncs) #ifdef FEATURE_COMINTEROP FCClassElement("Variant", "System", gVariantFuncs) diff --git a/src/coreclr/src/vm/gchelpers.cpp b/src/coreclr/src/vm/gchelpers.cpp index d08a747839204..028e17b020d9b 100644 --- a/src/coreclr/src/vm/gchelpers.cpp +++ b/src/coreclr/src/vm/gchelpers.cpp @@ -869,55 +869,6 @@ STRINGREF AllocateString( DWORD cchStringLength ) return ObjectToSTRINGREF(orString); } -#ifdef FEATURE_UTF8STRING -UTF8STRINGREF AllocateUtf8String(DWORD cchStringLength) -{ - CONTRACTL{ - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; // returns an objref without pinning it => cooperative - } CONTRACTL_END; - -#ifdef _DEBUG - if (g_pConfig->ShouldInjectFault(INJECTFAULT_GCHEAP)) - { - char *a = new char; - delete a; - } -#endif - - // Limit the maximum string size to <2GB to mitigate risk of security issues caused by 32-bit integer - // overflows in buffer size calculations. - // - // 0x7FFFFFBF is derived from the const 0x3FFFFFDF in SlowAllocateString. - // Adding +1 (for null terminator) and multiplying by sizeof(WCHAR) means that - // SlowAllocateString allows a maximum of 0x7FFFFFC0 bytes to be used for the - // string data itself, with some additional buffer for object headers and other - // data. Since we don't have the sizeof(WCHAR) multiplication here, we only need - // -1 to account for the null terminator, leading to a max size of 0x7FFFFFBF. - if (cchStringLength > 0x7FFFFFBF) - ThrowOutOfMemory(); - - SIZE_T totalSize = PtrAlign(Utf8StringObject::GetSize(cchStringLength)); - _ASSERTE(totalSize > cchStringLength); - - SetTypeHandleOnThreadForAlloc(TypeHandle(g_pUtf8StringClass)); - - GC_ALLOC_FLAGS flags = GC_ALLOC_NO_FLAGS; - if (totalSize >= g_pConfig->GetGCLOHThreshold()) - flags |= GC_ALLOC_LARGE_OBJECT_HEAP; - - Utf8StringObject* orString = (Utf8StringObject*)Alloc(totalSize, flags); - - // Initialize Object - orString->SetMethodTable(g_pUtf8StringClass); - orString->SetLength(cchStringLength); - - PublishObjectAndNotify(orString, flags); - return ObjectToUTF8STRINGREF(orString); -} -#endif // FEATURE_UTF8STRING - #ifdef FEATURE_COMINTEROP_UNMANAGED_ACTIVATION // OBJECTREF AllocateComClassObject(ComClassFactory* pComClsFac) void AllocateComClassObject(ComClassFactory* pComClsFac, OBJECTREF* ppRefClass) diff --git a/src/coreclr/src/vm/gchelpers.h b/src/coreclr/src/vm/gchelpers.h index f9a9ac5320e29..794706c222674 100644 --- a/src/coreclr/src/vm/gchelpers.h +++ b/src/coreclr/src/vm/gchelpers.h @@ -36,10 +36,6 @@ OBJECTREF AllocateObjectArray(DWORD cElements, TypeHandle ElementType, BOOL bAll // Allocate a string STRINGREF AllocateString( DWORD cchStringLength ); -#ifdef FEATURE_UTF8STRING -UTF8STRINGREF AllocateUtf8String( DWORD cchStringLength ); -#endif // FEATURE_UTF8STRING - OBJECTREF DupArrayForCloning(BASEARRAYREF pRef); // The JIT requests the EE to specify an allocation helper to use at each new-site. diff --git a/src/coreclr/src/vm/jithelpers.cpp b/src/coreclr/src/vm/jithelpers.cpp index 0df65b9e6b8cf..c101e43575a72 100644 --- a/src/coreclr/src/vm/jithelpers.cpp +++ b/src/coreclr/src/vm/jithelpers.cpp @@ -2389,61 +2389,6 @@ HCIMPL1(StringObject*, AllocateString_MP_FastPortable, DWORD stringLength) } HCIMPLEND -#ifdef FEATURE_UTF8STRING -HCIMPL1(Utf8StringObject*, AllocateUtf8String_MP_FastPortable, DWORD stringLength) -{ - FCALL_CONTRACT; - - do - { - _ASSERTE(GCHeapUtilities::UseThreadAllocationContexts()); - - // Instead of doing elaborate overflow checks, we just limit the number of elements. This will avoid all overflow - // problems, as well as making sure big string objects are correctly allocated in the big object heap. - if (stringLength >= LARGE_OBJECT_SIZE - 256) - { - break; - } - - // This is typically the only call in the fast path. Making the call early seems to be better, as it allows the compiler - // to use volatile registers for intermediate values. This reduces the number of push/pop instructions and eliminates - // some reshuffling of intermediate values into nonvolatile registers around the call. - Thread *thread = GetThread(); - - SIZE_T totalSize = Utf8StringObject::GetSize(stringLength); - - // The method table's base size includes space for a terminating null character - _ASSERTE(totalSize >= g_pUtf8StringClass->GetBaseSize()); - _ASSERTE(totalSize - g_pUtf8StringClass->GetBaseSize() == stringLength); - - SIZE_T alignedTotalSize = ALIGN_UP(totalSize, DATA_ALIGNMENT); - _ASSERTE(alignedTotalSize >= totalSize); - totalSize = alignedTotalSize; - - gc_alloc_context *allocContext = thread->GetAllocContext(); - BYTE *allocPtr = allocContext->alloc_ptr; - _ASSERTE(allocPtr <= allocContext->alloc_limit); - if (totalSize > static_cast(allocContext->alloc_limit - allocPtr)) - { - break; - } - allocContext->alloc_ptr = allocPtr + totalSize; - - _ASSERTE(allocPtr != nullptr); - Utf8StringObject *stringObject = reinterpret_cast(allocPtr); - stringObject->SetMethodTable(g_pUtf8StringClass); - stringObject->SetLength(stringLength); - - return stringObject; - } while (false); - - // Tail call to the slow helper - ENDFORBIDGC(); - return HCCALL1(FramedAllocateUtf8String, stringLength); -} -HCIMPLEND -#endif // FEATURE_UTF8STRING - #include /*********************************************************************/ @@ -2482,22 +2427,6 @@ HCIMPL1(StringObject*, FramedAllocateString, DWORD stringLength) } HCIMPLEND -#ifdef FEATURE_UTF8STRING -HCIMPL1(Utf8StringObject*, FramedAllocateUtf8String, DWORD stringLength) -{ - FCALL_CONTRACT; - - UTF8STRINGREF result = NULL; - HELPER_METHOD_FRAME_BEGIN_RET_0(); // Set up a frame - - result = AllocateUtf8String(stringLength); - - HELPER_METHOD_FRAME_END(); - return((Utf8StringObject*) OBJECTREFToObject(result)); -} -HCIMPLEND -#endif // FEATURE_UTF8STRING - /*********************************************************************/ OBJECTHANDLE ConstructStringLiteral(CORINFO_MODULE_HANDLE scopeHnd, mdToken metaTok) { diff --git a/src/coreclr/src/vm/jitinterface.cpp b/src/coreclr/src/vm/jitinterface.cpp index b8274eb3344e7..ad5f9b12c1819 100644 --- a/src/coreclr/src/vm/jitinterface.cpp +++ b/src/coreclr/src/vm/jitinterface.cpp @@ -7399,9 +7399,6 @@ bool getILIntrinsicImplementationForRuntimeHelpers(MethodDesc * ftn, if (methodTable == CoreLibBinder::GetClass(CLASS__BOOLEAN) || methodTable == CoreLibBinder::GetClass(CLASS__BYTE) || methodTable == CoreLibBinder::GetClass(CLASS__SBYTE) -#ifdef FEATURE_UTF8STRING - || methodTable == CoreLibBinder::GetClass(CLASS__CHAR8) -#endif // FEATURE_UTF8STRING || methodTable == CoreLibBinder::GetClass(CLASS__CHAR) || methodTable == CoreLibBinder::GetClass(CLASS__INT16) || methodTable == CoreLibBinder::GetClass(CLASS__UINT16) diff --git a/src/coreclr/src/vm/jitinterface.h b/src/coreclr/src/vm/jitinterface.h index 0d2a720299a4f..ccdafd03e8726 100644 --- a/src/coreclr/src/vm/jitinterface.h +++ b/src/coreclr/src/vm/jitinterface.h @@ -203,11 +203,6 @@ extern FCDECL1(StringObject*, AllocateString_MP_FastPortable, DWORD stringLength extern FCDECL1(StringObject*, UnframedAllocateString, DWORD stringLength); extern FCDECL1(StringObject*, FramedAllocateString, DWORD stringLength); -#ifdef FEATURE_UTF8STRING -extern FCDECL1(Utf8StringObject*, AllocateUtf8String_MP_FastPortable, DWORD stringLength); -extern FCDECL1(Utf8StringObject*, FramedAllocateUtf8String, DWORD stringLength); -#endif // FEATURE_UTF8STRING - extern FCDECL2(Object*, JIT_NewArr1VC_MP_FastPortable, CORINFO_CLASS_HANDLE arrayMT, INT_PTR size); extern FCDECL2(Object*, JIT_NewArr1OBJ_MP_FastPortable, CORINFO_CLASS_HANDLE arrayMT, INT_PTR size); extern FCDECL2(Object*, JIT_NewArr1, CORINFO_CLASS_HANDLE arrayMT, INT_PTR size); diff --git a/src/coreclr/src/vm/jitinterfacegen.cpp b/src/coreclr/src/vm/jitinterfacegen.cpp index 661d68fa7d8d1..68ab56aeb96ef 100644 --- a/src/coreclr/src/vm/jitinterfacegen.cpp +++ b/src/coreclr/src/vm/jitinterfacegen.cpp @@ -79,9 +79,6 @@ void InitJITHelpers1() SetJitHelperFunction(CORINFO_HELP_NEWARR_1_OBJ, JIT_NewArr1OBJ_MP_FastPortable); ECall::DynamicallyAssignFCallImpl(GetEEFuncEntryPoint(AllocateString_MP_FastPortable), ECall::FastAllocateString); -#ifdef FEATURE_UTF8STRING - ECall::DynamicallyAssignFCallImpl(GetEEFuncEntryPoint(AllocateUtf8String_MP_FastPortable), ECall::FastAllocateUtf8String); -#endif // FEATURE_UTF8STRING #else // TARGET_UNIX // if (multi-proc || server GC) if (GCHeapUtilities::UseThreadAllocationContexts()) @@ -93,9 +90,6 @@ void InitJITHelpers1() SetJitHelperFunction(CORINFO_HELP_NEWARR_1_OBJ, JIT_NewArr1OBJ_MP_InlineGetThread); ECall::DynamicallyAssignFCallImpl(GetEEFuncEntryPoint(AllocateStringFastMP_InlineGetThread), ECall::FastAllocateString); -#ifdef FEATURE_UTF8STRING - ECall::DynamicallyAssignFCallImpl(GetEEFuncEntryPoint(AllocateUtf8String_MP_FastPortable), ECall::FastAllocateUtf8String); -#endif // FEATURE_UTF8STRING } else { @@ -110,9 +104,6 @@ void InitJITHelpers1() SetJitHelperFunction(CORINFO_HELP_NEWARR_1_OBJ, JIT_NewArr1OBJ_UP); ECall::DynamicallyAssignFCallImpl(GetEEFuncEntryPoint(AllocateStringFastUP), ECall::FastAllocateString); -#ifdef FEATURE_UTF8STRING - ECall::DynamicallyAssignFCallImpl(GetEEFuncEntryPoint(AllocateUtf8String_MP_FastPortable), ECall::FastAllocateUtf8String); -#endif // FEATURE_UTF8STRING } #endif // TARGET_UNIX } diff --git a/src/coreclr/src/vm/marshalnative.cpp b/src/coreclr/src/vm/marshalnative.cpp index a2e2295cf7fca..56d874c2ed780 100644 --- a/src/coreclr/src/vm/marshalnative.cpp +++ b/src/coreclr/src/vm/marshalnative.cpp @@ -236,11 +236,6 @@ FCIMPL1(FC_BOOL_RET, MarshalNative::IsPinnable, Object* obj) if (obj->GetMethodTable() == g_pStringClass) FC_RETURN_BOOL(TRUE); -#ifdef FEATURE_UTF8STRING - if (obj->GetMethodTable() == g_pUtf8StringClass) - FC_RETURN_BOOL(TRUE); -#endif // FEATURE_UTF8STRING - if (obj->GetMethodTable()->IsArray()) { BASEARRAYREF asArray = (BASEARRAYREF)ObjectToOBJECTREF(obj); @@ -456,11 +451,6 @@ void ValidatePinnedObject(OBJECTREF obj) if (obj->GetMethodTable() == g_pStringClass) return; -#ifdef FEATURE_UTF8STRING - if (obj->GetMethodTable() == g_pUtf8StringClass) - return; -#endif // FEATURE_UTF8STRING - if (obj->GetMethodTable()->IsArray()) { BASEARRAYREF asArray = (BASEARRAYREF) obj; diff --git a/src/coreclr/src/vm/metasig.h b/src/coreclr/src/vm/metasig.h index 03b2e457271b5..0714e0c50e209 100644 --- a/src/coreclr/src/vm/metasig.h +++ b/src/coreclr/src/vm/metasig.h @@ -414,16 +414,6 @@ DEFINE_METASIG(IM(Obj_Int_RetIntPtr, j i, I)) DEFINE_METASIG(IM(ArrByte_Int_Int_RetVoid, a(b) i i, v)) DEFINE_METASIG(IM(PtrByte_RetVoid, P(b), v)) -#ifdef FEATURE_UTF8STRING -DEFINE_METASIG_T(IM(ReadOnlySpanOfByte_RetUtf8Str, GI(g(READONLY_SPAN), 1, b), C(UTF8_STRING))) -DEFINE_METASIG_T(IM(ReadOnlySpanOfChar_RetUtf8Str, GI(g(READONLY_SPAN), 1, u), C(UTF8_STRING))) -DEFINE_METASIG_T(IM(ArrByte_Int_Int_RetUtf8Str, a(b) i i, C(UTF8_STRING))) -DEFINE_METASIG_T(IM(PtrByte_RetUtf8Str, P(b), C(UTF8_STRING))) -DEFINE_METASIG_T(IM(ArrChar_Int_Int_RetUtf8Str, a(u) i i, C(UTF8_STRING))) -DEFINE_METASIG_T(IM(PtrChar_RetUtf8Str, P(u), C(UTF8_STRING))) -DEFINE_METASIG_T(IM(String_RetUtf8Str, s, C(UTF8_STRING))) -#endif // FEATURE_UTF8STRING - DEFINE_METASIG(IM(Char_Char_RetStr, u u, s)) DEFINE_METASIG(IM(Char_Int_RetVoid, u i, v)) DEFINE_METASIG_T(SM(RetCultureInfo, _, C(CULTURE_INFO))) diff --git a/src/coreclr/src/vm/methodtablebuilder.cpp b/src/coreclr/src/vm/methodtablebuilder.cpp index ec07edc2b557b..5e09e619b9e8b 100644 --- a/src/coreclr/src/vm/methodtablebuilder.cpp +++ b/src/coreclr/src/vm/methodtablebuilder.cpp @@ -9770,19 +9770,6 @@ void MethodTableBuilder::CheckForSystemTypes() pMT->SetComponentSize(2); } -#ifdef FEATURE_UTF8STRING - else if (strcmp(name, g_Utf8StringName) == 0 && strcmp(nameSpace, g_SystemNS) == 0) - { - // Utf8Strings are not "normal" objects, so we need to mess with their method table a bit - // so that the GC can figure out how big each string is... - DWORD baseSize = Utf8StringObject::GetBaseSize(); - pMT->SetBaseSize(baseSize); // NULL character included - - GetHalfBakedClass()->SetBaseSizePadding(baseSize - bmtFP->NumInstanceFieldBytes); - - pMT->SetComponentSize(1); - } -#endif // FEATURE_UTF8STRING else if (strcmp(name, g_CriticalFinalizerObjectName) == 0 && strcmp(nameSpace, g_ConstrainedExecutionNS) == 0) { // To introduce a class with a critical finalizer, diff --git a/src/coreclr/src/vm/object.h b/src/coreclr/src/vm/object.h index 0604d6583401c..9f6bdf8562ad9 100644 --- a/src/coreclr/src/vm/object.h +++ b/src/coreclr/src/vm/object.h @@ -783,9 +783,6 @@ typedef DPTR(UPTRArray) PTR_UPTRArray; typedef DPTR(PTRArray) PTR_PTRArray; class StringObject; -#ifdef FEATURE_UTF8STRING -class Utf8StringObject; -#endif // FEATURE_UTF8STRING #ifdef USE_CHECKED_OBJECTREFS typedef REF BASEARRAYREF; @@ -804,9 +801,6 @@ typedef REF UPTRARRAYREF; typedef REF CHARARRAYREF; typedef REF PTRARRAYREF; // Warning: Use PtrArray only for single dimensional arrays, not multidim arrays. typedef REF STRINGREF; -#ifdef FEATURE_UTF8STRING -typedef REF UTF8STRINGREF; -#endif // FEATURE_UTF8STRING #else // USE_CHECKED_OBJECTREFS @@ -826,9 +820,6 @@ typedef PTR_UPTRArray UPTRARRAYREF; typedef PTR_CHARArray CHARARRAYREF; typedef PTR_PTRArray PTRARRAYREF; // Warning: Use PtrArray only for single dimensional arrays, not multidim arrays. typedef PTR_StringObject STRINGREF; -#ifdef FEATURE_UTF8STRING -typedef PTR_Utf8StringObject UTF8STRINGREF; -#endif // FEATURE_UTF8STRING #endif // USE_CHECKED_OBJECTREFS @@ -1067,56 +1058,6 @@ class ReflectClassBaseObject : public BaseObjectWithCachedData }; -#ifdef FEATURE_UTF8STRING -class Utf8StringObject : public Object -{ -#ifdef DACCESS_COMPILE - friend class ClrDataAccess; -#endif - -private: - DWORD m_StringLength; - BYTE m_FirstChar; - -public: - VOID SetLength(DWORD len) { LIMITED_METHOD_CONTRACT; _ASSERTE(len >= 0); m_StringLength = len; } - -protected: - Utf8StringObject() { LIMITED_METHOD_CONTRACT; } - ~Utf8StringObject() { LIMITED_METHOD_CONTRACT; } - -public: - - /*=================RefInterpretGetStringValuesDangerousForGC====================== - **N.B.: This perfoms no range checking and relies on the caller to have done this. - **Args: (IN)ref -- the Utf8String to be interpretted. - ** (OUT)chars -- a pointer to the characters in the buffer. - ** (OUT)length -- a pointer to the length of the buffer. - **Returns: void. - **Exceptions: None. - ==============================================================================*/ - // !!!! If you use this function, you have to be careful because chars is a pointer - // !!!! to the data buffer of ref. If GC happens after this call, you need to make - // !!!! sure that you have a pin handle on ref, or use GCPROTECT_BEGINPINNING on ref. - void RefInterpretGetStringValuesDangerousForGC(__deref_out_ecount(*length + 1) CHAR **chars, int *length) { - WRAPPER_NO_CONTRACT; - - _ASSERTE(GetGCSafeMethodTable() == g_pUtf8StringClass); - *length = GetStringLength(); - *chars = GetBuffer(); -#ifdef _DEBUG - EnableStressHeapHelper(); -#endif - } - - DWORD GetStringLength() { LIMITED_METHOD_DAC_CONTRACT; return( m_StringLength );} - CHAR* GetBuffer() { LIMITED_METHOD_CONTRACT; return (CHAR*)( dac_cast(this) + offsetof(Utf8StringObject, m_FirstChar) ); } - - static DWORD GetBaseSize(); - static SIZE_T GetSize(DWORD stringLength); -}; -#endif // FEATURE_UTF8STRING - // This is the Method version of the Reflection object. // A Method has adddition information. // m_pMD - A pointer to the actual MethodDesc of the method. diff --git a/src/coreclr/src/vm/object.inl b/src/coreclr/src/vm/object.inl index e82fdebfbeb50..e61f2eb443bab 100644 --- a/src/coreclr/src/vm/object.inl +++ b/src/coreclr/src/vm/object.inl @@ -60,22 +60,6 @@ __forceinline /*static*/ SIZE_T StringObject::GetSize(DWORD strLen) return GetBaseSize() + strLen * sizeof(WCHAR); } -#ifdef FEATURE_UTF8STRING -__forceinline /*static*/ DWORD Utf8StringObject::GetBaseSize() -{ - LIMITED_METHOD_DAC_CONTRACT; - - return OBJECT_BASESIZE + sizeof(DWORD) /* length */ + sizeof(BYTE) /* null terminator */; -} - -__forceinline /*static*/ SIZE_T Utf8StringObject::GetSize(DWORD strLen) -{ - LIMITED_METHOD_DAC_CONTRACT; - - return GetBaseSize() + strLen; -} -#endif // FEATURE_UTF8STRING - #ifdef DACCESS_COMPILE inline void Object::EnumMemoryRegions(void) diff --git a/src/coreclr/src/vm/reflectioninvocation.cpp b/src/coreclr/src/vm/reflectioninvocation.cpp index 0051a9345c892..3dfa8ca727739 100644 --- a/src/coreclr/src/vm/reflectioninvocation.cpp +++ b/src/coreclr/src/vm/reflectioninvocation.cpp @@ -2201,11 +2201,7 @@ FCIMPL1(Object*, ReflectionSerialization::GetUninitializedObject, ReflectClassBa PREFIX_ASSUME(pMT != NULL); //We don't allow unitialized Strings or Utf8Strings. - if (pMT == g_pStringClass -#ifdef FEATURE_UTF8STRING - || pMT == g_pUtf8StringClass -#endif // FEATURE_UTF8STRING - ) { + if (pMT == g_pStringClass) { COMPlusThrow(kArgumentException, W("Argument_NoUninitializedStrings")); } diff --git a/src/coreclr/src/vm/vars.cpp b/src/coreclr/src/vm/vars.cpp index b684583c7d970..152027b02032c 100644 --- a/src/coreclr/src/vm/vars.cpp +++ b/src/coreclr/src/vm/vars.cpp @@ -59,9 +59,6 @@ GPTR_IMPL(MethodTable, g_pObjectClass); GPTR_IMPL(MethodTable, g_pRuntimeTypeClass); GPTR_IMPL(MethodTable, g_pCanonMethodTableClass); // System.__Canon GPTR_IMPL(MethodTable, g_pStringClass); -#ifdef FEATURE_UTF8STRING -GPTR_IMPL(MethodTable, g_pUtf8StringClass); -#endif // FEATURE_UTF8STRING GPTR_IMPL(MethodTable, g_pArrayClass); GPTR_IMPL(MethodTable, g_pSZArrayHelperClass); GPTR_IMPL(MethodTable, g_pNullableClass); diff --git a/src/coreclr/src/vm/vars.hpp b/src/coreclr/src/vm/vars.hpp index 3b85c93adc5e1..88140bdc48635 100644 --- a/src/coreclr/src/vm/vars.hpp +++ b/src/coreclr/src/vm/vars.hpp @@ -73,9 +73,6 @@ class LoaderHeap; class IGCHeap; class Object; class StringObject; -#ifdef FEATURE_UTF8STRING -class Utf8StringObject; -#endif // FEATURE_UTF8STRING class ArrayClass; class MethodTable; class MethodDesc; @@ -309,10 +306,6 @@ class REF : public OBJECTREF #define OBJECTREFToObject(objref) ((objref).operator-> ()) #define ObjectToSTRINGREF(obj) (STRINGREF(obj)) #define STRINGREFToObject(objref) (*( (StringObject**) &(objref) )) -#ifdef FEATURE_UTF8STRING -#define ObjectToUTF8STRINGREF(obj) (UTF8STRINGREF(obj)) -#define UTF8STRINGREFToObject(objref) (*( (Utf8StringObject**) &(objref) )) -#endif // FEATURE_UTF8STRING #else // _DEBUG_IMPL @@ -323,10 +316,6 @@ class REF : public OBJECTREF #define OBJECTREFToObject(objref) ((PTR_Object) (objref)) #define ObjectToSTRINGREF(obj) ((PTR_StringObject) (obj)) #define STRINGREFToObject(objref) ((PTR_StringObject) (objref)) -#ifdef FEATURE_UTF8STRING -#define ObjectToUTF8STRINGREF(obj) ((PTR_Utf8StringObject) (obj)) -#define UTF8STRINGREFToObject(objref) ((PTR_Utf8StringObject) (objref)) -#endif // FEATURE_UTF8STRING #endif // _DEBUG_IMPL @@ -365,9 +354,6 @@ GPTR_DECL(MethodTable, g_pObjectClass); GPTR_DECL(MethodTable, g_pRuntimeTypeClass); GPTR_DECL(MethodTable, g_pCanonMethodTableClass); // System.__Canon GPTR_DECL(MethodTable, g_pStringClass); -#ifdef FEATURE_UTF8STRING -GPTR_DECL(MethodTable, g_pUtf8StringClass); -#endif // FEATURE_UTF8STRING GPTR_DECL(MethodTable, g_pArrayClass); GPTR_DECL(MethodTable, g_pSZArrayHelperClass); GPTR_DECL(MethodTable, g_pNullableClass); diff --git a/src/libraries/Directory.Build.props b/src/libraries/Directory.Build.props index b48551a1fba5b..1b5162d941c82 100644 --- a/src/libraries/Directory.Build.props +++ b/src/libraries/Directory.Build.props @@ -90,8 +90,6 @@ - - diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index 159721414fde2..53d63d973da1d 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -1954,24 +1954,4 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/src/libraries/System.Private.CoreLib/src/System/Char8.cs b/src/libraries/System.Private.CoreLib/src/System/Char8.cs deleted file mode 100644 index 9dfdbc81215a1..0000000000000 --- a/src/libraries/System.Private.CoreLib/src/System/Char8.cs +++ /dev/null @@ -1,68 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace System -{ - /// - /// Represents a UTF-8 code unit, the elemental type of . - /// - public readonly struct Char8 : IComparable, IEquatable - { - private readonly byte _value; - - private Char8(byte value) - { - _value = value; - } - - public static bool operator ==(Char8 left, Char8 right) => left._value == right._value; - public static bool operator !=(Char8 left, Char8 right) => left._value != right._value; - public static bool operator <(Char8 left, Char8 right) => left._value < right._value; - public static bool operator <=(Char8 left, Char8 right) => left._value <= right._value; - public static bool operator >(Char8 left, Char8 right) => left._value > right._value; - public static bool operator >=(Char8 left, Char8 right) => left._value >= right._value; - - // Operators from Utf8Char to - // TODO: Once C# gets support for checked operators, we should add those here. - - public static implicit operator byte(Char8 value) => value._value; - [CLSCompliant(false)] - public static explicit operator sbyte(Char8 value) => (sbyte)value._value; // explicit because can integer overflow - public static explicit operator char(Char8 value) => (char)value._value; // explicit because don't want to encourage char conversion - public static implicit operator short(Char8 value) => value._value; - [CLSCompliant(false)] - public static implicit operator ushort(Char8 value) => value._value; - public static implicit operator int(Char8 value) => value._value; - [CLSCompliant(false)] - public static implicit operator uint(Char8 value) => value._value; - public static implicit operator long(Char8 value) => value._value; - [CLSCompliant(false)] - public static implicit operator ulong(Char8 value) => value._value; - - // Operators from to Char8; most are explicit because narrowing conversions could be lossy - // TODO: Once C# gets support for checked operators, we should add those here. - - public static implicit operator Char8(byte value) => new Char8(value); - [CLSCompliant(false)] - public static explicit operator Char8(sbyte value) => new Char8((byte)value); - public static explicit operator Char8(char value) => new Char8((byte)value); - public static explicit operator Char8(short value) => new Char8((byte)value); - [CLSCompliant(false)] - public static explicit operator Char8(ushort value) => new Char8((byte)value); - public static explicit operator Char8(int value) => new Char8((byte)value); - [CLSCompliant(false)] - public static explicit operator Char8(uint value) => new Char8((byte)value); - public static explicit operator Char8(long value) => new Char8((byte)value); - [CLSCompliant(false)] - public static explicit operator Char8(ulong value) => new Char8((byte)value); - - public int CompareTo(Char8 other) => this._value.CompareTo(other._value); - - public override bool Equals(object? obj) => (obj is Char8 other) && (this == other); - public bool Equals(Char8 other) => this == other; - - public override int GetHashCode() => _value; - - public override string ToString() => _value.ToString("X2"); - } -} diff --git a/src/libraries/System.Private.CoreLib/src/System/Memory.cs b/src/libraries/System.Private.CoreLib/src/System/Memory.cs index c93dfc4baed17..531ec481e0446 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Memory.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Memory.cs @@ -166,9 +166,6 @@ internal Memory(object? obj, int start, int length) // 'obj is T[]' below also handles things like int[] <-> uint[] being convertible Debug.Assert((obj == null) || (typeof(T) == typeof(char) && obj is string) -#if FEATURE_UTF8STRING - || ((typeof(T) == typeof(byte) || typeof(T) == typeof(Char8)) && obj is Utf8String) -#endif // FEATURE_UTF8STRING || (obj is T[]) || (obj is MemoryManager)); @@ -218,14 +215,6 @@ public override string ToString() { return (_object is string str) ? str.Substring(_index, _length) : Span.ToString(); } -#if FEATURE_UTF8STRING - else if (typeof(T) == typeof(Char8)) - { - // TODO_UTF8STRING: Call into optimized transcoding routine when it's available. - Span span = Span; - return Encoding.UTF8.GetString(new ReadOnlySpan(ref Unsafe.As(ref MemoryMarshal.GetReference(span)), span.Length)); - } -#endif // FEATURE_UTF8STRING return string.Format("System.Memory<{0}>[{1}]", typeof(T).Name, _length); } @@ -302,13 +291,6 @@ public unsafe Span Span refToReturn = ref Unsafe.As(ref Unsafe.As(tmpObject).GetRawStringData()); lengthOfUnderlyingSpan = Unsafe.As(tmpObject).Length; } -#if FEATURE_UTF8STRING - else if ((typeof(T) == typeof(byte) || typeof(T) == typeof(Char8)) && tmpObject.GetType() == typeof(Utf8String)) - { - refToReturn = ref Unsafe.As(ref Unsafe.As(tmpObject).DangerousGetMutableReference()); - lengthOfUnderlyingSpan = Unsafe.As(tmpObject).Length; - } -#endif // FEATURE_UTF8STRING else if (RuntimeHelpers.ObjectHasComponentSize(tmpObject)) { // We know the object is not null, it's not a string, and it is variable-length. The only @@ -423,14 +405,6 @@ public unsafe MemoryHandle Pin() ref char stringData = ref Unsafe.Add(ref s.GetRawStringData(), _index); return new MemoryHandle(Unsafe.AsPointer(ref stringData), handle); } -#if FEATURE_UTF8STRING - else if ((typeof(T) == typeof(byte) || typeof(T) == typeof(Char8)) && tmpObject is Utf8String utf8String) - { - GCHandle handle = GCHandle.Alloc(tmpObject, GCHandleType.Pinned); - ref byte stringData = ref utf8String.DangerousGetMutableReference(_index); - return new MemoryHandle(Unsafe.AsPointer(ref stringData), handle); - } -#endif // FEATURE_UTF8STRING else if (RuntimeHelpers.ObjectHasComponentSize(tmpObject)) { // 'tmpObject is T[]' below also handles things like int[] <-> uint[] being convertible diff --git a/src/libraries/System.Private.CoreLib/src/System/ReadOnlyMemory.cs b/src/libraries/System.Private.CoreLib/src/System/ReadOnlyMemory.cs index e26612c07ef67..105273a664921 100644 --- a/src/libraries/System.Private.CoreLib/src/System/ReadOnlyMemory.cs +++ b/src/libraries/System.Private.CoreLib/src/System/ReadOnlyMemory.cs @@ -101,9 +101,6 @@ internal ReadOnlyMemory(object? obj, int start, int length) // 'obj is T[]' below also handles things like int[] <-> uint[] being convertible Debug.Assert((obj == null) || (typeof(T) == typeof(char) && obj is string) -#if FEATURE_UTF8STRING - || ((typeof(T) == typeof(byte) || typeof(T) == typeof(Char8)) && obj is Utf8String) -#endif // FEATURE_UTF8STRING || (obj is T[]) || (obj is MemoryManager)); @@ -147,14 +144,6 @@ public override string ToString() { return (_object is string str) ? str.Substring(_index, _length) : Span.ToString(); } -#if FEATURE_UTF8STRING - else if (typeof(T) == typeof(Char8)) - { - // TODO_UTF8STRING: Call into optimized transcoding routine when it's available. - ReadOnlySpan span = Span; - return Encoding.UTF8.GetString(new ReadOnlySpan(ref Unsafe.As(ref MemoryMarshal.GetReference(span)), span.Length)); - } -#endif // FEATURE_UTF8STRING return string.Format("System.ReadOnlyMemory<{0}>[{1}]", typeof(T).Name, _length); } @@ -224,13 +213,6 @@ public unsafe ReadOnlySpan Span refToReturn = ref Unsafe.As(ref Unsafe.As(tmpObject).GetRawStringData()); lengthOfUnderlyingSpan = Unsafe.As(tmpObject).Length; } -#if FEATURE_UTF8STRING - else if ((typeof(T) == typeof(byte) || typeof(T) == typeof(Char8)) && tmpObject.GetType() == typeof(Utf8String)) - { - refToReturn = ref Unsafe.As(ref Unsafe.As(tmpObject).DangerousGetMutableReference()); - lengthOfUnderlyingSpan = Unsafe.As(tmpObject).Length; - } -#endif // FEATURE_UTF8STRING else if (RuntimeHelpers.ObjectHasComponentSize(tmpObject)) { // We know the object is not null, it's not a string, and it is variable-length. The only @@ -338,14 +320,6 @@ public unsafe MemoryHandle Pin() ref char stringData = ref Unsafe.Add(ref s.GetRawStringData(), _index); return new MemoryHandle(Unsafe.AsPointer(ref stringData), handle); } -#if FEATURE_UTF8STRING - else if ((typeof(T) == typeof(byte) || typeof(T) == typeof(Char8)) && tmpObject is Utf8String utf8String) - { - GCHandle handle = GCHandle.Alloc(tmpObject, GCHandleType.Pinned); - ref byte stringData = ref utf8String.DangerousGetMutableReference(_index); - return new MemoryHandle(Unsafe.AsPointer(ref stringData), handle); - } -#endif // FEATURE_UTF8STRING else if (RuntimeHelpers.ObjectHasComponentSize(tmpObject)) { // 'tmpObject is T[]' below also handles things like int[] <-> uint[] being convertible diff --git a/src/libraries/System.Private.CoreLib/src/System/ReadOnlySpan.cs b/src/libraries/System.Private.CoreLib/src/System/ReadOnlySpan.cs index 465fc78674df5..38fea0090ca9a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/ReadOnlySpan.cs +++ b/src/libraries/System.Private.CoreLib/src/System/ReadOnlySpan.cs @@ -319,13 +319,6 @@ public override string ToString() { return new string(new ReadOnlySpan(ref Unsafe.As(ref _pointer.Value), _length)); } -#if FEATURE_UTF8STRING - else if (typeof(T) == typeof(Char8)) - { - // TODO_UTF8STRING: Call into optimized transcoding routine when it's available. - return Encoding.UTF8.GetString(new ReadOnlySpan(ref Unsafe.As(ref _pointer.Value), _length)); - } -#endif // FEATURE_UTF8STRING return string.Format("System.ReadOnlySpan<{0}>[{1}]", typeof(T).Name, _length); } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/MemoryMarshal.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/MemoryMarshal.cs index 83e0d7db3b33b..3a76f44da15fb 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/MemoryMarshal.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/MemoryMarshal.cs @@ -245,9 +245,6 @@ public static bool TryGetArray(ReadOnlyMemory memory, out ArraySegment if (obj != null && !( (typeof(T) == typeof(char) && obj.GetType() == typeof(string)) -#if FEATURE_UTF8STRING - || ((typeof(T) == typeof(byte) || typeof(T) == typeof(Char8)) && obj.GetType() == typeof(Utf8String)) -#endif // FEATURE_UTF8STRING )) { if (RuntimeHelpers.ObjectHasComponentSize(obj)) diff --git a/src/libraries/System.Private.CoreLib/src/System/Span.cs b/src/libraries/System.Private.CoreLib/src/System/Span.cs index 735380233d9a3..e82ca80a44a54 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Span.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Span.cs @@ -399,13 +399,6 @@ public override string ToString() { return new string(new ReadOnlySpan(ref Unsafe.As(ref _pointer.Value), _length)); } -#if FEATURE_UTF8STRING - else if (typeof(T) == typeof(Char8)) - { - // TODO_UTF8STRING: Call into optimized transcoding routine when it's available. - return Encoding.UTF8.GetString(new ReadOnlySpan(ref Unsafe.As(ref _pointer.Value), _length)); - } -#endif // FEATURE_UTF8STRING return string.Format("System.Span<{0}>[{1}]", typeof(T).Name, _length); } diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/Unicode/Utf8Utility.cs b/src/libraries/System.Private.CoreLib/src/System/Text/Unicode/Utf8Utility.cs index 2ecb58c3782b2..91db035d8ef53 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Text/Unicode/Utf8Utility.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Text/Unicode/Utf8Utility.cs @@ -49,102 +49,5 @@ public static unsafe int GetIndexOfFirstInvalidUtf8Sequence(ReadOnlySpan u } } -#if FEATURE_UTF8STRING - /// - /// Returns a value stating whether contains only well-formed UTF-8 data. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static unsafe bool IsWellFormedUtf8(ReadOnlySpan utf8Data) - { - fixed (byte* pUtf8Data = &MemoryMarshal.GetReference(utf8Data)) - { - // The return value here will point to the end of the span if the data is well-formed. - byte* pFirstInvalidByte = GetPointerToFirstInvalidByte(pUtf8Data, utf8Data.Length, out int _, out _); - return (pFirstInvalidByte == (pUtf8Data + (uint)utf8Data.Length)); - } - } - - /// - /// Returns if it is null or contains only well-formed UTF-8 data; - /// otherwises allocates a new instance containing the same data as - /// but where all invalid UTF-8 sequences have been replaced - /// with U+FFFD. - /// - public static Utf8String ValidateAndFixupUtf8String(Utf8String value) - { - if (value.Length == 0) - { - return value; - } - - ReadOnlySpan valueAsBytes = value.AsBytes(); - - int idxOfFirstInvalidData = GetIndexOfFirstInvalidUtf8Sequence(valueAsBytes, out _); - if (idxOfFirstInvalidData < 0) - { - return value; - } - - // TODO_UTF8STRING: Replace this with the faster implementation once it's available. - // (The faster implementation is in the dev/utf8string_bak branch currently.) - - MemoryStream memStream = new MemoryStream(); -#if (!NETSTANDARD2_0 && !NETFRAMEWORK) - memStream.Write(valueAsBytes.Slice(0, idxOfFirstInvalidData)); - - valueAsBytes = valueAsBytes.Slice(idxOfFirstInvalidData); - do - { - if (Rune.DecodeFromUtf8(valueAsBytes, out _, out int bytesConsumed) == OperationStatus.Done) - { - // Valid scalar value - copy data as-is to MemoryStream - memStream.Write(valueAsBytes.Slice(0, bytesConsumed)); - } - else - { - // Invalid scalar value - copy U+FFFD to MemoryStream - memStream.Write(ReplacementCharSequence); - } - - valueAsBytes = valueAsBytes.Slice(bytesConsumed); - } while (!valueAsBytes.IsEmpty); -#else - if (!MemoryMarshal.TryGetArray(value.AsMemoryBytes(), out ArraySegment valueArraySegment)) - { - Debug.Fail("Utf8String on netstandard should always be backed by an array."); - } - - memStream.Write(valueArraySegment.Array, valueArraySegment.Offset, idxOfFirstInvalidData); - - valueArraySegment = new ArraySegment( - valueArraySegment.Array, - idxOfFirstInvalidData, - valueArraySegment.Count - idxOfFirstInvalidData); - do - { - if (Rune.DecodeFromUtf8(valueArraySegment, out _, out int bytesConsumed) == OperationStatus.Done) - { - // Valid scalar value - copy data as-is to MemoryStream - memStream.Write(valueArraySegment.Array, valueArraySegment.Offset, bytesConsumed); - } - else - { - // Invalid scalar value - copy U+FFFD to MemoryStream - memStream.Write(ReplacementCharSequence, 0, ReplacementCharSequence.Length); - } - - valueArraySegment = new ArraySegment( - valueArraySegment.Array, - valueArraySegment.Offset + bytesConsumed, - valueArraySegment.Count - bytesConsumed); - } while (valueArraySegment.Count > 0); -#endif - - bool success = memStream.TryGetBuffer(out ArraySegment memStreamBuffer); - Debug.Assert(success, "Couldn't get underlying MemoryStream buffer."); - - return Utf8String.UnsafeCreateWithoutValidation(memStreamBuffer); - } -#endif // FEATURE_UTF8STRING } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/Utf8Span.Comparison.cs b/src/libraries/System.Private.CoreLib/src/System/Text/Utf8Span.Comparison.cs deleted file mode 100644 index ed42f474ee8a4..0000000000000 --- a/src/libraries/System.Private.CoreLib/src/System/Text/Utf8Span.Comparison.cs +++ /dev/null @@ -1,231 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Text.Unicode; - -namespace System.Text -{ - public readonly ref partial struct Utf8Span - { - public static bool operator ==(Utf8Span left, Utf8Span right) => Equals(left, right); - public static bool operator !=(Utf8Span left, Utf8Span right) => !Equals(left, right); - - public int CompareTo(Utf8Span other) - { - // TODO_UTF8STRING: This is ordinal, but String.CompareTo uses CurrentCulture. - // Is this acceptable? - - return Utf8StringComparer.Ordinal.Compare(this, other); - } - - public int CompareTo(Utf8Span other, StringComparison comparison) - { - // TODO_UTF8STRING: We can avoid the virtual dispatch by moving the switch into this method. - - return Utf8StringComparer.FromComparison(comparison).Compare(this, other); - } - - /// - /// Returns a value stating whether the current instance contains - /// . An ordinal comparison is used. - /// - public bool Contains(char value) - { - return Rune.TryCreate(value, out Rune rune) && Contains(rune); - } - - /// - /// Returns a value stating whether the current instance contains - /// . The specified comparison is used. - /// - public bool Contains(char value, StringComparison comparison) - { - return Rune.TryCreate(value, out Rune rune) && Contains(rune, comparison); - } - - /// - /// Returns a value stating whether the current instance contains - /// the specified . An ordinal comparison is used. - /// - public bool Contains(Rune value) - { - // TODO_UTF8STRING: This should be split into two methods: - // One which operates on a single-byte (ASCII) search value, - // the other which operates on a multi-byte (non-ASCII) search value. - - Span runeBytes = stackalloc byte[Utf8Utility.MaxBytesPerScalar]; - int runeBytesWritten = value.EncodeToUtf8(runeBytes); - - return (this.Bytes.IndexOf(runeBytes.Slice(0, runeBytesWritten)) >= 0); - } - - /// - /// Returns a value stating whether the current instance contains - /// the specified . The specified comparison is used. - /// - public bool Contains(Rune value, StringComparison comparison) - { - // TODO_UTF8STRING: Optimize me to avoid allocations. - -#if (!NETSTANDARD2_0 && !NETFRAMEWORK) - return this.ToString().Contains(value.ToString(), comparison); -#else - return this.ToString().IndexOf(value.ToString(), comparison) >= 0; -#endif - } - - /// - /// Returns a value stating whether the current instance contains . - /// An ordinal comparison is used. - /// - public bool Contains(Utf8Span value) - { - return (this.Bytes.IndexOf(value.Bytes) >= 0); - } - - /// - /// Returns a value stating whether the current instance contains . - /// The specified comparison is used. - /// - public bool Contains(Utf8Span value, StringComparison comparison) - { - // TODO_UTF8STRING: Optimize me to avoid allocations. - -#if (!NETSTANDARD2_0 && !NETFRAMEWORK) - return this.ToString().Contains(value.ToString(), comparison); -#else - return this.ToString().IndexOf(value.ToString(), comparison) >= 0; -#endif - } - - /// - /// Returns a value stating whether the current instance ends with - /// . An ordinal comparison is used. - /// - public bool EndsWith(char value) - { - return Rune.TryCreate(value, out Rune rune) && EndsWith(rune); - } - - /// - /// Returns a value stating whether the current instance ends with - /// . The specified comparison is used. - /// - public bool EndsWith(char value, StringComparison comparison) - { - return Rune.TryCreate(value, out Rune rune) && EndsWith(rune, comparison); - } - - /// - /// Returns a value stating whether the current instance ends with - /// the specified . An ordinal comparison is used. - /// - public bool EndsWith(Rune value) - { - // TODO_UTF8STRING: This should be split into two methods: - // One which operates on a single-byte (ASCII) search value, - // the other which operates on a multi-byte (non-ASCII) search value. - - Span runeBytes = stackalloc byte[Utf8Utility.MaxBytesPerScalar]; - int runeBytesWritten = value.EncodeToUtf8(runeBytes); - - return this.Bytes.EndsWith(runeBytes.Slice(0, runeBytesWritten)); - } - - /// - /// Returns a value stating whether the current instance ends with - /// the specified . The specified comparison is used. - /// - public bool EndsWith(Rune value, StringComparison comparison) - { - // TODO_UTF8STRING: Optimize me to avoid allocations. - - return this.ToString().EndsWith(value.ToString(), comparison); - } - - /// - /// Returns a value stating whether the current instance ends with . - /// An ordinal comparison is used. - /// - public bool EndsWith(Utf8Span value) - { - return this.Bytes.EndsWith(value.Bytes); - } - - /// - /// Returns a value stating whether the current instance ends with . - /// The specified comparison is used. - /// - public bool EndsWith(Utf8Span value, StringComparison comparison) - { - // TODO_UTF8STRING: Optimize me to avoid allocations. - - return this.ToString().EndsWith(value.ToString(), comparison); - } - - /// - /// Returns a value stating whether the current instance begins with - /// . An ordinal comparison is used. - /// - public bool StartsWith(char value) - { - return Rune.TryCreate(value, out Rune rune) && StartsWith(rune); - } - - /// - /// Returns a value stating whether the current instance begins with - /// . The specified comparison is used. - /// - public bool StartsWith(char value, StringComparison comparison) - { - return Rune.TryCreate(value, out Rune rune) && StartsWith(rune, comparison); - } - - /// - /// Returns a value stating whether the current instance begins with - /// the specified . An ordinal comparison is used. - /// - public bool StartsWith(Rune value) - { - // TODO_UTF8STRING: This should be split into two methods: - // One which operates on a single-byte (ASCII) search value, - // the other which operates on a multi-byte (non-ASCII) search value. - - Span runeBytes = stackalloc byte[Utf8Utility.MaxBytesPerScalar]; - int runeBytesWritten = value.EncodeToUtf8(runeBytes); - - return this.Bytes.StartsWith(runeBytes.Slice(0, runeBytesWritten)); - } - - /// - /// Returns a value stating whether the current instance begins with - /// the specified . The specified comparison is used. - /// - public bool StartsWith(Rune value, StringComparison comparison) - { - // TODO_UTF8STRING: Optimize me to avoid allocations. - - return this.ToString().StartsWith(value.ToString(), comparison); - } - - /// - /// Returns a value stating whether the current instance begins with . - /// An ordinal comparison is used. - /// - public bool StartsWith(Utf8Span value) - { - return this.Bytes.StartsWith(value.Bytes); - } - - /// - /// Returns a value stating whether the current instance begins with . - /// The specified comparison is used. - /// - public bool StartsWith(Utf8Span value, StringComparison comparison) - { - // TODO_UTF8STRING: Optimize me to avoid allocations. - - return this.ToString().StartsWith(value.ToString(), comparison); - } - } -} diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/Utf8Span.Conversion.cs b/src/libraries/System.Private.CoreLib/src/System/Text/Utf8Span.Conversion.cs deleted file mode 100644 index 23535043af544..0000000000000 --- a/src/libraries/System.Private.CoreLib/src/System/Text/Utf8Span.Conversion.cs +++ /dev/null @@ -1,325 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Buffers; -using System.Diagnostics; -using System.Globalization; -using System.Runtime.InteropServices; -using System.Text.Unicode; - -namespace System.Text -{ - public readonly ref partial struct Utf8Span - { - /// - /// Returns a new instance which represents this instance - /// normalized using the specified Unicode normalization form. - /// - /// - /// The original is left unchanged by this operation. - /// - public Utf8String Normalize(NormalizationForm normalizationForm = NormalizationForm.FormC) - { - // TODO_UTF8STRING: Reduce allocations in this code path. - - return new Utf8String(this.ToString().Normalize(normalizationForm)); - } - - /// - /// Converts this to the desired Unicode normalization form, writing the - /// UTF-8 result to the buffer . - /// - /// - /// The number of bytes written to , or -1 if - /// is not large enough to hold the result of the normalization operation. - /// - /// - /// The original is left unchanged by this operation. Note that the the required - /// length of may be longer or shorter (in terms of UTF-8 byte count) - /// than the input . - /// - public int Normalize(Span destination, NormalizationForm normalizationForm = NormalizationForm.FormC) - { - // TODO_UTF8STRING: Reduce allocations in this code path. - - ReadOnlySpan normalized = this.ToString().Normalize(normalizationForm).AsSpan(); - OperationStatus status = Utf8.FromUtf16(normalized, destination, out int _, out int bytesWritten, replaceInvalidSequences: false, isFinalBlock: true); - - Debug.Assert(status == OperationStatus.Done || status == OperationStatus.DestinationTooSmall, "Normalize shouldn't have produced malformed Unicode string."); - - if (status != OperationStatus.Done) - { - bytesWritten = -1; // "destination too small" - } - - return bytesWritten; - } - - /// - /// Returns the entire as an array of UTF-8 bytes. - /// - public byte[] ToByteArray() => Bytes.ToArray(); - - /// - /// Converts this to a . - /// - public unsafe char[] ToCharArray() - { - if (IsEmpty) - { - return Array.Empty(); - } - - // TODO_UTF8STRING: Since we know the underlying data is immutable, well-formed UTF-8, - // we can perform transcoding using an optimized code path that skips all safety checks. - // We should also consider skipping the two-pass if possible. - - fixed (byte* pbUtf8 = &DangerousGetMutableReference()) - { - byte* pbUtf8Invalid = Utf8Utility.GetPointerToFirstInvalidByte(pbUtf8, this.Length, out int utf16CodeUnitCountAdjustment, out _); - Debug.Assert(pbUtf8Invalid == pbUtf8 + this.Length, "Invalid UTF-8 data seen in buffer."); - - char[] asUtf16 = new char[this.Length + utf16CodeUnitCountAdjustment]; - fixed (char* pbUtf16 = asUtf16) - { - OperationStatus status = Utf8Utility.TranscodeToUtf16(pbUtf8, this.Length, pbUtf16, asUtf16.Length, out byte* pbUtf8End, out char* pchUtf16End); - Debug.Assert(status == OperationStatus.Done, "The buffer changed out from under us unexpectedly?"); - Debug.Assert(pbUtf8End == pbUtf8 + this.Length, "The buffer changed out from under us unexpectedly?"); - Debug.Assert(pchUtf16End == pbUtf16 + asUtf16.Length, "The buffer changed out from under us unexpectedly?"); - - return asUtf16; - } - } - } - - /// - /// Converts this instance to its UTF-16 equivalent, writing the result into - /// the buffer . - /// - /// - /// The number of bytes written to , or -1 if - /// is not large enough to hold the result of the transcoding operation. - /// - public int ToChars(Span destination) - { - OperationStatus status = Utf8.ToUtf16(Bytes, destination, out int _, out int charsWritten, replaceInvalidSequences: false, isFinalBlock: true); - - Debug.Assert(status == OperationStatus.Done || status == OperationStatus.DestinationTooSmall, "Utf8Spans shouldn't contain ill-formed UTF-8 data."); - - if (status != OperationStatus.Done) - { - charsWritten = -1; // "destination too small" - } - - return charsWritten; - } - - /// - /// Returns a new instance which represents this instance - /// converted to lowercase using . - /// - /// - /// The original is left unchanged by this operation. Note that the returned - /// instance may be longer or shorter (in terms of UTF-8 byte count) than the - /// input . - /// - public Utf8String ToLower(CultureInfo culture) - { - // TODO_UTF8STRING: Avoid intermediate allocations. - - if (culture is null) - { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.culture); - } - - return new Utf8String(this.ToString().ToLower(culture)); - } - - /// - /// Converts this to lowercase using , writing the - /// UTF-8 result to the buffer . - /// - /// - /// The number of bytes written to , or -1 if - /// is not large enough to hold the result of the case conversion operation. - /// - /// - /// The original is left unchanged by this operation. Note that the the required - /// length of may be longer or shorter (in terms of UTF-8 byte count) - /// than the input . - /// - public int ToLower(Span destination, CultureInfo culture) - { - // TODO_UTF8STRING: Avoid intermediate allocations. - - if (culture is null) - { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.culture); - } - - ReadOnlySpan asLower = this.ToString().ToLower(culture).AsSpan(); - OperationStatus status = Utf8.FromUtf16(asLower, destination, out int _, out int bytesWritten, replaceInvalidSequences: false, isFinalBlock: true); - - Debug.Assert(status == OperationStatus.Done || status == OperationStatus.DestinationTooSmall, "ToLower shouldn't have produced malformed Unicode string."); - - if (status != OperationStatus.Done) - { - bytesWritten = -1; // "destination too small" - } - - return bytesWritten; - } - - /// - /// Returns a new instance which represents this instance - /// converted to lowercase using the invariant culture. - /// - /// - /// The original is left unchanged by this operation. For more information on the - /// invariant culture, see the property. Note that the returned - /// instance may be longer or shorter (in terms of UTF-8 byte count) than the - /// input . - /// - public Utf8String ToLowerInvariant() - { - // TODO_UTF8STRING: Avoid intermediate allocations. - - return new Utf8String(this.ToString().ToLowerInvariant()); - } - - /// - /// Converts this to lowercase using the invariant culture, writing the - /// UTF-8 result to the buffer . - /// - /// - /// The number of bytes written to , or -1 if - /// is not large enough to hold the result of the case conversion operation. - /// - /// - /// The original is left unchanged by this operation. For more information on the - /// invariant culture, see the property. Note that the the required - /// length of may be longer or shorter (in terms of UTF-8 byte count) - /// than the input . - /// - public int ToLowerInvariant(Span destination) - { - // TODO_UTF8STRING: Avoid intermediate allocations. - - ReadOnlySpan asLowerInvariant = this.ToString().ToLowerInvariant().AsSpan(); - OperationStatus status = Utf8.FromUtf16(asLowerInvariant, destination, out int _, out int bytesWritten, replaceInvalidSequences: false, isFinalBlock: true); - - Debug.Assert(status == OperationStatus.Done || status == OperationStatus.DestinationTooSmall, "ToLowerInvariant shouldn't have produced malformed Unicode string."); - - if (status != OperationStatus.Done) - { - bytesWritten = -1; // "destination too small" - } - - return bytesWritten; - } - - /// - /// Returns a new instance which represents this instance - /// converted to uppercase using . - /// - /// - /// The original is left unchanged by this operation. Note that the returned - /// instance may be longer or shorter (in terms of UTF-8 byte count) than the - /// input . - /// - public Utf8String ToUpper(CultureInfo culture) - { - // TODO_UTF8STRING: Avoid intermediate allocations. - - if (culture is null) - { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.culture); - } - - return new Utf8String(this.ToString().ToUpper(culture)); - } - - /// - /// Converts this to uppercase using , writing the - /// UTF-8 result to the buffer . - /// - /// - /// The number of bytes written to , or -1 if - /// is not large enough to hold the result of the case conversion operation. - /// - /// - /// The original is left unchanged by this operation. Note that the the required - /// length of may be longer or shorter (in terms of UTF-8 byte count) - /// than the input . - /// - public int ToUpper(Span destination, CultureInfo culture) - { - // TODO_UTF8STRING: Avoid intermediate allocations. - - if (culture is null) - { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.culture); - } - - ReadOnlySpan asUpper = this.ToString().ToUpper(culture).AsSpan(); - OperationStatus status = Utf8.FromUtf16(asUpper, destination, out int _, out int bytesWritten, replaceInvalidSequences: false, isFinalBlock: true); - - Debug.Assert(status == OperationStatus.Done || status == OperationStatus.DestinationTooSmall, "ToUpper shouldn't have produced malformed Unicode string."); - - if (status != OperationStatus.Done) - { - bytesWritten = -1; // "destination too small" - } - - return bytesWritten; - } - - /// - /// Returns a new instance which represents this instance - /// converted to uppercase using the invariant culture. - /// - /// - /// The original is left unchanged by this operation. For more information on the - /// invariant culture, see the property. Note that the returned - /// instance may be longer or shorter (in terms of UTF-8 byte count) than the - /// input . - /// - public Utf8String ToUpperInvariant() - { - // TODO_UTF8STRING: Avoid intermediate allocations. - - return new Utf8String(this.ToString().ToUpperInvariant()); - } - - /// - /// Converts this to uppercase using the invariant culture, writing the - /// UTF-8 result to the buffer . - /// - /// - /// The number of bytes written to , or -1 if - /// is not large enough to hold the result of the case conversion operation. - /// - /// - /// The original is left unchanged by this operation. For more information on the - /// invariant culture, see the property. Note that the the required - /// length of may be longer or shorter (in terms of UTF-8 byte count) - /// than the input . - /// - public int ToUpperInvariant(Span destination) - { - // TODO_UTF8STRING: Avoid intermediate allocations. - - ReadOnlySpan asUpperInvariant = this.ToString().ToUpperInvariant().AsSpan(); - OperationStatus status = Utf8.FromUtf16(asUpperInvariant, destination, out int _, out int bytesWritten, replaceInvalidSequences: false, isFinalBlock: true); - - Debug.Assert(status == OperationStatus.Done || status == OperationStatus.DestinationTooSmall, "ToUpperInvariant shouldn't have produced malformed Unicode string."); - - if (status != OperationStatus.Done) - { - bytesWritten = -1; // "destination too small" - } - - return bytesWritten; - } - } -} diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/Utf8Span.Enumeration.cs b/src/libraries/System.Private.CoreLib/src/System/Text/Utf8Span.Enumeration.cs deleted file mode 100644 index 422a12ed109f7..0000000000000 --- a/src/libraries/System.Private.CoreLib/src/System/Text/Utf8Span.Enumeration.cs +++ /dev/null @@ -1,136 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Buffers; -using System.Diagnostics; - -namespace System.Text -{ - public readonly ref partial struct Utf8Span - { - public CharEnumerable Chars => new CharEnumerable(this); - public RuneEnumerable Runes => new RuneEnumerable(this); - - public readonly ref struct CharEnumerable - { - private readonly Utf8Span _span; - - internal CharEnumerable(Utf8Span span) - { - _span = span; - } - - public Enumerator GetEnumerator() => new Enumerator(_span); - - public ref struct Enumerator - { - private uint _currentCharPair; - private ReadOnlySpan _remainingUtf8Bytes; - - internal Enumerator(Utf8Span span) - { - _currentCharPair = default; - _remainingUtf8Bytes = span.Bytes; - } - - public char Current => (char)_currentCharPair; - - public bool MoveNext() - { - // We don't need to worry about tearing since this enumerator is a ref struct. - - if (_currentCharPair > char.MaxValue) - { - // There was a surrogate pair smuggled in here from a previous operation. - // Shift out the high surrogate value and return immediately. - - _currentCharPair >>= 16; - return true; - } - - if (_remainingUtf8Bytes.IsEmpty) - { - return false; - } - - // TODO_UTF8STRING: Since we assume Utf8String instances are well-formed, we may instead - // call an optimized version of the "decode" routine below which skips well-formedness checks. - - OperationStatus status = Rune.DecodeFromUtf8(_remainingUtf8Bytes, out Rune currentRune, out int bytesConsumed); - Debug.Assert(status == OperationStatus.Done, "Somebody fed us invalid data?"); - - if (currentRune.IsBmp) - { - // Common case - BMP scalar value. - - _currentCharPair = (uint)currentRune.Value; - } - else - { - // Uncommon case - supplementary plane (astral) scalar value. - // We'll smuggle the two UTF-16 code units into a single 32-bit value, - // with the leading surrogate packed into the low 16 bits of the value, - // and the trailing surrogate packed into the high 16 bits of the value. - - UnicodeUtility.GetUtf16SurrogatesFromSupplementaryPlaneScalar((uint)currentRune.Value, out char leadingCodeUnit, out char trailingCodeUnit); - _currentCharPair = (uint)leadingCodeUnit + ((uint)trailingCodeUnit << 16); - } - - // TODO_UTF8STRING: We can consider unsafe slicing below if we wish since we know we're - // not going to overrun the end of the span. - - _remainingUtf8Bytes = _remainingUtf8Bytes.Slice(bytesConsumed); - return true; - } - } - } - - public readonly ref struct RuneEnumerable - { - private readonly Utf8Span _span; - - internal RuneEnumerable(Utf8Span span) - { - _span = span; - } - - public Enumerator GetEnumerator() => new Enumerator(_span); - - public ref struct Enumerator - { - private Rune _currentRune; - private ReadOnlySpan _remainingUtf8Bytes; - - internal Enumerator(Utf8Span span) - { - _currentRune = default; - _remainingUtf8Bytes = span.Bytes; - } - - public Rune Current => _currentRune; - - public bool MoveNext() - { - // We don't need to worry about tearing since this enumerator is a ref struct. - - if (_remainingUtf8Bytes.IsEmpty) - { - return false; - } - - // TODO_UTF8STRING: Since we assume Utf8Span instances are well-formed, we may instead - // call an optimized version of the "decode" routine below which skips well-formedness checks. - - OperationStatus status = Rune.DecodeFromUtf8(_remainingUtf8Bytes, out _currentRune, out int bytesConsumed); - Debug.Assert(status == OperationStatus.Done, "Somebody fed us invalid data?"); - - // TODO_UTF8STRING: We can consider unsafe slicing below if we wish since we know we're - // not going to overrun the end of the span. - - _remainingUtf8Bytes = _remainingUtf8Bytes.Slice(bytesConsumed); - return true; - } - } - } - } -} diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/Utf8Span.Manipulation.cs b/src/libraries/System.Private.CoreLib/src/System/Text/Utf8Span.Manipulation.cs deleted file mode 100644 index a0b874af5ea66..0000000000000 --- a/src/libraries/System.Private.CoreLib/src/System/Text/Utf8Span.Manipulation.cs +++ /dev/null @@ -1,521 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.ComponentModel; -using System.Diagnostics; -using System.Runtime.InteropServices; -using System.Text.Unicode; - -namespace System.Text -{ - public readonly ref partial struct Utf8Span - { - public SplitResult Split(char separator, Utf8StringSplitOptions options = Utf8StringSplitOptions.None) - { - if (!Rune.TryCreate(separator, out Rune rune)) - { - throw new ArgumentOutOfRangeException( - paramName: nameof(separator), - message: SR.ArgumentOutOfRange_Utf16SurrogatesDisallowed); - } - - Utf8String.CheckSplitOptions(options); - - return new SplitResult(this, rune, options); - } - - public SplitResult Split(Rune separator, Utf8StringSplitOptions options = Utf8StringSplitOptions.None) - { - Utf8String.CheckSplitOptions(options); - - return new SplitResult(this, separator, options); - } - - public SplitResult Split(Utf8Span separator, Utf8StringSplitOptions options = Utf8StringSplitOptions.None) - { - if (separator.IsEmpty) - { - throw new ArgumentException( - paramName: nameof(separator), - message: SR.Argument_CannotBeEmptySpan); - } - - Utf8String.CheckSplitOptions(options); - - return new SplitResult(this, separator, options); - } - - /// - /// Locates within this instance, creating - /// instances which represent the data on either side of the separator. If is not found - /// within this instance, returns the tuple "(this, Empty)". - /// - /// - /// An ordinal search is performed. - /// - public SplitOnResult SplitOn(char separator) - { - return TryFind(separator, out Range range) ? new SplitOnResult(this, range) : new SplitOnResult(this); - } - - /// - /// Locates within this instance, creating - /// instances which represent the data on either side of the separator. If is not found - /// within this instance, returns the tuple "(this, Empty)". - /// - /// - /// The search is performed using the specified . - /// - public SplitOnResult SplitOn(char separator, StringComparison comparisonType) - { - return TryFind(separator, comparisonType, out Range range) ? new SplitOnResult(this, range) : new SplitOnResult(this); - } - - /// - /// Locates within this instance, creating - /// instances which represent the data on either side of the separator. If is not found - /// within this instance, returns the tuple "(this, Empty)". - /// - /// - /// An ordinal search is performed. - /// - public SplitOnResult SplitOn(Rune separator) - { - return TryFind(separator, out Range range) ? new SplitOnResult(this, range) : new SplitOnResult(this); - } - - /// - /// Locates within this instance, creating - /// instances which represent the data on either side of the separator. If is not found - /// within this instance, returns the tuple "(this, Empty)". - /// - /// - /// The search is performed using the specified . - /// - public SplitOnResult SplitOn(Rune separator, StringComparison comparisonType) - { - return TryFind(separator, comparisonType, out Range range) ? new SplitOnResult(this, range) : new SplitOnResult(this); - } - - /// - /// Locates within this instance, creating - /// instances which represent the data on either side of the separator. If is not found - /// within this instance, returns the tuple "(this, Empty)". - /// - /// - /// An ordinal search is performed. - /// - public SplitOnResult SplitOn(Utf8Span separator) - { - return TryFind(separator, out Range range) ? new SplitOnResult(this, range) : new SplitOnResult(this); - } - - /// - /// Locates the last occurrence of within this instance, creating - /// instances which represent the data on either side of the separator. If is not found - /// within this instance, returns the tuple "(this, Empty)". - /// - /// - /// The search is performed using the specified . - /// - public SplitOnResult SplitOn(Utf8Span separator, StringComparison comparisonType) - { - return TryFind(separator, comparisonType, out Range range) ? new SplitOnResult(this, range) : new SplitOnResult(this); - } - - /// - /// Locates the last occurrence of within this instance, creating - /// instances which represent the data on either side of the separator. If is not found - /// within this instance, returns the tuple "(this, Empty)". - /// - /// - /// An ordinal search is performed. - /// - public SplitOnResult SplitOnLast(char separator) - { - return TryFindLast(separator, out Range range) ? new SplitOnResult(this, range) : new SplitOnResult(this); - } - - /// - /// Locates the last occurrence of within this instance, creating - /// instances which represent the data on either side of the separator. If is not found - /// within this instance, returns the tuple "(this, Empty)". - /// - /// - /// The search is performed using the specified . - /// - public SplitOnResult SplitOnLast(char separator, StringComparison comparisonType) - { - return TryFindLast(separator, comparisonType, out Range range) ? new SplitOnResult(this, range) : new SplitOnResult(this); - } - - /// - /// Locates the last occurrence of within this instance, creating - /// instances which represent the data on either side of the separator. If is not found - /// within this instance, returns the tuple "(this, Empty)". - /// - /// - /// An ordinal search is performed. - /// - public SplitOnResult SplitOnLast(Rune separator) - { - return TryFindLast(separator, out Range range) ? new SplitOnResult(this, range) : new SplitOnResult(this); - } - - /// - /// Locates the last occurrence of within this instance, creating - /// instances which represent the data on either side of the separator. If is not found - /// within this instance, returns the tuple "(this, Empty)". - /// - /// - /// The search is performed using the specified . - /// - public SplitOnResult SplitOnLast(Rune separator, StringComparison comparisonType) - { - return TryFindLast(separator, comparisonType, out Range range) ? new SplitOnResult(this, range) : new SplitOnResult(this); - } - - /// - /// Locates the last occurrence of within this instance, creating - /// instances which represent the data on either side of the separator. If is not found - /// within this instance, returns the tuple "(this, Empty)". - /// - /// - /// An ordinal search is performed. - /// - public SplitOnResult SplitOnLast(Utf8Span separator) - { - return TryFindLast(separator, out Range range) ? new SplitOnResult(this, range) : new SplitOnResult(this); - } - - /// - /// Locates the last occurrence of within this instance, creating - /// instances which represent the data on either side of the separator. If is not found - /// within this instance, returns the tuple "(this, Empty)". - /// - /// - /// The search is performed using the specified . - /// - public SplitOnResult SplitOnLast(Utf8Span separator, StringComparison comparisonType) - { - return TryFindLast(separator, comparisonType, out Range range) ? new SplitOnResult(this, range) : new SplitOnResult(this); - } - - /// - /// Trims whitespace from the beginning and the end of this , - /// returning a new containing the resulting slice. - /// - public Utf8Span Trim() => TrimHelper(TrimType.Both); - - /// - /// Trims whitespace from only the end of this , - /// returning a new containing the resulting slice. - /// - public Utf8Span TrimEnd() => TrimHelper(TrimType.Tail); - - internal Utf8Span TrimHelper(TrimType trimType) - { - ReadOnlySpan retSpan = Bytes; - - if ((trimType & TrimType.Head) != 0) - { - int indexOfFirstNonWhiteSpaceChar = Utf8Utility.GetIndexOfFirstNonWhiteSpaceChar(retSpan); - Debug.Assert((uint)indexOfFirstNonWhiteSpaceChar <= (uint)retSpan.Length); - - // TODO_UTF8STRING: Can use an unsafe slicing routine below if we need a perf boost. - - retSpan = retSpan.Slice(indexOfFirstNonWhiteSpaceChar); - } - - if ((trimType & TrimType.Tail) != 0) - { - int indexOfTrailingWhiteSpaceSequence = Utf8Utility.GetIndexOfTrailingWhiteSpaceSequence(retSpan); - Debug.Assert((uint)indexOfTrailingWhiteSpaceSequence <= (uint)retSpan.Length); - - // TODO_UTF8STRING: Can use an unsafe slicing routine below if we need a perf boost. - - retSpan = retSpan.Slice(0, indexOfTrailingWhiteSpaceSequence); - } - - return UnsafeCreateWithoutValidation(retSpan); - } - - /// - /// Trims whitespace from only the beginning of this , - /// returning a new containing the resulting slice. - /// - public Utf8Span TrimStart() => TrimHelper(TrimType.Head); - - [StructLayout(LayoutKind.Auto)] - public readonly ref struct SplitResult - { - private readonly State _state; - - internal SplitResult(Utf8Span source, Rune searchRune, Utf8StringSplitOptions splitOptions) - { - _state = new State - { - RemainingSearchSpace = source, - SearchRune = searchRune.Value, - SearchTerm = default, - SplitOptions = splitOptions - }; - } - - internal SplitResult(Utf8Span source, Utf8Span searchTerm, Utf8StringSplitOptions splitOptions) - { - _state = new State - { - RemainingSearchSpace = source, - SearchRune = -1, - SearchTerm = searchTerm, - SplitOptions = splitOptions - }; - } - - [EditorBrowsable(EditorBrowsableState.Never)] - public void Deconstruct(out Utf8Span item1, out Utf8Span item2) - { - _state.DeconstructHelper(in _state.RemainingSearchSpace, out item1, out item2); - TrimIfNeeded(ref item2); - } - - [EditorBrowsable(EditorBrowsableState.Never)] - public void Deconstruct(out Utf8Span item1, out Utf8Span item2, out Utf8Span item3) - { - _state.DeconstructHelper(in _state.RemainingSearchSpace, out item1, out Utf8Span remainder); - _state.DeconstructHelper(in remainder, out item2, out item3); - TrimIfNeeded(ref item3); - } - - [EditorBrowsable(EditorBrowsableState.Never)] - public void Deconstruct(out Utf8Span item1, out Utf8Span item2, out Utf8Span item3, out Utf8Span item4) - { - _state.DeconstructHelper(in _state.RemainingSearchSpace, out item1, out Utf8Span remainder); - _state.DeconstructHelper(in remainder, out item2, out remainder); - _state.DeconstructHelper(in remainder, out item3, out item4); - TrimIfNeeded(ref item4); - } - - [EditorBrowsable(EditorBrowsableState.Never)] - public void Deconstruct(out Utf8Span item1, out Utf8Span item2, out Utf8Span item3, out Utf8Span item4, out Utf8Span item5) - { - _state.DeconstructHelper(in _state.RemainingSearchSpace, out item1, out Utf8Span remainder); - _state.DeconstructHelper(in remainder, out item2, out remainder); - _state.DeconstructHelper(in remainder, out item3, out remainder); - _state.DeconstructHelper(in remainder, out item4, out item5); - TrimIfNeeded(ref item5); - } - - [EditorBrowsable(EditorBrowsableState.Never)] - public void Deconstruct(out Utf8Span item1, out Utf8Span item2, out Utf8Span item3, out Utf8Span item4, out Utf8Span item5, out Utf8Span item6) - { - _state.DeconstructHelper(in _state.RemainingSearchSpace, out item1, out Utf8Span remainder); - _state.DeconstructHelper(in remainder, out item2, out remainder); - _state.DeconstructHelper(in remainder, out item3, out remainder); - _state.DeconstructHelper(in remainder, out item4, out remainder); - _state.DeconstructHelper(in remainder, out item5, out item6); - TrimIfNeeded(ref item6); - } - - [EditorBrowsable(EditorBrowsableState.Never)] - public void Deconstruct(out Utf8Span item1, out Utf8Span item2, out Utf8Span item3, out Utf8Span item4, out Utf8Span item5, out Utf8Span item6, out Utf8Span item7) - { - _state.DeconstructHelper(in _state.RemainingSearchSpace, out item1, out Utf8Span remainder); - _state.DeconstructHelper(in remainder, out item2, out remainder); - _state.DeconstructHelper(in remainder, out item3, out remainder); - _state.DeconstructHelper(in remainder, out item4, out remainder); - _state.DeconstructHelper(in remainder, out item5, out remainder); - _state.DeconstructHelper(in remainder, out item6, out item7); - TrimIfNeeded(ref item7); - } - - [EditorBrowsable(EditorBrowsableState.Never)] - public void Deconstruct(out Utf8Span item1, out Utf8Span item2, out Utf8Span item3, out Utf8Span item4, out Utf8Span item5, out Utf8Span item6, out Utf8Span item7, out Utf8Span item8) - { - _state.DeconstructHelper(in _state.RemainingSearchSpace, out item1, out Utf8Span remainder); - _state.DeconstructHelper(in remainder, out item2, out remainder); - _state.DeconstructHelper(in remainder, out item3, out remainder); - _state.DeconstructHelper(in remainder, out item4, out remainder); - _state.DeconstructHelper(in remainder, out item5, out remainder); - _state.DeconstructHelper(in remainder, out item6, out remainder); - _state.DeconstructHelper(in remainder, out item7, out item8); - TrimIfNeeded(ref item8); - } - - public Enumerator GetEnumerator() => new Enumerator(this); - - private void TrimIfNeeded(ref Utf8Span span) - { - if ((_state.SplitOptions & Utf8StringSplitOptions.TrimEntries) != 0) - { - span = span.Trim(); - } - } - - [StructLayout(LayoutKind.Auto)] - public ref struct Enumerator - { - private const Utf8StringSplitOptions HALT_ENUMERATION = (Utf8StringSplitOptions)int.MinValue; - - private Utf8Span _current; - private State _state; - - internal Enumerator(SplitResult result) - { - _current = default; - _state = result._state; // copy by value - } - - public Utf8Span Current => _current; - - public bool MoveNext() - { - // Happy path: if the search term was found, then the two 'out' fields below are overwritten with - // the contents of the (before, after) tuple, and we can return right away. - - if (_state.DeconstructHelper(in _state.RemainingSearchSpace, out _current, out _state.RemainingSearchSpace)) - { - return true; - } - - // At this point, the search term was not found within the search space. '_current' contains the last - // bit of data after the final occurrence of the search term. We'll also set a flag saying that we've - // completed enumeration. - - if (_current.IsEmpty && (_state.SplitOptions & Utf8StringSplitOptions.RemoveEmptyEntries) != 0) - { - return false; - } - - if ((_state.SplitOptions & HALT_ENUMERATION) != 0) - { - return false; - } - - _state.SplitOptions |= HALT_ENUMERATION; // prevents yielding forever at end of split - - return true; - } - } - - [StructLayout(LayoutKind.Auto)] - private ref struct State // fully mutable - { - internal Utf8Span RemainingSearchSpace; - internal int SearchRune; // -1 if not specified, takes less space than "Rune?" - internal Utf8Span SearchTerm; - internal Utf8StringSplitOptions SplitOptions; - - // Returns 'true' if a match was found, 'false' otherwise. - internal readonly bool DeconstructHelper(in Utf8Span source, out Utf8Span firstItem, out Utf8Span remainder) - { - // n.b. Our callers might pass the same reference for 'source' and 'remainder'. - // We need to take care not to read 'source' after writing 'remainder'. - - bool wasMatchFound; - ref readonly Utf8Span searchSpan = ref source; - - while (true) - { - if (searchSpan.IsEmpty) - { - firstItem = searchSpan; - remainder = default; - wasMatchFound = false; - break; - } - - Range matchRange; - - if (SearchRune >= 0) - { -#if NETCOREAPP3_0 - wasMatchFound = searchSpan.TryFind(new Rune((uint)SearchRune), out matchRange); -#else - wasMatchFound = searchSpan.TryFind(Rune.UnsafeCreate((uint)SearchRune), out matchRange); -#endif - } - else - { - wasMatchFound = searchSpan.TryFind(SearchTerm, out matchRange); - } - - if (!wasMatchFound) - { - // If no match was found, we move 'source' to 'firstItem', trim if necessary, and return right away. - - firstItem = searchSpan; - - if ((SplitOptions & Utf8StringSplitOptions.TrimEntries) != 0) - { - firstItem = firstItem.Trim(); - } - - remainder = default; - } - else - { - // Otherwise, if a match was found, split the result across 'firstItem' and 'remainder', - // applying trimming if necessary. - - firstItem = searchSpan[..matchRange.Start]; // TODO_UTF8STRING: Could use unsafe slicing as optimization - remainder = searchSpan[matchRange.End..]; // TODO_UTF8STRING: Could use unsafe slicing as optimization - - if ((SplitOptions & Utf8StringSplitOptions.TrimEntries) != 0) - { - firstItem = firstItem.Trim(); - } - - // If we're asked to remove empty entries, loop until there's a real value in 'firstItem'. - - if ((SplitOptions & Utf8StringSplitOptions.RemoveEmptyEntries) != 0 && firstItem.IsEmpty) - { - searchSpan = ref remainder; - continue; - } - } - - break; // loop only if explicit 'continue' statement was hit - } - - return wasMatchFound; - } - } - } - - [StructLayout(LayoutKind.Auto)] - public readonly ref struct SplitOnResult - { - // Used when there is no match. - internal SplitOnResult(Utf8Span originalSearchSpace) - { - Before = originalSearchSpace; - After = Empty; - } - - // Used when a match is found. - internal SplitOnResult(Utf8Span originalSearchSpace, Range searchTermMatchRange) - { - (int startIndex, int length) = searchTermMatchRange.GetOffsetAndLength(originalSearchSpace.Length); - - // TODO_UTF8STRING: The below indexer performs correctness checks. We can skip these checks (and even the - // bounds checks more generally) since we know the inputs are all valid and the containing struct is not - // subject to tearing. - - Before = originalSearchSpace[..startIndex]; - After = originalSearchSpace[(startIndex + length)..]; - } - - public Utf8Span After { get; } - public Utf8Span Before { get; } - - [EditorBrowsable(EditorBrowsableState.Never)] - public void Deconstruct(out Utf8Span before, out Utf8Span after) - { - before = Before; - after = After; - } - } - } -} diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/Utf8Span.Searching.cs b/src/libraries/System.Private.CoreLib/src/System/Text/Utf8Span.Searching.cs deleted file mode 100644 index a004812e61a5a..0000000000000 --- a/src/libraries/System.Private.CoreLib/src/System/Text/Utf8Span.Searching.cs +++ /dev/null @@ -1,577 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Diagnostics; -using System.Globalization; -using System.Text.Unicode; - -namespace System.Text -{ - public readonly ref partial struct Utf8Span - { - /// - /// Attempts to locate the target within this instance. - /// If is found, returns and sets to - /// the location where occurs within this instance. - /// If is not found, returns and sets - /// to . - /// - /// - /// An ordinal search is performed. - /// - public bool TryFind(char value, out Range range) - { - if (Rune.TryCreate(value, out Rune rune)) - { - return TryFind(rune, out range); - } - else - { - // Surrogate chars can't exist in well-formed UTF-8 data - bail immediately. - - range = default; - return false; - } - } - - /// - /// Attempts to locate the target within this instance. - /// If is found, returns and sets to - /// the location where occurs within this instance. - /// If is not found, returns and sets - /// to . - /// - /// - /// The search is performed using the specified . - /// - public bool TryFind(char value, StringComparison comparisonType, out Range range) - { - if (Rune.TryCreate(value, out Rune rune)) - { - return TryFind(rune, comparisonType, out range); - } - else - { - CheckStringComparison(comparisonType); - - // Surrogate chars can't exist in well-formed UTF-8 data - bail immediately. - - range = default; - return false; - } - } - - /// - /// Attempts to locate the target within this instance. - /// If is found, returns and sets to - /// the location where occurs within this instance. - /// If is not found, returns and sets - /// to . - /// - /// - /// An ordinal search is performed. - /// - public bool TryFind(Rune value, out Range range) - { - if (value.IsAscii) - { - // Special-case ASCII since it's a simple single byte search. - - int idx = Bytes.IndexOf((byte)value.Value); - if (idx < 0) - { - range = default; - return false; - } - else - { - range = idx..(idx + 1); - return true; - } - } - else - { - // Slower path: need to search a multi-byte sequence. - // TODO_UTF8STRING: As an optimization, we could use unsafe APIs below since we - // know Rune instances are well-formed and slicing is safe. - - Span runeBytes = stackalloc byte[Utf8Utility.MaxBytesPerScalar]; - int utf8ByteLengthOfRune = value.EncodeToUtf8(runeBytes); - - return TryFind(UnsafeCreateWithoutValidation(runeBytes.Slice(0, utf8ByteLengthOfRune)), out range); - } - } - - /// - /// Attempts to locate the target within this instance. - /// If is found, returns and sets to - /// the location where occurs within this instance. - /// If is not found, returns and sets - /// to . - /// - /// - /// The search is performed using the specified . - /// - public bool TryFind(Rune value, StringComparison comparisonType, out Range range) - { - if (comparisonType == StringComparison.Ordinal) - { - return TryFind(value, out range); - } - else - { - // Slower path: not an ordinal comparison. - // TODO_UTF8STRING: As an optimization, we could use unsafe APIs below since we - // know Rune instances are well-formed and slicing is safe. - - Span runeBytes = stackalloc byte[Utf8Utility.MaxBytesPerScalar]; - int utf8ByteLengthOfRune = value.EncodeToUtf8(runeBytes); - - return TryFind(UnsafeCreateWithoutValidation(runeBytes.Slice(0, utf8ByteLengthOfRune)), comparisonType, out range); - } - } - - /// - /// Attempts to locate the target within this instance. - /// If is found, returns and sets to - /// the location where occurs within this instance. - /// If is not found, returns and sets - /// to . - /// - /// - /// An ordinal search is performed. - /// - public bool TryFind(Utf8Span value, out Range range) - { - int idx; - - if (value.Bytes.Length == 1) - { - // Special-case ASCII since it's a simple single byte search. - - idx = this.Bytes.IndexOf(value.Bytes[0]); - } - else - { - // Slower path: need to search a multi-byte sequence. - - idx = this.Bytes.IndexOf(value.Bytes); - } - - if (idx < 0) - { - range = default; - return false; - } - else - { - range = idx..(idx + value.Bytes.Length); - return true; - } - } - - /// - /// Attempts to locate the target within this instance. - /// If is found, returns and sets to - /// the location where occurs within this instance. - /// If is not found, returns and sets - /// to . - /// - /// - /// The search is performed using the specified . - /// - public bool TryFind(Utf8Span value, StringComparison comparisonType, out Range range) => TryFind(value, comparisonType, out range, fromBeginning: true); - - private unsafe bool TryFind(Utf8Span value, StringComparison comparisonType, out Range range, bool fromBeginning) - { - CheckStringComparison(comparisonType); - - if (value.IsEmpty) - { - // sourceString.IndexOf/LastIndexOf(term, comparer) should return the minimum/maximum value index - // for which the expression "sourceString.Substring(index).StartsWith(term, comparer)" is true. - // The range we return to the caller should reflect this so that they can pull out the correct index. - - if (fromBeginning) - { - range = Index.Start..Index.Start; - } - else - { - range = Index.End..Index.End; - } - return true; - } - - if (this.IsEmpty) - { - range = default; - return false; - } - - CompareInfo compareInfo = default!; // will be overwritten if it matters - CompareOptions compareOptions = GetCaseCompareOfComparisonCulture(comparisonType); - - if (GlobalizationMode.Invariant) - { - // In the Invariant globalization mode, all comparisons are normalized to Ordinal or OrdinalIgnoreCase, - // and even in "ignore case" we only map [a-z] <-> [A-Z]. All other code points remain unmapped. - - // TODO_UTF8STRING: We should take advantage of the property described above to avoid the UTF-16 - // transcoding step entirely. - - if (compareOptions == CompareOptions.None) - { - return (fromBeginning) - ? TryFind(value, out range) - : TryFindLast(value, out range); // call the ordinal search routine - } - } - else - { - switch (comparisonType) - { - case StringComparison.Ordinal: - return (fromBeginning) - ? TryFind(value, out range) - : TryFindLast(value, out range); - - case StringComparison.OrdinalIgnoreCase: - // TODO_UTF8STRING: Can probably optimize this case. -#if SYSTEM_PRIVATE_CORELIB - compareInfo = CompareInfo.Invariant; -#else - compareInfo = CultureInfo.InvariantCulture.CompareInfo; -#endif - break; - - case StringComparison.CurrentCulture: - case StringComparison.CurrentCultureIgnoreCase: - compareInfo = CultureInfo.CurrentCulture.CompareInfo; - break; - - default: - Debug.Assert(comparisonType == StringComparison.InvariantCulture || comparisonType == StringComparison.InvariantCultureIgnoreCase); -#if SYSTEM_PRIVATE_CORELIB - compareInfo = CompareInfo.Invariant; -#else - compareInfo = CultureInfo.InvariantCulture.CompareInfo; -#endif - break; - } - } - - // TODO_UTF8STRING: Remove allocations below, and try to avoid the transcoding step if possible. - - string thisTranscodedToUtf16 = this.ToStringNoReplacement(); - string otherTranscodedToUtf16 = value.ToStringNoReplacement(); - - int idx, matchLength; - -#if SYSTEM_PRIVATE_CORELIB - if (GlobalizationMode.Invariant) - { - // If we got here, it meant we're doing an OrdinalIgnoreCase comparison. - - Debug.Assert(compareOptions == CompareOptions.IgnoreCase); - - idx = CompareInfo.InvariantIndexOf(thisTranscodedToUtf16, otherTranscodedToUtf16, ignoreCase: true, fromBeginning); - matchLength = otherTranscodedToUtf16.Length; // If there was a match, it involved only simple case folding. - } - else - { - idx = (fromBeginning) - ? compareInfo.IndexOf(thisTranscodedToUtf16, otherTranscodedToUtf16, compareOptions, out matchLength) - : compareInfo.LastIndexOf(thisTranscodedToUtf16, otherTranscodedToUtf16, compareOptions, out matchLength); - } -#else - Debug.Assert(comparisonType == StringComparison.OrdinalIgnoreCase); - - if (fromBeginning) - { - idx = compareInfo.IndexOf(thisTranscodedToUtf16, otherTranscodedToUtf16, 0, thisTranscodedToUtf16.Length, compareOptions); - } - else - { - idx = compareInfo.LastIndexOf(thisTranscodedToUtf16, otherTranscodedToUtf16, thisTranscodedToUtf16.Length, thisTranscodedToUtf16.Length, compareOptions); - } - matchLength = otherTranscodedToUtf16.Length; -#endif - - if (idx < 0) - { - // No match found. Bail out now. - - range = default; - return false; - } - - // If we reached this point, we found a match. The 'idx' local is the index in the source - // string (indexed by UTF-16 code units) where the match was found, and the 'matchLength' - // local is the number of chars in the source string which constitute the match. This length - // can be different than the length of the search string, as non-ordinal IndexOf operations - // follow Unicode full case folding semantics and might also normalize characters like - // digraphs. - -#if SYSTEM_PRIVATE_CORELIB - fixed (char* pThisTranscodedToUtf16 = &thisTranscodedToUtf16.GetRawStringData()) -#else - fixed (char* pThisTranscodedToUtf16 = thisTranscodedToUtf16) -#endif - { - // First, we need to convert the UTF-16 'idx' to its UTF-8 equivalent. - - char* pStoppedCounting = Utf16Utility.GetPointerToFirstInvalidChar(pThisTranscodedToUtf16, idx, out long utf8CodeUnitCountAdjustment, out _); - Debug.Assert(pStoppedCounting == pThisTranscodedToUtf16 + idx, "We shouldn't have generated an ill-formed UTF-16 temp string."); - Debug.Assert((ulong)(idx + utf8CodeUnitCountAdjustment) <= (uint)this.Bytes.Length, "Start index should be within the source UTF-8 data."); - - // Normally when we produce a UTF-8 code unit count from a UTF-16 source we - // need to perform 64-bit arithmetic so we don't overflow. But in this case - // we know the true original source was UTF-8, so its length is known already - // to fit into a signed 32-bit integer. So we'll perform an unchecked cast. - - int utf8StartIdx = idx + (int)utf8CodeUnitCountAdjustment; - - // Now we need to convert the UTF-16 'matchLength' to its UTF-8 equivalent. - - pStoppedCounting = Utf16Utility.GetPointerToFirstInvalidChar(pThisTranscodedToUtf16 + idx, matchLength, out utf8CodeUnitCountAdjustment, out _); - Debug.Assert(pStoppedCounting == pThisTranscodedToUtf16 + idx + matchLength, "We shouldn't have generated an ill-formed UTF-16 temp string."); - Debug.Assert((ulong)(utf8StartIdx + matchLength + utf8CodeUnitCountAdjustment) <= (uint)this.Bytes.Length, "End index should be within the source UTF-8 data."); - - int utf8EndIdx = utf8StartIdx + matchLength + (int)utf8CodeUnitCountAdjustment; - - // Some quick sanity checks on the return value before we return. - - Debug.Assert(0 <= utf8StartIdx); - Debug.Assert(utf8StartIdx <= utf8EndIdx); - Debug.Assert(utf8EndIdx <= this.Bytes.Length); - - range = utf8StartIdx..utf8EndIdx; - return true; - } - } - - /// - /// Attempts to locate the last occurrence of the target within this instance. - /// If is found, returns and sets to - /// the location where occurs within this instance. - /// If is not found, returns and sets - /// to . - /// - /// - /// An ordinal search is performed. - /// - public bool TryFindLast(char value, out Range range) - { - if (Rune.TryCreate(value, out Rune rune)) - { - return TryFindLast(rune, out range); - } - else - { - // Surrogate chars can't exist in well-formed UTF-8 data - bail immediately. - - range = default; - return false; - } - } - - /// - /// Attempts to locate the last occurrence of the target within this instance. - /// If is found, returns and sets to - /// the location where occurs within this instance. - /// If is not found, returns and sets - /// to . - /// - /// - /// The search is performed using the specified . - /// - public bool TryFindLast(char value, StringComparison comparisonType, out Range range) - { - if (Rune.TryCreate(value, out Rune rune)) - { - return TryFindLast(rune, comparisonType, out range); - } - else - { - CheckStringComparison(comparisonType); - - // Surrogate chars can't exist in well-formed UTF-8 data - bail immediately. - - range = default; - return false; - } - } - - /// - /// Attempts to locate the last occurrence of the target within this instance. - /// If is found, returns and sets to - /// the location where occurs within this instance. - /// If is not found, returns and sets - /// to . - /// - /// - /// An ordinal search is performed. - /// - public bool TryFindLast(Rune value, out Range range) - { - if (value.IsAscii) - { - // Special-case ASCII since it's a simple single byte search. - - int idx = Bytes.LastIndexOf((byte)value.Value); - if (idx < 0) - { - range = default; - return false; - } - else - { - range = idx..(idx + 1); - return true; - } - } - else - { - // Slower path: need to search a multi-byte sequence. - // TODO_UTF8STRING: As an optimization, we could use unsafe APIs below since we - // know Rune instances are well-formed and slicing is safe. - - Span runeBytes = stackalloc byte[Utf8Utility.MaxBytesPerScalar]; - int utf8ByteLengthOfRune = value.EncodeToUtf8(runeBytes); - - return TryFindLast(UnsafeCreateWithoutValidation(runeBytes.Slice(0, utf8ByteLengthOfRune)), out range); - } - } - - /// - /// Attempts to locate the last occurrence of the target within this instance. - /// If is found, returns and sets to - /// the location where occurs within this instance. - /// If is not found, returns and sets - /// to . - /// - /// - /// The search is performed using the specified . - /// - public bool TryFindLast(Rune value, StringComparison comparisonType, out Range range) - { - if (comparisonType == StringComparison.Ordinal) - { - return TryFindLast(value, out range); - } - else - { - // Slower path: not an ordinal comparison. - // TODO_UTF8STRING: As an optimization, we could use unsafe APIs below since we - // know Rune instances are well-formed and slicing is safe. - - Span runeBytes = stackalloc byte[Utf8Utility.MaxBytesPerScalar]; - int utf8ByteLengthOfRune = value.EncodeToUtf8(runeBytes); - - return TryFindLast(UnsafeCreateWithoutValidation(runeBytes.Slice(0, utf8ByteLengthOfRune)), comparisonType, out range); - } - } - - /// - /// Attempts to locate the last occurrence of the target within this instance. - /// If is found, returns and sets to - /// the location where occurs within this instance. - /// If is not found, returns and sets - /// to . - /// - /// - /// An ordinal search is performed. - /// - public bool TryFindLast(Utf8Span value, out Range range) - { - int idx; - - if (value.Bytes.Length <= 1) - { - if (value.Bytes.Length == 1) - { - idx = this.Bytes.LastIndexOf(value.Bytes[0]); // special-case ASCII since it's a single byte search - } - else - { - idx = this.Length; // the last empty substring always occurs at the end of the buffer - } - } - else - { - // Slower path: need to search a multi-byte sequence. - - idx = this.Bytes.LastIndexOf(value.Bytes); - } - - if (idx < 0) - { - range = default; - return false; - } - else - { - range = idx..(idx + value.Bytes.Length); - return true; - } - } - - /// - /// Attempts to locate the last occurrence of the target within this instance. - /// If is found, returns and sets to - /// the location where occurs within this instance. - /// If is not found, returns and sets - /// to . - /// - /// - /// The search is performed using the specified . - /// - public bool TryFindLast(Utf8Span value, StringComparison comparisonType, out Range range) => TryFind(value, comparisonType, out range, fromBeginning: false); - - private static void CheckStringComparison(StringComparison comparisonType) - { -#if SYSTEM_PRIVATE_CORELIB - string.CheckStringComparison(comparisonType); -#else - // Single comparison to check if comparisonType is within [CurrentCulture .. OrdinalIgnoreCase] - if ((uint)comparisonType > (uint)StringComparison.OrdinalIgnoreCase) - { - ThrowHelper.ThrowArgumentException(SR.NotSupported_StringComparison, ExceptionArgument.comparisonType); - } - - // There's no API that would allow getting the correct match length - // for other StringComparisons. - if (comparisonType != StringComparison.Ordinal && - comparisonType != StringComparison.OrdinalIgnoreCase) - { - ThrowHelper.ThrowNotSupportedException(SR.Utf8Span_TryFindOnlySupportsOrdinal); - } -#endif - } - - private static CompareOptions GetCaseCompareOfComparisonCulture(StringComparison comparisonType) - { -#if SYSTEM_PRIVATE_CORELIB - return string.GetCaseCompareOfComparisonCulture(comparisonType); -#else - Debug.Assert((uint)comparisonType <= (uint)StringComparison.OrdinalIgnoreCase); - - // Culture enums can be & with CompareOptions.IgnoreCase 0x01 to extract if IgnoreCase or CompareOptions.None 0x00 - // - // CompareOptions.None 0x00 - // CompareOptions.IgnoreCase 0x01 - // - // StringComparison.CurrentCulture: 0x00 - // StringComparison.InvariantCulture: 0x02 - // StringComparison.Ordinal 0x04 - // - // StringComparison.CurrentCultureIgnoreCase: 0x01 - // StringComparison.InvariantCultureIgnoreCase: 0x03 - // StringComparison.OrdinalIgnoreCase 0x05 - - return (CompareOptions)((int)comparisonType & (int)CompareOptions.IgnoreCase); -#endif - } - } -} diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/Utf8Span.cs b/src/libraries/System.Private.CoreLib/src/System/Text/Utf8Span.cs deleted file mode 100644 index fcd6d4f92cb23..0000000000000 --- a/src/libraries/System.Private.CoreLib/src/System/Text/Utf8Span.cs +++ /dev/null @@ -1,329 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Buffers; -using System.ComponentModel; -using System.Diagnostics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Text.Unicode; - -#if SYSTEM_PRIVATE_CORELIB -using Internal.Runtime.CompilerServices; -#endif - -#pragma warning disable 0809 //warning CS0809: Obsolete member 'Utf8Span.Equals(object)' overrides non-obsolete member 'object.Equals(object)' - -namespace System.Text -{ - [StructLayout(LayoutKind.Auto)] - public readonly ref partial struct Utf8Span - { - /// - /// Creates a from an existing instance. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Utf8Span(Utf8String? value) - { - Bytes = Utf8Extensions.AsBytes(value); - } - - /// - /// Ctor for internal use only. Caller _must_ validate both invariants hold: - /// (a) the buffer represents well-formed UTF-8 data, and - /// (b) the buffer is immutable. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Utf8Span(ReadOnlySpan rawData) - { - // In debug builds, we want to ensure that the callers really did validate - // the buffer for well-formedness. The entire line below is removed when - // compiling release builds. - - Debug.Assert(Utf8Utility.GetIndexOfFirstInvalidUtf8Sequence(rawData, out _) == -1); - - Bytes = rawData; - } - - public ReadOnlySpan Bytes { get; } - - public static Utf8Span Empty => default; - - public bool IsEmpty => Bytes.IsEmpty; - - /// - /// Returns the length (in UTF-8 code units, or s) of this instance. - /// - public int Length => Bytes.Length; - - public Utf8Span this[Range range] - { - get - { - (int offset, int length) = range.GetOffsetAndLength(Length); - - // Check for a split across a multi-byte subsequence on the way out. - // Reminder: Unlike Utf8String, we can't safely dereference past the end of the span. - - ref byte newRef = ref DangerousGetMutableReference(offset); - if (length > 0 && Utf8Utility.IsUtf8ContinuationByte(newRef)) - { - Utf8String.ThrowImproperStringSplit(); - } - - int endIdx = offset + length; - if (endIdx < Length && Utf8Utility.IsUtf8ContinuationByte(DangerousGetMutableReference(endIdx))) - { - Utf8String.ThrowImproperStringSplit(); - } - -#if SYSTEM_PRIVATE_CORELIB - return UnsafeCreateWithoutValidation(new ReadOnlySpan(ref newRef, length)); -#else - return UnsafeCreateWithoutValidation(Bytes.Slice(offset, length)); -#endif - } - } - - /// - /// Returns a mutable reference to the first byte of this - /// (or, if this is empty, to where the first byte would be). - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal ref byte DangerousGetMutableReference() => ref MemoryMarshal.GetReference(Bytes); - - /// - /// Returns a mutable reference to the element at index - /// of this instance. The index is not bounds-checked. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal ref byte DangerousGetMutableReference(int index) - { - Debug.Assert(index >= 0, "Caller should've performed bounds checking."); - return ref DangerousGetMutableReference((uint)index); - } - - /// - /// Returns a mutable reference to the element at index - /// of this instance. The index is not bounds-checked. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal ref byte DangerousGetMutableReference(nuint index) - { - // Allow retrieving references to just past the end of the span (but shouldn't dereference this). - - Debug.Assert(index <= (uint)Length, "Caller should've performed bounds checking."); -#if SYSTEM_PRIVATE_CORELIB - return ref Unsafe.AddByteOffset(ref DangerousGetMutableReference(), index); -#else - return ref Unsafe.AddByteOffset(ref DangerousGetMutableReference(), (nint)index); -#endif - } - - public bool IsEmptyOrWhiteSpace() => (Utf8Utility.GetIndexOfFirstNonWhiteSpaceChar(Bytes) == Length); - - /// - /// This method is not supported as spans cannot be boxed. To compare two spans, use operator==. - /// - /// Always thrown by this method. - /// - /// - [Obsolete("Equals(object) on Utf8Span will always throw an exception. Use Equals(Utf8Span) or operator == instead.")] - [EditorBrowsable(EditorBrowsableState.Never)] - public override bool Equals(object? obj) - { - throw new NotSupportedException(SR.Utf8Span_CannotCallEqualsObject); - } - - public bool Equals(Utf8Span other) => Equals(this, other); - - public bool Equals(Utf8Span other, StringComparison comparison) => Equals(this, other, comparison); - - public static bool Equals(Utf8Span left, Utf8Span right) => left.Bytes.SequenceEqual(right.Bytes); - - public static bool Equals(Utf8Span left, Utf8Span right, StringComparison comparison) - { - // TODO_UTF8STRING: This perf can be improved, including removing - // the virtual dispatch by putting the switch directly in this method. - - return Utf8StringComparer.FromComparison(comparison).Equals(left, right); - } - - public override int GetHashCode() - { - // TODO_UTF8STRING: Consider whether this should use a different seed than String.GetHashCode. - // This method should only be called to calculate the hash code over spans that represent - // UTF-8 textual data, not over arbitrary binary sequences. - - ulong seed = Marvin.DefaultSeed; -#if SYSTEM_PRIVATE_CORELIB - return Marvin.ComputeHash32(ref MemoryMarshal.GetReference(Bytes), (uint)Length /* in bytes */, (uint)seed, (uint)(seed >> 32)); -#else - return Marvin.ComputeHash32(Bytes, seed); -#endif - } - - public int GetHashCode(StringComparison comparison) - { - // TODO_UTF8STRING: This perf can be improved, including removing - // the virtual dispatch by putting the switch directly in this method. - - return Utf8StringComparer.FromComparison(comparison).GetHashCode(this); - } - - /// - /// Returns if this UTF-8 text consists of all-ASCII data, - /// if there is any non-ASCII data within this UTF-8 text. - /// - /// - /// ASCII text is defined as text consisting only of scalar values in the range [ U+0000..U+007F ]. - /// Empty spans are considered to be all-ASCII. The runtime of this method is O(n). - /// - public bool IsAscii() - { - // TODO_UTF8STRING: Use an API that takes 'ref byte' instead of a 'byte*' as a parameter. - - unsafe - { - fixed (byte* pData = &MemoryMarshal.GetReference(Bytes)) - { - return (ASCIIUtility.GetIndexOfFirstNonAsciiByte(pData, (uint)Length) == (uint)Length); - } - } - } - - /// - /// Returns a value stating whether this instance is normalized - /// using the specified Unicode normalization form. - /// - /// The to check. - /// if this instance represents text - /// normalized under , otherwise . - public bool IsNormalized(NormalizationForm normalizationForm = NormalizationForm.FormC) - { - // TODO_UTF8STRING: Avoid allocations in this code path. - - return ToString().IsNormalized(normalizationForm); - } - - /// - /// Gets an immutable reference that can be used in a statement. Unlike - /// , the resulting reference is not guaranteed to be null-terminated. - /// - /// - /// If this instance is empty, returns . Dereferencing - /// such a reference will result in a being generated. - /// - [EditorBrowsable(EditorBrowsableState.Never)] - public ref readonly byte GetPinnableReference() - { - // This returns null if the underlying span is empty. The reason for this is that unlike - // Utf8String, these buffers are not guaranteed to be null-terminated, so it's not always - // safe or meaningful to dereference the element just past the end of the buffer. - - return ref Bytes.GetPinnableReference(); - } - - public override string ToString() - { - // TODO_UTF8STRING: Since we know the underlying data is immutable, well-formed UTF-8, - // we can perform transcoding using an optimized code path that skips all safety checks. - -#if (!NETSTANDARD2_0 && !NETFRAMEWORK) - return Encoding.UTF8.GetString(Bytes); -#else - if (IsEmpty) - { - return string.Empty; - } - - unsafe - { - fixed (byte* pBytes = Bytes) - { - return Encoding.UTF8.GetString(pBytes, Length); - } - } -#endif - } - - /// - /// Converts this instance to a . - /// - /// - /// This routine throws if the underlying instance - /// contains invalid UTF-8 data. - /// - internal unsafe string ToStringNoReplacement() - { - // TODO_UTF8STRING: Optimize the call below, potentially by avoiding the two-pass. - - fixed (byte* pData = &MemoryMarshal.GetReference(Bytes)) - { - byte* pFirstInvalidByte = Utf8Utility.GetPointerToFirstInvalidByte(pData, Length, out int utf16CodeUnitCountAdjustment, out _); - if (pFirstInvalidByte != pData + (uint)Length) - { - // Saw bad UTF-8 data. - // TODO_UTF8STRING: Throw a better exception below? - - ThrowHelper.ThrowInvalidOperationException(); - } - - int utf16CharCount = Length + utf16CodeUnitCountAdjustment; - Debug.Assert(utf16CharCount <= Length && utf16CharCount >= 0); - -#if (!NETSTANDARD2_0 && !NETFRAMEWORK) - // TODO_UTF8STRING: Can we call string.FastAllocate directly? - return string.Create(utf16CharCount, (pbData: (IntPtr)pData, cbData: Length), static (chars, state) => - { - OperationStatus status = Utf8.ToUtf16(new ReadOnlySpan((byte*)state.pbData, state.cbData), chars, out _, out _, replaceInvalidSequences: false); - Debug.Assert(status == OperationStatus.Done, "Did somebody mutate this Utf8String instance unexpectedly?"); - }); -#else - char[] buffer = ArrayPool.Shared.Rent(utf16CharCount); - try - { - fixed (char* pBuffer = buffer) - { - Encoding.UTF8.GetChars(pData, Length, pBuffer, utf16CharCount); - return new string(pBuffer, 0, utf16CharCount); - } - } - finally - { - ArrayPool.Shared.Return(buffer); - } -#endif - } - } - - public Utf8String ToUtf8String() - { - // TODO_UTF8STRING: Since we know the underlying data is immutable, well-formed UTF-8, - // we can perform transcoding using an optimized code path that skips all safety checks. - - return Utf8String.UnsafeCreateWithoutValidation(Bytes); - } - - /// - /// Wraps a instance around the provided , - /// skipping validation of the input data. - /// - /// - /// Callers must uphold the following two invariants: - /// - /// (a) consists only of well-formed UTF-8 data and does - /// not contain invalid or incomplete UTF-8 subsequences; and - /// (b) the contents of will not change for the duration - /// of the returned 's existence. - /// - /// If these invariants are not maintained, the runtime may exhibit undefined behavior. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Utf8Span UnsafeCreateWithoutValidation(ReadOnlySpan buffer) - { - return new Utf8Span(buffer); - } - } -} diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/Utf8StringComparer.cs b/src/libraries/System.Private.CoreLib/src/System/Text/Utf8StringComparer.cs deleted file mode 100644 index 8e56da7442594..0000000000000 --- a/src/libraries/System.Private.CoreLib/src/System/Text/Utf8StringComparer.cs +++ /dev/null @@ -1,187 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Collections.Generic; -using System.Diagnostics; -using System.Globalization; - -namespace System.Text -{ - internal abstract class Utf8StringComparer : IComparer, IEqualityComparer - { - // Nobody except for nested classes can create instances of this type. - private Utf8StringComparer() { } - - public static Utf8StringComparer CurrentCulture => new CultureAwareComparer(CultureInfo.CurrentCulture.CompareInfo, CompareOptions.None); - public static Utf8StringComparer CurrentCultureIgnoreCase => new CultureAwareComparer(CultureInfo.CurrentCulture.CompareInfo, CompareOptions.IgnoreCase); - public static Utf8StringComparer InvariantCulture => CultureAwareComparer.Invariant; - public static Utf8StringComparer InvariantCultureIgnoreCase => CultureAwareComparer.InvariantIgnoreCase; - public static Utf8StringComparer Ordinal => OrdinalComparer.Instance; - public static Utf8StringComparer OrdinalIgnoreCase => OrdinalIgnoreCaseComparer.Instance; - - public static Utf8StringComparer Create(CultureInfo culture, bool ignoreCase) => Create(culture, ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None); - - public static Utf8StringComparer Create(CultureInfo culture, CompareOptions options) - { - if (culture is null) - { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.culture); - } - - return new CultureAwareComparer(culture.CompareInfo, options); - } - - public static Utf8StringComparer FromComparison(StringComparison comparisonType) - { - return comparisonType switch - { - StringComparison.CurrentCulture => CurrentCulture, - StringComparison.CurrentCultureIgnoreCase => CurrentCultureIgnoreCase, - StringComparison.InvariantCulture => InvariantCulture, - StringComparison.InvariantCultureIgnoreCase => InvariantCultureIgnoreCase, - StringComparison.Ordinal => Ordinal, - StringComparison.OrdinalIgnoreCase => OrdinalIgnoreCase, - _ => throw new ArgumentException(SR.NotSupported_StringComparison, nameof(comparisonType)), - }; - } - - public abstract int Compare(Utf8String? x, Utf8String? y); - public abstract int Compare(Utf8Span x, Utf8Span y); - public abstract bool Equals(Utf8String? x, Utf8String? y); - public abstract bool Equals(Utf8Span x, Utf8Span y); -#pragma warning disable CS8614 // Remove warning disable when nullable attributes are respected - public abstract int GetHashCode(Utf8String obj); -#pragma warning restore CS8614 - public abstract int GetHashCode(Utf8Span obj); - - private sealed class CultureAwareComparer : Utf8StringComparer - { -#if SYSTEM_PRIVATE_CORELIB - internal static readonly CultureAwareComparer Invariant = new CultureAwareComparer(CompareInfo.Invariant, CompareOptions.None); - internal static readonly CultureAwareComparer InvariantIgnoreCase = new CultureAwareComparer(CompareInfo.Invariant, CompareOptions.IgnoreCase); -#else - internal static readonly CultureAwareComparer Invariant = new CultureAwareComparer(CultureInfo.InvariantCulture.CompareInfo, CompareOptions.None); - internal static readonly CultureAwareComparer InvariantIgnoreCase = new CultureAwareComparer(CultureInfo.InvariantCulture.CompareInfo, CompareOptions.IgnoreCase); -#endif - - private readonly CompareInfo _compareInfo; - private readonly CompareOptions _options; - - internal CultureAwareComparer(CompareInfo compareInfo, CompareOptions options) - { - Debug.Assert(compareInfo != null); - - _compareInfo = compareInfo; - _options = options; - } - - public override int Compare(Utf8String? x, Utf8String? y) - { - // TODO_UTF8STRING: Avoid the allocations below. - - return _compareInfo.Compare(x?.ToString(), y?.ToString(), _options); - } - - public override int Compare(Utf8Span x, Utf8Span y) - { - // TODO_UTF8STRING: Avoid the allocations below. - - return _compareInfo.Compare(x.ToString(), y.ToString(), _options); - } - - public override bool Equals(Utf8String? x, Utf8String? y) => Compare(x, y) == 0; - public override bool Equals(Utf8Span x, Utf8Span y) => Compare(x, y) == 0; - - public override int GetHashCode(Utf8String? obj) - { - // TODO_UTF8STRING: Avoid the allocations below. - - return (obj is null) ? 0 : _compareInfo.GetHashCode(obj.ToString(), _options); - } - - public override int GetHashCode(Utf8Span obj) - { - // TODO_UTF8STRING: Avoid the allocations below. - - return _compareInfo.GetHashCode(obj.ToString(), _options); - } - } - - private sealed class OrdinalComparer : Utf8StringComparer - { - public static readonly OrdinalComparer Instance = new OrdinalComparer(); - - // All accesses must be through the static factory. - private OrdinalComparer() { } - - public override int Compare(Utf8String? x, Utf8String? y) - { - // TODO_UTF8STRING: Avoid the allocations below. - - return string.CompareOrdinal(x?.ToString(), y?.ToString()); - } - - public override int Compare(Utf8Span x, Utf8Span y) - { - // TODO_UTF8STRING: Avoid the allocations below. - - return string.CompareOrdinal(x.ToString(), y.ToString()); - } - - public override bool Equals(Utf8String? x, Utf8String? y) => Utf8String.Equals(x, y); - public override bool Equals(Utf8Span x, Utf8Span y) => Utf8Span.Equals(x, y); - public override int GetHashCode(Utf8String obj) => obj.GetHashCode(); - public override int GetHashCode(Utf8Span obj) => obj.GetHashCode(); - } - - private sealed class OrdinalIgnoreCaseComparer : Utf8StringComparer - { - public static readonly OrdinalIgnoreCaseComparer Instance = new OrdinalIgnoreCaseComparer(); - - // All accesses must be through the static factory. - private OrdinalIgnoreCaseComparer() { } - - public override int Compare(Utf8String? x, Utf8String? y) - { - // TODO_UTF8STRING: Avoid the allocations below. - - return StringComparer.OrdinalIgnoreCase.Compare(x?.ToString(), y?.ToString()); - } - - public override int Compare(Utf8Span x, Utf8Span y) - { - // TODO_UTF8STRING: Avoid the allocations below. - - return StringComparer.OrdinalIgnoreCase.Compare(x.ToString(), y.ToString()); - } - - public override bool Equals(Utf8String? x, Utf8String? y) - { - // TODO_UTF8STRING: Avoid the allocations below. - - return StringComparer.OrdinalIgnoreCase.Equals(x?.ToString(), y?.ToString()); - } - - public override bool Equals(Utf8Span x, Utf8Span y) - { - // TODO_UTF8STRING: Avoid the allocations below. - - return StringComparer.OrdinalIgnoreCase.Equals(x.ToString(), y.ToString()); - } - - public override int GetHashCode(Utf8String obj) - { - // TODO_UTF8STRING: Avoid the allocations below. - - return StringComparer.OrdinalIgnoreCase.GetHashCode(obj.ToString()); - } - - public override int GetHashCode(Utf8Span obj) - { - // TODO_UTF8STRING: Avoid the allocations below. - - return StringComparer.OrdinalIgnoreCase.GetHashCode(obj.ToString()); - } - } - } -} diff --git a/src/libraries/System.Private.CoreLib/src/System/Utf8String.Comparison.cs b/src/libraries/System.Private.CoreLib/src/System/Utf8String.Comparison.cs deleted file mode 100644 index df4f9fb32a0be..0000000000000 --- a/src/libraries/System.Private.CoreLib/src/System/Utf8String.Comparison.cs +++ /dev/null @@ -1,383 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Buffers; -using System.Diagnostics; -using System.Runtime.InteropServices; -using System.Text; -using System.Text.Unicode; - -namespace System -{ - public sealed partial class Utf8String - { - /* - * COMPARISON OF UTF-8 AGAINST UTF-16 - */ - - /// - /// Returns a value stating whether and - /// represent the same data. An ordinal comparison is performed scalar-by-scalar. - /// - /// - /// This method returns if both and - /// are null, or if both are empty. This method returns - /// if either input contains an ill-formed subsequence. Otherwise, this method returns - /// if and only if both arguments decode to the same Unicode scalar value sequence. - /// - public static bool AreEquivalent(Utf8String? utf8Text, string? utf16Text) - { - if (ReferenceEquals(utf8Text, utf16Text)) - { - return true; // both are null - } - - if (utf8Text is null || utf16Text is null) - { - return false; // null is never equivalent to non-null - } - - if (utf8Text.Length == 0 && utf16Text.Length == 0) - { - return true; // empty is equivalent to empty - } - - // Short-circuit: are the texts of sufficiently different lengths that - // they could never be equivalent? This check allows us to skip the - // normal decoding walk, which is O(n). - // - // The maximum length of a 'System.String' is around 1 billion elements, - // so we can perform the multiplication within an unsigned 32-bit domain. - - Debug.Assert((ulong)utf16Text.Length * MAX_UTF8_BYTES_PER_UTF16_CHAR <= uint.MaxValue, "Did somebody change the max. allowed string length?"); - - if (utf8Text.Length < utf16Text.Length - || ((uint)utf16Text.Length * MAX_UTF8_BYTES_PER_UTF16_CHAR < (uint)utf8Text.Length)) - { - return false; - } - - return AreEquivalentOrdinalSkipShortCircuitingChecks(utf8Text.AsBytes(), utf16Text.AsSpan()); - } - - /// - /// Returns a value stating whether and - /// represent the same data. An ordinal comparison is performed scalar-by-scalar. - /// - /// - /// This method returns if both and - /// are empty. This method returns - /// if either input contains an ill-formed subsequence. Otherwise, this method returns - /// if and only if both arguments decode to the same Unicode scalar value sequence. - /// - public static bool AreEquivalent(Utf8Span utf8Text, ReadOnlySpan utf16Text) => AreEquivalent(utf8Text.Bytes, utf16Text); - - /// - /// Returns a value stating whether and - /// represent the same data. An ordinal comparison is performed scalar-by-scalar. - /// - /// - /// This method returns if both and - /// are empty. This method returns - /// if either input contains an ill-formed subsequence. Otherwise, this method returns - /// if and only if both arguments decode to the same Unicode scalar value sequence. - /// - public static bool AreEquivalent(ReadOnlySpan utf8Text, ReadOnlySpan utf16Text) - { - if (utf8Text.Length == 0 && utf16Text.Length == 0) - { - // Don't use IsEmpty for this check; JIT can optimize "Length == 0" better - // for this particular scenario. - - return true; - } - - // Same check as the (Utf8String, string) overload. The primary difference is that - // since spans can be up to 2 billion elements in length, we need to perform - // the multiplication step in the unsigned 64-bit domain to avoid integer overflow. - - if (utf8Text.Length < utf16Text.Length - || ((ulong)(uint)utf16Text.Length * MAX_UTF8_BYTES_PER_UTF16_CHAR < (uint)utf8Text.Length)) - { - return false; - } - - return AreEquivalentOrdinalSkipShortCircuitingChecks(utf8Text, utf16Text); - } - - private static bool AreEquivalentOrdinalSkipShortCircuitingChecks(ReadOnlySpan utf8Text, ReadOnlySpan utf16Text) - { - while (!utf16Text.IsEmpty) - { - // If the next UTF-16 subsequence is malformed or incomplete, or if the next - // UTF-8 subsequence is malformed or incomplete, or if they don't decode to - // the exact same Unicode scalar value, fail. - // - // The Rune.DecodeFrom* APIs handle empty inputs just fine and return "Incomplete". - - // TODO_UTF8STRING: If we assume Utf8String contains well-formed UTF-8, we could - // create a version of this method that calls a faster implementation of DecodeFromUtf8. - // We'd need to be careful not to call that optimized routine if the user passed - // us a normal ROS that didn't originate from a Utf8String or similar. - - if (Rune.DecodeFromUtf16(utf16Text, out Rune scalarFromUtf16, out int charsConsumedJustNow) != OperationStatus.Done - || Rune.DecodeFromUtf8(utf8Text, out Rune scalarFromUtf8, out int bytesConsumedJustNow) != OperationStatus.Done - || scalarFromUtf16 != scalarFromUtf8) - { - return false; - } - - // TODO_UTF8STRING: As an optimization, we could perform unsafe slices below. - - utf16Text = utf16Text.Slice(charsConsumedJustNow); - utf8Text = utf8Text.Slice(bytesConsumedJustNow); - } - - // We decoded the entire UTF-16 input, and so far it has matched the decoded form - // of the UTF-8 input. Now just make sure we've also decoded the entirety of the - // UTF-8 data, otherwise the input strings aren't equivalent. - - return utf8Text.IsEmpty; - } - - /// - /// Returns a value stating whether the current instance contains - /// . An ordinal comparison is used. - /// - public bool Contains(char value) - { - return Rune.TryCreate(value, out Rune rune) && Contains(rune); - } - - /// - /// Returns a value stating whether the current instance contains - /// . The specified comparison is used. - /// - public bool Contains(char value, StringComparison comparison) - { - return Rune.TryCreate(value, out Rune rune) && Contains(rune, comparison); - } - - /// - /// Returns a value stating whether the current instance contains - /// the specified . An ordinal comparison is used. - /// - public bool Contains(Rune value) - { - // TODO_UTF8STRING: This should be split into two methods: - // One which operates on a single-byte (ASCII) search value, - // the other which operates on a multi-byte (non-ASCII) search value. - - Span runeBytes = stackalloc byte[Utf8Utility.MaxBytesPerScalar]; - int runeBytesWritten = value.EncodeToUtf8(runeBytes); - -#if SYSTEM_PRIVATE_CORELIB - return SpanHelpers.IndexOf( - ref DangerousGetMutableReference(), Length, - ref MemoryMarshal.GetReference(runeBytes), runeBytesWritten) >= 0; -#else - return GetSpan() - .IndexOf(runeBytes.Slice(0, runeBytesWritten)) >= 0; -#endif - } - - /// - /// Returns a value stating whether the current instance contains - /// the specified . The specified comparison is used. - /// - public bool Contains(Rune value, StringComparison comparison) - { - // TODO_UTF8STRING: Optimize me to avoid allocations. - -#if (!NETSTANDARD2_0 && !NETFRAMEWORK) - return ToString().Contains(value.ToString(), comparison); -#else - return ToString().IndexOf(value.ToString(), comparison) >= 0; -#endif - } - - /// - /// Returns a value stating whether the current instance contains . - /// An ordinal comparison is used. - /// - public bool Contains(Utf8String value) - { - if (value is null) - { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); - } - - return this.AsBytes().IndexOf(value.AsBytes()) >= 0; - } - - /// - /// Returns a value stating whether the current instance contains . - /// The specified comparison is used. - /// - public bool Contains(Utf8String value, StringComparison comparison) - { - if (value is null) - { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); - } - - // TODO_UTF8STRING: Optimize me to avoid allocations. - -#if (!NETSTANDARD2_0 && !NETFRAMEWORK) - return ToString().Contains(value.ToString(), comparison); -#else - return ToString().IndexOf(value.ToString(), comparison) >= 0; -#endif - } - - /// - /// Returns a value stating whether the current instance ends with - /// . An ordinal comparison is used. - /// - public bool EndsWith(char value) - { - return Rune.TryCreate(value, out Rune rune) && EndsWith(rune); - } - - /// - /// Returns a value stating whether the current instance ends with - /// . The specified comparison is used. - /// - public bool EndsWith(char value, StringComparison comparison) - { - return Rune.TryCreate(value, out Rune rune) && EndsWith(rune, comparison); - } - - /// - /// Returns a value stating whether the current instance ends with - /// the specified . An ordinal comparison is used. - /// - public bool EndsWith(Rune value) - { - // TODO_UTF8STRING: This should be split into two methods: - // One which operates on a single-byte (ASCII) search value, - // the other which operates on a multi-byte (non-ASCII) search value. - - Span runeBytes = stackalloc byte[Utf8Utility.MaxBytesPerScalar]; - int runeBytesWritten = value.EncodeToUtf8(runeBytes); - - return this.AsBytes().EndsWith(runeBytes.Slice(0, runeBytesWritten)); - } - - /// - /// Returns a value stating whether the current instance ends with - /// the specified . The specified comparison is used. - /// - public bool EndsWith(Rune value, StringComparison comparison) - { - // TODO_UTF8STRING: Optimize me to avoid allocations. - - return ToString().EndsWith(value.ToString(), comparison); - } - - /// - /// Returns a value stating whether the current instance ends with . - /// An ordinal comparison is used. - /// - public bool EndsWith(Utf8String value) - { - if (value is null) - { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); - } - - return this.AsBytes().EndsWith(value.AsBytes()); - } - - /// - /// Returns a value stating whether the current instance ends with . - /// The specified comparison is used. - /// - public bool EndsWith(Utf8String value, StringComparison comparison) - { - if (value is null) - { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); - } - - // TODO_UTF8STRING: Optimize me to avoid allocations. - - return ToString().EndsWith(value.ToString(), comparison); - } - - /// - /// Returns a value stating whether the current instance begins with - /// . An ordinal comparison is used. - /// - public bool StartsWith(char value) - { - return Rune.TryCreate(value, out Rune rune) && StartsWith(rune); - } - - /// - /// Returns a value stating whether the current instance begins with - /// . The specified comparison is used. - /// - public bool StartsWith(char value, StringComparison comparison) - { - return Rune.TryCreate(value, out Rune rune) && StartsWith(rune, comparison); - } - - /// - /// Returns a value stating whether the current instance begins with - /// the specified . An ordinal comparison is used. - /// - public bool StartsWith(Rune value) - { - // TODO_UTF8STRING: This should be split into two methods: - // One which operates on a single-byte (ASCII) search value, - // the other which operates on a multi-byte (non-ASCII) search value. - - Span runeBytes = stackalloc byte[Utf8Utility.MaxBytesPerScalar]; - int runeBytesWritten = value.EncodeToUtf8(runeBytes); - - return this.AsBytes().StartsWith(runeBytes.Slice(0, runeBytesWritten)); - } - - /// - /// Returns a value stating whether the current instance begins with - /// the specified . The specified comparison is used. - /// - public bool StartsWith(Rune value, StringComparison comparison) - { - // TODO_UTF8STRING: Optimize me to avoid allocations. - - return ToString().StartsWith(value.ToString(), comparison); - } - - /// - /// Returns a value stating whether the current instance begins with . - /// An ordinal comparison is used. - /// - public bool StartsWith(Utf8String value) - { - if (value is null) - { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); - } - - return this.AsBytes().StartsWith(value.AsBytes()); - } - - /// - /// Returns a value stating whether the current instance begins with . - /// The specified comparison is used. - /// - public bool StartsWith(Utf8String value, StringComparison comparison) - { - if (value is null) - { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); - } - - // TODO_UTF8STRING: Optimize me to avoid allocations. - - return ToString().StartsWith(value.ToString(), comparison); - } - } -} diff --git a/src/libraries/System.Private.CoreLib/src/System/Utf8String.Construction.cs b/src/libraries/System.Private.CoreLib/src/System/Utf8String.Construction.cs deleted file mode 100644 index 7508458d73bad..0000000000000 --- a/src/libraries/System.Private.CoreLib/src/System/Utf8String.Construction.cs +++ /dev/null @@ -1,547 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Buffers; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.InteropServices; -using System.Text; -using System.Text.Unicode; - -namespace System -{ - public sealed partial class Utf8String - { - private const int MAX_STACK_TRANSCODE_CHAR_COUNT = 128; - - // For values beyond U+FFFF, it's 4 UTF-8 bytes per 2 UTF-16 chars (2:1 ratio) - private const int MAX_UTF8_BYTES_PER_UTF16_CHAR = 3; - - /* - * STATIC FACTORIES - */ - - /// - /// Creates a instance from existing UTF-8 data. - /// - /// The existing data from which to create the new . - /// - /// When this method returns, contains a with the same contents as - /// if consists of well-formed UTF-8 data. Otherwise, . - /// - /// - /// if contains well-formed UTF-8 data and - /// contains the encapsulating a copy of that data. Otherwise, . - /// - /// - /// This method is a non-throwing equivalent of the constructor . - /// - public static bool TryCreateFrom(ReadOnlySpan buffer, [NotNullWhen(true)] out Utf8String? value) - { - if (buffer.IsEmpty) - { - value = Empty; // it's valid to create a Utf8String instance from an empty buffer; we'll return the Empty singleton - return true; - } - - // Create and populate the Utf8String instance. - - Utf8String newString = FastAllocateSkipZeroInit(buffer.Length); -#if SYSTEM_PRIVATE_CORELIB - Buffer.Memmove(ref newString.DangerousGetMutableReference(), ref MemoryMarshal.GetReference(buffer), (uint)buffer.Length); -#else - buffer.CopyTo(newString.DangerousGetMutableSpan()); -#endif - - // Now perform validation. - // Reminder: Perform validation over the copy, not over the source. - - if (Utf8Utility.IsWellFormedUtf8(newString.AsBytes())) - { - value = newString; - return true; - } - else - { - value = default; - return false; - } - } - - /// - /// Creates a instance from existing UTF-16 data, transcoding the - /// existing data to UTF-8 upon creation. - /// - /// The existing UTF-16 data from which to create a new . - /// - /// When this method returns, contains a with equivalent contents as - /// if consists of well-formed UTF-16 data. Otherwise, . - /// - /// - /// if contains well-formed UTF-16 data and - /// contains the encapsulating equivalent data (as UTF-8). Otherwise, . - /// - /// - /// This method is a non-throwing equivalent of the constructor . - /// - public static bool TryCreateFrom(ReadOnlySpan buffer, [NotNullWhen(true)] out Utf8String? value) - { - // Returning "false" from this method means only that the original input buffer didn't - // contain well-formed UTF-16 data. This method could fail in other ways, such as - // throwing an OutOfMemoryException if allocation of the output parameter fails. - - value = CreateFromUtf16Common(buffer, replaceInvalidSequences: false); - return !(value is null); - } - - /// - /// Creates a instance from existing UTF-8 data. - /// - /// The existing data from which to create the new . - /// - /// If contains any ill-formed UTF-8 subsequences, those subsequences will - /// be replaced with in the returned instance. - /// This may result in the returned having different contents (and thus a different - /// total byte length) than the source parameter . - /// - public static Utf8String CreateFromRelaxed(ReadOnlySpan buffer) - { - if (buffer.IsEmpty) - { - return Empty; - } - - // Create and populate the Utf8String instance. - - Utf8String newString = FastAllocateSkipZeroInit(buffer.Length); -#if SYSTEM_PRIVATE_CORELIB - Buffer.Memmove(ref newString.DangerousGetMutableReference(), ref MemoryMarshal.GetReference(buffer), (uint)buffer.Length); -#else - buffer.CopyTo(newString.DangerousGetMutableSpan()); -#endif - - // Now perform validation & fixup. - - return Utf8Utility.ValidateAndFixupUtf8String(newString); - } - - /// - /// Creates a instance from existing UTF-16 data. - /// - /// The existing data from which to create the new . - /// - /// If contains any ill-formed UTF-16 subsequences, those subsequences will - /// be replaced with in the returned instance. - /// This may result in the original string data not round-tripping properly; that is, calling - /// on the returned instance may produce a - /// whose contents differ from . - /// - public static Utf8String CreateFromRelaxed(ReadOnlySpan buffer) - { - Utf8String? newString = CreateFromUtf16Common(buffer, replaceInvalidSequences: true); - - if (newString is null) - { - // This shouldn't happen unless somebody mutated the input buffer in the middle - // of data processing. We just fail in this scenario rather than retrying. - - throw new ArgumentException( - message: SR.Utf8String_InputContainedMalformedUtf16, - paramName: nameof(buffer)); - } - - return newString; - } - - internal static Utf8String CreateFromRune(Rune value) - { - // Can skip zero-init since we're going to populate the entire buffer. - - Utf8String newString = FastAllocateSkipZeroInit(value.Utf8SequenceLength); - - if (value.IsAscii) - { - // Fast path: If an ASCII value, just allocate the one-byte string and fill in the single byte contents. - - newString.DangerousGetMutableReference() = (byte)value.Value; - return newString; - } - else - { - // Slow path: If not ASCII, allocate a string of the appropriate length and fill in the multi-byte contents. - - int bytesWritten = value.EncodeToUtf8(newString.DangerousGetMutableSpan()); - Debug.Assert(newString.Length == bytesWritten); - return newString; - } - } - - // Returns 'null' if the input buffer does not represent well-formed UTF-16 data and 'replaceInvalidSequences' is false. - private static Utf8String? CreateFromUtf16Common(ReadOnlySpan value, bool replaceInvalidSequences) - { - // Shortcut: Since we expect most strings to be small-ish, first try a one-pass - // operation where we transcode directly on to the stack and then copy the validated - // data into the new Utf8String instance. It's still O(n), but it should have a smaller - // constant factor than a typical "count + transcode" combo. - - OperationStatus status; - Utf8String newString; - - if (value.Length <= MAX_STACK_TRANSCODE_CHAR_COUNT /* in chars */) - { - if (value.IsEmpty) - { - return Empty; - } - - Span scratch = stackalloc byte[MAX_STACK_TRANSCODE_CHAR_COUNT * MAX_UTF8_BYTES_PER_UTF16_CHAR]; // largest possible expansion, as explained below - status = Utf8.FromUtf16(value, scratch, out _, out int scratchBytesWritten, replaceInvalidSequences); - Debug.Assert(status == OperationStatus.Done || status == OperationStatus.InvalidData); - - if (status == OperationStatus.InvalidData) - { - return null; - } - - // At this point we know transcoding succeeded, so the original input data was well-formed. - // We'll memcpy the scratch buffer into the new Utf8String instance, which is very fast. - - newString = FastAllocateSkipZeroInit(scratchBytesWritten); - scratch.Slice(0, scratchBytesWritten).CopyTo(newString.DangerousGetMutableSpan()); - return newString; - } - - // First, determine how many UTF-8 bytes we'll need in order to represent this data. - // This also checks the input data for well-formedness. - - long utf8CodeUnitCountAdjustment; - - unsafe - { - fixed (char* pChars = &MemoryMarshal.GetReference(value)) - { - if (Utf16Utility.GetPointerToFirstInvalidChar(pChars, value.Length, out utf8CodeUnitCountAdjustment, out int _) != (pChars + (uint)value.Length)) - { - return null; - } - } - } - - // The max possible expansion transcoding UTF-16 to UTF-8 is that each input char corresponds - // to 3 UTF-8 bytes. This is most common in CJK languages. Since the input buffer could be - // up to int.MaxValue elements in length, we need to use a 64-bit value to hold the total - // required UTF-8 byte length. However, the VM places restrictions on how large a Utf8String - // instance can be, and the maximum allowed element count is just under int.MaxValue. (This - // mirrors the restrictions already in place for System.String.) The VM will throw an - // OutOfMemoryException if anybody tries to create a Utf8String instance larger than that, - // so if we detect any sort of overflow we'll end up passing int.MaxValue down to the allocation - // routine. This normalizes the OutOfMemoryException the caller sees. - - long totalUtf8BytesRequired = (uint)value.Length + utf8CodeUnitCountAdjustment; - if (totalUtf8BytesRequired > int.MaxValue) - { - totalUtf8BytesRequired = int.MaxValue; - } - - // We can get away with FastAllocateSkipZeroInit here because we're not going to return the - // new Utf8String instance to the caller if we don't overwrite every byte of the buffer. - - newString = FastAllocateSkipZeroInit((int)totalUtf8BytesRequired); - - // Now transcode the UTF-16 input into the newly allocated Utf8String's buffer. We can't call the - // "skip validation" transcoder because the caller could've mutated the input buffer between the - // initial counting step and the transcoding step below. - - status = Utf8.FromUtf16(value, newString.DangerousGetMutableSpan(), out _, out int bytesWritten, replaceInvalidSequences: false); - if (status != OperationStatus.Done || bytesWritten != newString.Length) - { - // Did somebody mutate our input buffer? Shouldn't be any other way this could happen. - - return null; - } - - return newString; - } - -#if !SYSTEM_PRIVATE_CORELIB - // Returns 'null' if the input buffer does not represent well-formed UTF-16 data and 'replaceInvalidSequences' is false. - private static byte[]? CreateBufferFromUtf16Common(ReadOnlySpan value, bool replaceInvalidSequences) - { - // Shortcut: Since we expect most strings to be small-ish, first try a one-pass - // operation where we transcode directly on to the stack and then copy the validated - // data into the new Utf8String instance. It's still O(n), but it should have a smaller - // constant factor than a typical "count + transcode" combo. - - OperationStatus status; - byte[] newBuffer; - - if (value.Length <= MAX_STACK_TRANSCODE_CHAR_COUNT /* in chars */) - { - if (value.IsEmpty) - { - return Utf8String.Empty._bytes; - } - - Span scratch = stackalloc byte[MAX_STACK_TRANSCODE_CHAR_COUNT * MAX_UTF8_BYTES_PER_UTF16_CHAR]; // largest possible expansion, as explained below - status = Utf8.FromUtf16(value, scratch, out _, out int scratchBytesWritten, replaceInvalidSequences); - Debug.Assert(status == OperationStatus.Done || status == OperationStatus.InvalidData); - - if (status == OperationStatus.InvalidData) - { - return null; - } - - // At this point we know transcoding succeeded, so the original input data was well-formed. - // We'll memcpy the scratch buffer into the new Utf8String instance, which is very fast. - - newBuffer = new byte[scratchBytesWritten + 1]; // null-terminated - scratch.Slice(0, scratchBytesWritten).CopyTo(newBuffer); - return newBuffer; - } - - // First, determine how many UTF-8 bytes we'll need in order to represent this data. - // This also checks the input data for well-formedness. - - long utf8CodeUnitCountAdjustment; - - unsafe - { - fixed (char* pChars = &MemoryMarshal.GetReference(value)) - { - if (Utf16Utility.GetPointerToFirstInvalidChar(pChars, value.Length, out utf8CodeUnitCountAdjustment, out int _) != (pChars + (uint)value.Length)) - { - return null; - } - } - } - - // The max possible expansion transcoding UTF-16 to UTF-8 is that each input char corresponds - // to 3 UTF-8 bytes. This is most common in CJK languages. Since the input buffer could be - // up to int.MaxValue elements in length, we need to use a 64-bit value to hold the total - // required UTF-8 byte length. However, the VM places restrictions on how large a Utf8String - // instance can be, and the maximum allowed element count is just under int.MaxValue. (This - // mirrors the restrictions already in place for System.String.) The VM will throw an - // OutOfMemoryException if anybody tries to create a Utf8String instance larger than that, - // so if we detect any sort of overflow we'll end up passing int.MaxValue down to the allocation - // routine. This normalizes the OutOfMemoryException the caller sees. - - long totalUtf8BytesRequired = (uint)value.Length + utf8CodeUnitCountAdjustment; - if (totalUtf8BytesRequired >= int.MaxValue) - { - totalUtf8BytesRequired = int.MaxValue - 1; - } - - // We can get away with FastAllocateSkipZeroInit here because we're not going to return the - // new Utf8String instance to the caller if we don't overwrite every byte of the buffer. - - newBuffer = new byte[(int)totalUtf8BytesRequired + 1]; // null-terminated - - // Now transcode the UTF-16 input into the newly allocated Utf8String's buffer. We can't call the - // "skip validation" transcoder because the caller could've mutated the input buffer between the - // initial counting step and the transcoding step below. - - status = Utf8.FromUtf16(value, newBuffer.AsSpan(0, newBuffer.Length - 1), out _, out int bytesWritten, replaceInvalidSequences: false); - if (status != OperationStatus.Done || bytesWritten != newBuffer.Length - 1) - { - // Did somebody mutate our input buffer? Shouldn't be any other way this could happen. - - return null; - } - - return newBuffer; - } -#endif // !SYSTEM_PRIVATE_CORELIB - -#if (!NETSTANDARD2_0 && !NETFRAMEWORK) - /// - /// Creates a new instance, allowing the provided delegate to populate the - /// instance data of the returned object. - /// - /// Type of the state object provided to . - /// The length, in bytes, of the instance to create. - /// The state object to provide to . - /// The callback which will be invoked to populate the returned . - /// - /// Thrown if populates the buffer with ill-formed UTF-8 data. - /// - /// - /// The runtime will perform UTF-8 validation over the contents provided by the delegate. - /// If an invalid UTF-8 subsequence is detected, an exception is thrown. - /// - public static Utf8String Create(int length, TState state, SpanAction action) - { - if (length < 0) - { - ThrowHelper.ThrowLengthArgumentOutOfRange_ArgumentOutOfRange_NeedNonNegNum(); - } - - if (action is null) - { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.action); - } - - if (length == 0) - { - return Empty; // special-case empty input - } - - // Create and populate the Utf8String instance. - // Can't use FastAllocateSkipZeroInit here because we're handing the raw buffer to user code. - - Utf8String newString = FastAllocate(length); - action(newString.DangerousGetMutableSpan(), state); - - // Now perform validation. - - if (!Utf8Utility.IsWellFormedUtf8(newString.AsBytes())) - { - throw new ArgumentException( - message: SR.Utf8String_CallbackProvidedMalformedData, - paramName: nameof(action)); - } - - return newString; - } - - /// - /// Creates a new instance, allowing the provided delegate to populate the - /// instance data of the returned object. - /// - /// Type of the state object provided to . - /// The length, in bytes, of the instance to create. - /// The state object to provide to . - /// The callback which will be invoked to populate the returned . - /// - /// The runtime will perform UTF-8 validation over the contents provided by the delegate. - /// If an invalid UTF-8 subsequence is detected, the invalid subsequence is replaced with - /// in the returned instance. This could result in the returned instance - /// having a different byte length than specified by the parameter. - /// - public static Utf8String CreateRelaxed(int length, TState state, SpanAction action) - { - if (length < 0) - { - ThrowHelper.ThrowLengthArgumentOutOfRange_ArgumentOutOfRange_NeedNonNegNum(); - } - - if (action is null) - { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.action); - } - - if (length == 0) - { - return Empty; // special-case empty input - } - - // Create and populate the Utf8String instance. - // Can't use FastAllocateSkipZeroInit here because we're handing the raw buffer to user code. - - Utf8String newString = FastAllocate(length); - action(newString.DangerousGetMutableSpan(), state); - - // Now perform validation and fixup. - - return Utf8Utility.ValidateAndFixupUtf8String(newString); - } - - /// - /// Creates a new instance, allowing the provided delegate to populate the - /// instance data of the returned object. Please see remarks for important safety information about - /// this method. - /// - /// Type of the state object provided to . - /// The length, in bytes, of the instance to create. - /// The state object to provide to . - /// The callback which will be invoked to populate the returned . - /// - /// This factory method can be used as an optimization to skip the validation step that - /// normally performs. The contract - /// of this method requires that populate the buffer with well-formed UTF-8 - /// data, as contractually guarantees that it contains only well-formed UTF-8 data, - /// and runtime instability could occur if a caller violates this guarantee. - /// - public static Utf8String UnsafeCreateWithoutValidation(int length, TState state, SpanAction action) - { - if (length < 0) - { - ThrowHelper.ThrowLengthArgumentOutOfRange_ArgumentOutOfRange_NeedNonNegNum(); - } - - if (action is null) - { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.action); - } - - if (length == 0) - { - return Empty; // special-case empty input - } - - // Create and populate the Utf8String instance. - // Can't use FastAllocateSkipZeroInit here because we're handing the raw buffer to user code. - - Utf8String newString = FastAllocate(length); - action(newString.DangerousGetMutableSpan(), state); - - // The line below is removed entirely in release builds. - - Debug.Assert(Utf8Utility.IsWellFormedUtf8(newString.AsBytes()), "Callback populated the buffer with ill-formed UTF-8 data."); - - return newString; - } -#endif // !NETSTANDARD2_0 - - /// - /// Creates a new instance populated with a copy of the provided contents. - /// Please see remarks for important safety information about this method. - /// - /// The contents to copy to the new . - /// - /// This factory method can be used as an optimization to skip the validation step that the - /// constructors normally perform. The contract of this method requires that - /// contain only well-formed UTF-8 data, as - /// contractually guarantees that it contains only well-formed UTF-8 data, and runtime instability - /// could occur if a caller violates this guarantee. - /// - public static Utf8String UnsafeCreateWithoutValidation(ReadOnlySpan utf8Contents) - { - if (utf8Contents.IsEmpty) - { - return Empty; // special-case empty input - } - - // Create and populate the Utf8String instance. - - Utf8String newString = FastAllocateSkipZeroInit(utf8Contents.Length); - utf8Contents.CopyTo(newString.DangerousGetMutableSpan()); - // TODO_UTF8STRING: Zero-init was skipped above, but we didn't null-terminate the string - - // The line below is removed entirely in release builds. - - Debug.Assert(Utf8Utility.IsWellFormedUtf8(newString.AsBytes()), "Buffer contained ill-formed UTF-8 data."); - - return newString; - } - - /* - * HELPER METHODS - */ - - /// - /// Creates a new instance of the specified length. Actual storage allocated is "length + 1" bytes - /// because instances are null-terminated. Aside from the null terminator, the contents of the new - /// instance are not zero-inited. Use only with first-party APIs which we know for a fact will - /// initialize the entire contents of the Utf8String instance. - /// - /// - /// The implementation of this method checks its input argument for overflow. - /// - private static Utf8String FastAllocateSkipZeroInit(int length) - { - // TODO_UTF8STRING: Actually skip zero-init. - - return FastAllocate(length); - } - } -} diff --git a/src/libraries/System.Private.CoreLib/src/System/Utf8String.Conversion.cs b/src/libraries/System.Private.CoreLib/src/System/Utf8String.Conversion.cs deleted file mode 100644 index 2e304e1a08b9e..0000000000000 --- a/src/libraries/System.Private.CoreLib/src/System/Utf8String.Conversion.cs +++ /dev/null @@ -1,85 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Globalization; -using System.Text; - -namespace System -{ - public sealed partial class Utf8String - { - /// - /// Returns a value stating whether this instance is normalized - /// using the specified Unicode normalization form. - /// - /// The to check. - /// if this instance represents text - /// normalized under , otherwise . - public bool IsNormalized(NormalizationForm normalizationForm = NormalizationForm.FormC) - { - // TODO_UTF8STRING: Avoid allocations in this code path. - - return ToString().IsNormalized(normalizationForm); - } - - /// - /// Returns a new instance which represents this instance - /// normalized using the specified Unicode normalization form. - /// - /// - /// The original is left unchanged by this operation. - /// - public Utf8String Normalize(NormalizationForm normalizationForm = NormalizationForm.FormC) => this.AsSpanSkipNullCheck().Normalize(normalizationForm); - - /// - /// Converts this to a . - /// - public char[] ToCharArray() => this.AsSpanSkipNullCheck().ToCharArray(); - - /// - /// Returns a new instance which represents this instance - /// converted to lowercase using . - /// - /// - /// The original is left unchanged by this operation. Note that the returned - /// instance may be longer or shorter (in terms of UTF-8 byte count) than the - /// input . - /// - public Utf8String ToLower(CultureInfo culture) => this.AsSpanSkipNullCheck().ToLower(culture); - - /// - /// Returns a new instance which represents this instance - /// converted to lowercase using the invariant culture. - /// - /// - /// The original is left unchanged by this operation. For more information on the - /// invariant culture, see the property. Note that the returned - /// instance may be longer or shorter (in terms of UTF-8 byte count) than the - /// input . - /// - public Utf8String ToLowerInvariant() => this.AsSpanSkipNullCheck().ToLowerInvariant(); - - /// - /// Returns a new instance which represents this instance - /// converted to uppercase using . - /// - /// - /// The original is left unchanged by this operation. Note that the returned - /// instance may be longer or shorter (in terms of UTF-8 byte count) than the - /// input . - /// - public Utf8String ToUpper(CultureInfo culture) => this.AsSpanSkipNullCheck().ToUpper(culture); - - /// - /// Returns a new instance which represents this instance - /// converted to uppercase using the invariant culture. - /// - /// - /// The original is left unchanged by this operation. For more information on the - /// invariant culture, see the property. Note that the returned - /// instance may be longer or shorter (in terms of UTF-8 byte count) than the - /// input . - /// - public Utf8String ToUpperInvariant() => this.AsSpanSkipNullCheck().ToUpperInvariant(); - } -} diff --git a/src/libraries/System.Private.CoreLib/src/System/Utf8String.Enumeration.cs b/src/libraries/System.Private.CoreLib/src/System/Utf8String.Enumeration.cs deleted file mode 100644 index b52f2799d52b1..0000000000000 --- a/src/libraries/System.Private.CoreLib/src/System/Utf8String.Enumeration.cs +++ /dev/null @@ -1,254 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Buffers; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; -using System.Text; - -namespace System -{ - public sealed partial class Utf8String - { - /* - * ENUMERABLE PROPERTY ACCESSORS - */ - - /// - /// Allows enumeration over the individual UTF-8 bytes of this instance. - /// - public ByteEnumerable Bytes => new ByteEnumerable(this); - - /// - /// Allows enumeration over the UTF-16 code units (see ) which would result - /// from transcoding this instance to a UTF-16 . - /// - public CharEnumerable Chars => new CharEnumerable(this); - - /// - /// Allows enumeration over the Unicode scalar values (see ) which are - /// encoded by this instance. - /// - public RuneEnumerable Runes => new RuneEnumerable(this); - - /* - * ENUMERATORS - */ - - public readonly struct ByteEnumerable : IEnumerable - { - private readonly Utf8String _obj; - - internal ByteEnumerable(Utf8String obj) - { - _obj = obj; - } - - public Enumerator GetEnumerator() => new Enumerator(_obj); - - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - - public struct Enumerator : IEnumerator - { - private readonly Utf8String _obj; - private int _nextByteIdx; - - internal Enumerator(Utf8String obj) - { - _obj = obj; - _nextByteIdx = 0; - Current = default; - } - - public byte Current { get; private set; } - - public bool MoveNext() - { - int nextByteIdx = _nextByteIdx; - ReadOnlySpan objAsBytes = _obj.AsBytesSkipNullCheck(); - - if ((uint)nextByteIdx < (uint)objAsBytes.Length) - { - Current = objAsBytes[nextByteIdx]; - _nextByteIdx = nextByteIdx + 1; - return true; - } - else - { - return false; - } - } - - void IDisposable.Dispose() - { - // intentionally no-op - } - - object IEnumerator.Current => Current; - - void IEnumerator.Reset() => throw NotImplemented.ByDesign; - } - } - - public readonly struct CharEnumerable : IEnumerable - { - private readonly Utf8String _obj; - - internal CharEnumerable(Utf8String obj) - { - _obj = obj; - } - - public Enumerator GetEnumerator() => new Enumerator(_obj); - - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - - public struct Enumerator : IEnumerator - { - private readonly Utf8String _obj; - private uint _currentCharPair; - private int _nextByteIdx; - - internal Enumerator(Utf8String obj) - { - _obj = obj; - _currentCharPair = default; - _nextByteIdx = 0; - } - - public char Current => (char)_currentCharPair; - - public bool MoveNext() - { - // Make copies of fields to avoid tearing issues since we're - // about to perform unsafe accesses. - - uint currentCharPair = _currentCharPair; - if (currentCharPair > char.MaxValue) - { - // There was a surrogate pair smuggled in here from a previous operation. - // Shift out the high surrogate value and return immediately. - - _currentCharPair = currentCharPair >> 16; - return true; - } - - ReadOnlySpan bytes = _obj.AsBytesSkipNullCheck(); - int nextByteIdx = _nextByteIdx; - - if ((uint)nextByteIdx >= (uint)bytes.Length) - { - return false; // no more data - } - - // TODO_UTF8STRING: Can we skip correctness checks below? - // Perhaps not, this enumerator struct is potentially tearable. - - OperationStatus status = Rune.DecodeFromUtf8(bytes.Slice(nextByteIdx), out Rune currentRune, out int bytesConsumedJustNow); - Debug.Assert(status == OperationStatus.Done); - - _nextByteIdx = nextByteIdx + bytesConsumedJustNow; - - if (currentRune.IsBmp) - { - // Common case - BMP scalar value. - - _currentCharPair = (uint)currentRune.Value; - } - else - { - // Uncommon case - supplementary (astral) plane scalar value. - // We'll smuggle the two UTF-16 code units into a single 32-bit value, - // with the leading surrogate packed into the low 16 bits of the value, - // and the trailing surrogate packed into the high 16 bits of the value. - - UnicodeUtility.GetUtf16SurrogatesFromSupplementaryPlaneScalar((uint)currentRune.Value, out char leadingCodeUnit, out char trailingCodeUnit); - _currentCharPair = (uint)leadingCodeUnit + ((uint)trailingCodeUnit << 16); - } - - return true; - } - - void IDisposable.Dispose() - { - // intentionally no-op - } - - object IEnumerator.Current => Current; - - void IEnumerator.Reset() => throw NotImplemented.ByDesign; - } - } - - public readonly struct RuneEnumerable : IEnumerable - { - private readonly Utf8String _obj; - - internal RuneEnumerable(Utf8String obj) - { - _obj = obj; - } - - public Enumerator GetEnumerator() => new Enumerator(_obj); - - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - - public struct Enumerator : IEnumerator - { - private readonly Utf8String _obj; - private Rune _currentRune; - private int _nextByteIdx; - - internal Enumerator(Utf8String obj) - { - _obj = obj; - _currentRune = default; - _nextByteIdx = 0; - } - - public Rune Current => _currentRune; - - public bool MoveNext() - { - // Make copies of fields to avoid tearing issues since we're - // about to perform unsafe accesses. - - ReadOnlySpan bytes = _obj.AsBytesSkipNullCheck(); - int nextByteIdx = _nextByteIdx; - - if ((uint)nextByteIdx >= (uint)bytes.Length) - { - return false; // no more data - } - - bytes = bytes.Slice(nextByteIdx); - - // TODO_UTF8STRING: Can we skip correctness checks below? - // Perhaps not, this enumerator struct is potentially tearable. - - OperationStatus status = Rune.DecodeFromUtf8(bytes, out _currentRune, out int bytesConsumedJustNow); - Debug.Assert(status == OperationStatus.Done); - - _nextByteIdx = nextByteIdx + bytesConsumedJustNow; - return true; - } - - void IDisposable.Dispose() - { - // intentionally no-op - } - - object IEnumerator.Current => Current; - - void IEnumerator.Reset() => throw NotImplemented.ByDesign; - } - } - } -} diff --git a/src/libraries/System.Private.CoreLib/src/System/Utf8String.Manipulation.cs b/src/libraries/System.Private.CoreLib/src/System/Utf8String.Manipulation.cs deleted file mode 100644 index affdaf7d2e040..0000000000000 --- a/src/libraries/System.Private.CoreLib/src/System/Utf8String.Manipulation.cs +++ /dev/null @@ -1,767 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Collections; -using System.Collections.Generic; -using System.ComponentModel; -using System.Diagnostics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Text; -using System.Text.Unicode; - -#if SYSTEM_PRIVATE_CORELIB -using Internal.Runtime.CompilerServices; -#endif - -namespace System -{ - public sealed partial class Utf8String - { - [StackTraceHidden] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static void CheckSplitOptions(Utf8StringSplitOptions options) - { - if ((uint)options > (uint)(Utf8StringSplitOptions.RemoveEmptyEntries | Utf8StringSplitOptions.TrimEntries)) - { - CheckSplitOptions_Throw(options); - } - } - - [StackTraceHidden] - private static void CheckSplitOptions_Throw(Utf8StringSplitOptions options) - { - throw new ArgumentOutOfRangeException( - paramName: nameof(options), - message: SR.Format(SR.Arg_EnumIllegalVal, (int)options)); - } - - /// - /// Substrings this without bounds checking. - /// - private Utf8String InternalSubstring(int startIndex, int length) - { - Debug.Assert(startIndex >= 0, "StartIndex cannot be negative."); - Debug.Assert(startIndex <= this.Length, "StartIndex cannot point beyond the end of the string (except to the null terminator)."); - Debug.Assert(length >= 0, "Length cannot be negative."); - Debug.Assert(startIndex + length <= this.Length, "StartIndex and Length cannot point beyond the end of the string."); - - Debug.Assert(length != 0 && length != this.Length, "Caller should handle Length boundary conditions."); - - // Since Utf8String instances must contain well-formed UTF-8 data, we cannot allow a substring such that - // either boundary of the new substring splits a multi-byte UTF-8 subsequence. Fortunately this is a very - // easy check: since we assume the original buffer consisted entirely of well-formed UTF-8 data, all we - // need to do is check that neither the substring we're about to create nor the substring that would - // follow immediately thereafter begins with a UTF-8 continuation byte. Should this occur, it means that - // the UTF-8 lead byte is in a prior substring, which would indicate a multi-byte sequence has been split. - // It's ok for us to dereference the element immediately after the end of the Utf8String instance since - // we know it's a null terminator. - - if (Utf8Utility.IsUtf8ContinuationByte(DangerousGetMutableReference(startIndex)) - || Utf8Utility.IsUtf8ContinuationByte(DangerousGetMutableReference(startIndex + length))) - { - ThrowImproperStringSplit(); - } - - Utf8String newString = FastAllocateSkipZeroInit(length); -#if SYSTEM_PRIVATE_CORELIB - Buffer.Memmove(ref newString.DangerousGetMutableReference(), ref this.DangerousGetMutableReference(startIndex), (uint)length); -#else - this.GetSpan().Slice(startIndex, length).CopyTo(newString.DangerousGetMutableSpan()); -#endif - - return newString; - } - - private Utf8String InternalSubstringWithoutCorrectnessChecks(int startIndex, int length) - { - Debug.Assert(startIndex >= 0, "StartIndex cannot be negative."); - Debug.Assert(startIndex <= this.Length, "StartIndex cannot point beyond the end of the string (except to the null terminator)."); - Debug.Assert(length >= 0, "Length cannot be negative."); - Debug.Assert(startIndex + length <= this.Length, "StartIndex and Length cannot point beyond the end of the string."); - - // In debug mode, perform the checks anyway. It's ok if we read just past the end of the - // Utf8String instance, since we'll just be reading the null terminator (which is safe). - - Debug.Assert(!Utf8Utility.IsUtf8ContinuationByte(DangerousGetMutableReference(startIndex)), "Somebody is trying to split this Utf8String improperly."); - Debug.Assert(!Utf8Utility.IsUtf8ContinuationByte(DangerousGetMutableReference(startIndex + length)), "Somebody is trying to split this Utf8String improperly."); - - if (length == 0) - { - return Empty; - } - else if (length == this.Length) - { - return this; - } - else - { - Utf8String newString = FastAllocateSkipZeroInit(length); -#if SYSTEM_PRIVATE_CORELIB - Buffer.Memmove(ref newString.DangerousGetMutableReference(), ref this.DangerousGetMutableReference(startIndex), (uint)length); -#else - this.GetSpan().Slice(startIndex, length).CopyTo(newString.DangerousGetMutableSpan()); -#endif - return newString; - } - } - - [StackTraceHidden] - internal static void ThrowImproperStringSplit() - { - throw new InvalidOperationException( - message: SR.Utf8String_CannotSplitMultibyteSubsequence); - } - - internal Utf8String Substring(int startIndex, int length) - { - ValidateStartIndexAndLength(startIndex, length); - - // Optimizations: since instances are immutable, we can return 'this' or the known - // Empty instance if the caller passed us a startIndex at the string boundary. - - if (length == 0) - { - return Empty; - } - - if (length == this.Length) - { - return this; - } - - return InternalSubstring(startIndex, length); - } - - public SplitResult Split(char separator, Utf8StringSplitOptions options = Utf8StringSplitOptions.None) - { - if (!Rune.TryCreate(separator, out Rune rune)) - { - throw new ArgumentOutOfRangeException( - paramName: nameof(separator), - message: SR.ArgumentOutOfRange_Utf16SurrogatesDisallowed); - } - - CheckSplitOptions(options); - - return new SplitResult(this, rune, options); - } - - public SplitResult Split(Rune separator, Utf8StringSplitOptions options = Utf8StringSplitOptions.None) - { - CheckSplitOptions(options); - - return new SplitResult(this, separator, options); - } - - public SplitResult Split(Utf8String separator, Utf8StringSplitOptions options = Utf8StringSplitOptions.None) - { - if (IsNullOrEmpty(separator)) - { - throw new ArgumentException( - paramName: nameof(separator), - message: SR.Argument_CannotBeNullOrEmpty); - } - - CheckSplitOptions(options); - - return new SplitResult(this, separator, options); - } - - /// - /// Locates within this instance, creating - /// instances which represent the data on either side of the separator. If is not found - /// within this instance, returns the tuple "(this, null)". - /// - /// - /// An ordinal search is performed. - /// - public SplitOnResult SplitOn(char separator) - { - return TryFind(separator, out Range range) ? new SplitOnResult(this, range) : new SplitOnResult(this); - } - - /// - /// Locates within this instance, creating - /// instances which represent the data on either side of the separator. If is not found - /// within this instance, returns the tuple "(this, null)". - /// - /// - /// The search is performed using the specified . - /// - public SplitOnResult SplitOn(char separator, StringComparison comparisonType) - { - return TryFind(separator, comparisonType, out Range range) ? new SplitOnResult(this, range) : new SplitOnResult(this); - } - - /// - /// Locates within this instance, creating - /// instances which represent the data on either side of the separator. If is not found - /// within this instance, returns the tuple "(this, null)". - /// - /// - /// An ordinal search is performed. - /// - public SplitOnResult SplitOn(Rune separator) - { - return TryFind(separator, out Range range) ? new SplitOnResult(this, range) : new SplitOnResult(this); - } - - /// - /// Locates within this instance, creating - /// instances which represent the data on either side of the separator. If is not found - /// within this instance, returns the tuple "(this, null)". - /// - /// - /// The search is performed using the specified . - /// - public SplitOnResult SplitOn(Rune separator, StringComparison comparisonType) - { - return TryFind(separator, comparisonType, out Range range) ? new SplitOnResult(this, range) : new SplitOnResult(this); - } - - /// - /// Locates within this instance, creating - /// instances which represent the data on either side of the separator. If is not found - /// within this instance, returns the tuple "(this, null)". - /// - /// - /// An ordinal search is performed. - /// - public SplitOnResult SplitOn(Utf8String separator) - { - return TryFind(separator, out Range range) ? new SplitOnResult(this, range) : new SplitOnResult(this); - } - - /// - /// Locates the last occurrence of within this instance, creating - /// instances which represent the data on either side of the separator. If is not found - /// within this instance, returns the tuple "(this, null)". - /// - /// - /// The search is performed using the specified . - /// - public SplitOnResult SplitOn(Utf8String separator, StringComparison comparisonType) - { - return TryFind(separator, comparisonType, out Range range) ? new SplitOnResult(this, range) : new SplitOnResult(this); - } - - /// - /// Locates the last occurrence of within this instance, creating - /// instances which represent the data on either side of the separator. If is not found - /// within this instance, returns the tuple "(this, null)". - /// - /// - /// An ordinal search is performed. - /// - public SplitOnResult SplitOnLast(char separator) - { - return TryFindLast(separator, out Range range) ? new SplitOnResult(this, range) : new SplitOnResult(this); - } - - /// - /// Locates the last occurrence of within this instance, creating - /// instances which represent the data on either side of the separator. If is not found - /// within this instance, returns the tuple "(this, null)". - /// - /// - /// The search is performed using the specified . - /// - public SplitOnResult SplitOnLast(char separator, StringComparison comparisonType) - { - return TryFindLast(separator, comparisonType, out Range range) ? new SplitOnResult(this, range) : new SplitOnResult(this); - } - - /// - /// Locates the last occurrence of within this instance, creating - /// instances which represent the data on either side of the separator. If is not found - /// within this instance, returns the tuple "(this, null)". - /// - /// - /// An ordinal search is performed. - /// - public SplitOnResult SplitOnLast(Rune separator) - { - return TryFindLast(separator, out Range range) ? new SplitOnResult(this, range) : new SplitOnResult(this); - } - - /// - /// Locates the last occurrence of within this instance, creating - /// instances which represent the data on either side of the separator. If is not found - /// within this instance, returns the tuple "(this, null)". - /// - /// - /// The search is performed using the specified . - /// - public SplitOnResult SplitOnLast(Rune separator, StringComparison comparisonType) - { - return TryFindLast(separator, comparisonType, out Range range) ? new SplitOnResult(this, range) : new SplitOnResult(this); - } - - /// - /// Locates the last occurrence of within this instance, creating - /// instances which represent the data on either side of the separator. If is not found - /// within this instance, returns the tuple "(this, null)". - /// - /// - /// An ordinal search is performed. - /// - public SplitOnResult SplitOnLast(Utf8String separator) - { - return TryFindLast(separator, out Range range) ? new SplitOnResult(this, range) : new SplitOnResult(this); - } - - /// - /// Locates the last occurrence of within this instance, creating - /// instances which represent the data on either side of the separator. If is not found - /// within this instance, returns the tuple "(this, null)". - /// - /// - /// The search is performed using the specified . - /// - public SplitOnResult SplitOnLast(Utf8String separator, StringComparison comparisonType) - { - return TryFindLast(separator, comparisonType, out Range range) ? new SplitOnResult(this, range) : new SplitOnResult(this); - } - - /// - /// Trims whitespace from the beginning and the end of this , - /// returning a new containing the resulting slice. - /// - public Utf8String Trim() => TrimHelper(TrimType.Both); - - /// - /// Trims whitespace from only the end of this , - /// returning a new containing the resulting slice. - /// - public Utf8String TrimEnd() => TrimHelper(TrimType.Tail); - - private Utf8String TrimHelper(TrimType trimType) - { - Utf8Span trimmedSpan = this.AsSpan().TrimHelper(trimType); - - // Try to avoid allocating a new Utf8String instance if possible. - // Otherwise, allocate a new substring wrapped around the resulting slice. - - return (trimmedSpan.Length == this.Length) ? this : trimmedSpan.ToUtf8String(); - } - - /// - /// Trims whitespace from only the beginning of this , - /// returning a new containing the resulting slice. - /// - public Utf8String TrimStart() => TrimHelper(TrimType.Head); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - [StackTraceHidden] - private void ValidateStartIndexAndLength(int startIndex, int length) - { -#if TARGET_64BIT - // See comment in Span.Slice for how this works. - if ((ulong)(uint)startIndex + (ulong)(uint)length > (ulong)(uint)this.Length) - ThrowHelper.ThrowArgumentOutOfRangeException(); -#else - if ((uint)startIndex > (uint)this.Length || (uint)length > (uint)(this.Length - startIndex)) - ThrowHelper.ThrowArgumentOutOfRangeException(); -#endif - } - - [StructLayout(LayoutKind.Auto)] - public readonly struct SplitResult : IEnumerable - { - private readonly State _state; - - internal SplitResult(Utf8String source, Rune searchRune, Utf8StringSplitOptions splitOptions) - { - _state = new State - { - FullSearchSpace = source, - OffsetAtWhichToContinueSearch = 0, - SearchRune = searchRune.Value, - SearchTerm = default, - SplitOptions = splitOptions - }; - } - - internal SplitResult(Utf8String source, Utf8String searchTerm, Utf8StringSplitOptions splitOptions) - { - _state = new State - { - FullSearchSpace = source, - OffsetAtWhichToContinueSearch = 0, - SearchRune = -1, - SearchTerm = searchTerm, - SplitOptions = splitOptions - }; - } - - [EditorBrowsable(EditorBrowsableState.Never)] - public void Deconstruct(out Utf8String? item1, out Utf8String? item2) - { - _state.DeconstructHelper(_state.GetRemainingSearchSpace(), out Utf8Span nextItem, out Utf8Span remainder); - item1 = TrimIfNeeded(nextItem); - - item2 = TrimIfNeeded(remainder); - } - - [EditorBrowsable(EditorBrowsableState.Never)] - public void Deconstruct(out Utf8String? item1, out Utf8String? item2, out Utf8String? item3) - { - _state.DeconstructHelper(_state.GetRemainingSearchSpace(), out Utf8Span nextItem, out Utf8Span remainder); - item1 = TrimIfNeeded(nextItem); - - _state.DeconstructHelper(in remainder, out nextItem, out remainder); - item2 = TrimIfNeeded(nextItem); - - item3 = TrimIfNeeded(remainder); - } - - [EditorBrowsable(EditorBrowsableState.Never)] - public void Deconstruct(out Utf8String? item1, out Utf8String? item2, out Utf8String? item3, out Utf8String? item4) - { - _state.DeconstructHelper(_state.GetRemainingSearchSpace(), out Utf8Span nextItem, out Utf8Span remainder); - item1 = TrimIfNeeded(nextItem); - - _state.DeconstructHelper(in remainder, out nextItem, out remainder); - item2 = TrimIfNeeded(nextItem); - - _state.DeconstructHelper(in remainder, out nextItem, out remainder); - item3 = TrimIfNeeded(nextItem); - - item4 = TrimIfNeeded(remainder); - } - - [EditorBrowsable(EditorBrowsableState.Never)] - public void Deconstruct(out Utf8String? item1, out Utf8String? item2, out Utf8String? item3, out Utf8String? item4, out Utf8String? item5) - { - _state.DeconstructHelper(_state.GetRemainingSearchSpace(), out Utf8Span nextItem, out Utf8Span remainder); - item1 = TrimIfNeeded(nextItem); - - _state.DeconstructHelper(in remainder, out nextItem, out remainder); - item2 = TrimIfNeeded(nextItem); - - _state.DeconstructHelper(in remainder, out nextItem, out remainder); - item3 = TrimIfNeeded(nextItem); - - _state.DeconstructHelper(in remainder, out nextItem, out remainder); - item4 = TrimIfNeeded(nextItem); - - item5 = TrimIfNeeded(remainder); - } - - [EditorBrowsable(EditorBrowsableState.Never)] - public void Deconstruct(out Utf8String? item1, out Utf8String? item2, out Utf8String? item3, out Utf8String? item4, out Utf8String? item5, out Utf8String? item6) - { - _state.DeconstructHelper(_state.GetRemainingSearchSpace(), out Utf8Span nextItem, out Utf8Span remainder); - item1 = TrimIfNeeded(nextItem); - - _state.DeconstructHelper(in remainder, out nextItem, out remainder); - item2 = TrimIfNeeded(nextItem); - - _state.DeconstructHelper(in remainder, out nextItem, out remainder); - item3 = TrimIfNeeded(nextItem); - - _state.DeconstructHelper(in remainder, out nextItem, out remainder); - item4 = TrimIfNeeded(nextItem); - - _state.DeconstructHelper(in remainder, out nextItem, out remainder); - item5 = TrimIfNeeded(nextItem); - - item6 = TrimIfNeeded(remainder); - } - - [EditorBrowsable(EditorBrowsableState.Never)] - public void Deconstruct(out Utf8String? item1, out Utf8String? item2, out Utf8String? item3, out Utf8String? item4, out Utf8String? item5, out Utf8String? item6, out Utf8String? item7) - { - _state.DeconstructHelper(_state.GetRemainingSearchSpace(), out Utf8Span nextItem, out Utf8Span remainder); - item1 = TrimIfNeeded(nextItem); - - _state.DeconstructHelper(in remainder, out nextItem, out remainder); - item2 = TrimIfNeeded(nextItem); - - _state.DeconstructHelper(in remainder, out nextItem, out remainder); - item3 = TrimIfNeeded(nextItem); - - _state.DeconstructHelper(in remainder, out nextItem, out remainder); - item4 = TrimIfNeeded(nextItem); - - _state.DeconstructHelper(in remainder, out nextItem, out remainder); - item5 = TrimIfNeeded(nextItem); - - _state.DeconstructHelper(in remainder, out nextItem, out remainder); - item6 = TrimIfNeeded(nextItem); - - item7 = TrimIfNeeded(remainder); - } - - [EditorBrowsable(EditorBrowsableState.Never)] - public void Deconstruct(out Utf8String? item1, out Utf8String? item2, out Utf8String? item3, out Utf8String? item4, out Utf8String? item5, out Utf8String? item6, out Utf8String? item7, out Utf8String? item8) - { - _state.DeconstructHelper(_state.GetRemainingSearchSpace(), out Utf8Span nextItem, out Utf8Span remainder); - item1 = TrimIfNeeded(nextItem); - - _state.DeconstructHelper(in remainder, out nextItem, out remainder); - item2 = TrimIfNeeded(nextItem); - - _state.DeconstructHelper(in remainder, out nextItem, out remainder); - item3 = TrimIfNeeded(nextItem); - - _state.DeconstructHelper(in remainder, out nextItem, out remainder); - item4 = TrimIfNeeded(nextItem); - - _state.DeconstructHelper(in remainder, out nextItem, out remainder); - item5 = TrimIfNeeded(nextItem); - - _state.DeconstructHelper(in remainder, out nextItem, out remainder); - item6 = TrimIfNeeded(nextItem); - - _state.DeconstructHelper(in remainder, out nextItem, out remainder); - item7 = TrimIfNeeded(nextItem); - - item8 = TrimIfNeeded(remainder); - } - - public Enumerator GetEnumerator() => new Enumerator(this); - - private unsafe Utf8String? TrimIfNeeded(Utf8Span span) - { - if ((_state.SplitOptions & Utf8StringSplitOptions.TrimEntries) != 0) - { - span = span.Trim(); - } - - if (span.Length < _state.FullSearchSpace.Length) - { - if (!span.IsEmpty) - { - return span.ToUtf8String(); - } - else - { - // normalize empty spans to null if needed, otherwise normalize to Utf8String.Empty - - if ((_state.SplitOptions & Utf8StringSplitOptions.RemoveEmptyEntries) != 0 - || Unsafe.AreSame(ref span.DangerousGetMutableReference(), ref Unsafe.AsRef(null))) - { - return null; - } - - return Empty; - } - } - else - { - // Don't bother making a copy of the entire Utf8String instance; - // just return the original value. - - return _state.FullSearchSpace; - } - } - - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - - [StructLayout(LayoutKind.Auto)] - public struct Enumerator : IEnumerator - { - private const Utf8StringSplitOptions HALT_ENUMERATION = (Utf8StringSplitOptions)int.MinValue; - - private Utf8String? _current; - private State _state; - - internal Enumerator(SplitResult result) - { - _current = null; - _state = result._state; // copy by value - } - - public Utf8String? Current => _current; - - public bool MoveNext() - { - bool wasMatchFound = _state.DeconstructHelper(_state.GetRemainingSearchSpace(), out Utf8Span firstItem, out Utf8Span remainder); - - _current = (firstItem.IsEmpty) ? Empty : (firstItem.Length == _state.FullSearchSpace.Length) ? _state.FullSearchSpace : firstItem.ToUtf8String(); - _state.OffsetAtWhichToContinueSearch = _state.FullSearchSpace.Length - remainder.Length; - - if (wasMatchFound) - { - return true; - } - - // At this point, the search term was not found within the search space. '_current' contains the last - // bit of data after the final occurrence of the search term. We'll also set a flag saying that we've - // completed enumeration. - - if (firstItem.IsEmpty && (_state.SplitOptions & Utf8StringSplitOptions.RemoveEmptyEntries) != 0) - { - return false; - } - - if ((_state.SplitOptions & HALT_ENUMERATION) != 0) - { - return false; - } - - _state.SplitOptions |= HALT_ENUMERATION; // prevents yielding forever at end of split - - return true; - } - - void IDisposable.Dispose() - { - // no-op - } - - object? IEnumerator.Current => Current; - - void IEnumerator.Reset() - { - throw new NotSupportedException(); - } - } - - [StructLayout(LayoutKind.Auto)] - private struct State // fully mutable - { - internal Utf8String FullSearchSpace; - internal int OffsetAtWhichToContinueSearch; - internal int SearchRune; // -1 if not specified, takes less space than "Rune?" - internal Utf8String? SearchTerm; - internal Utf8StringSplitOptions SplitOptions; - - // Returns 'true' if a match was found, 'false' otherwise. - internal readonly bool DeconstructHelper(in Utf8Span source, out Utf8Span firstItem, out Utf8Span remainder) - { - // n.b. Our callers might pass the same reference for 'source' and 'remainder'. - // We need to take care not to read 'source' after writing 'remainder'. - - bool wasMatchFound; - ref readonly Utf8Span searchSpan = ref source; - - while (true) - { - if (searchSpan.IsEmpty) - { - firstItem = searchSpan; - remainder = default; - wasMatchFound = false; - break; - } - - Range matchRange; - - int searchRune = SearchRune; // local copy so as to avoid struct tearing - if (searchRune >= 0) - { -#if NETCOREAPP3_0 - wasMatchFound = searchSpan.TryFind(new Rune((uint)searchRune), out matchRange); -#else - wasMatchFound = searchSpan.TryFind(Rune.UnsafeCreate((uint)searchRune), out matchRange); -#endif - } - else - { - wasMatchFound = searchSpan.TryFind(SearchTerm, out matchRange); - } - - if (!wasMatchFound) - { - // If no match was found, we move 'source' to 'firstItem', trim if necessary, and return right away. - - firstItem = searchSpan; - - if ((SplitOptions & Utf8StringSplitOptions.TrimEntries) != 0) - { - firstItem = firstItem.Trim(); - } - - remainder = default; - } - else - { - // Otherwise, if a match was found, split the result across 'firstItem' and 'remainder', - // applying trimming if necessary. - - firstItem = searchSpan[..matchRange.Start]; // TODO_UTF8STRING: Could use unsafe slicing as optimization - remainder = searchSpan[matchRange.End..]; // TODO_UTF8STRING: Could use unsafe slicing as optimization - - if ((SplitOptions & Utf8StringSplitOptions.TrimEntries) != 0) - { - firstItem = firstItem.Trim(); - } - - // If we're asked to remove empty entries, loop until there's a real value in 'firstItem'. - - if ((SplitOptions & Utf8StringSplitOptions.RemoveEmptyEntries) != 0 && firstItem.IsEmpty) - { - searchSpan = ref remainder; - continue; - } - } - - break; // loop only if explicit 'continue' statement was hit - } - - return wasMatchFound; - } - - internal Utf8Span GetRemainingSearchSpace() - { - // TODO_UTF8STRING: The slice below can be optimized by performing a specialized bounds check - // and multi-byte subsequence check, since we don't need to check the end of the span. - // If we do optimize this we need to remember to make local copies of the fields we're reading - // to guard against torn structs. - - return FullSearchSpace.AsSpanSkipNullCheck()[OffsetAtWhichToContinueSearch..]; - } - } - } - - [StructLayout(LayoutKind.Auto)] - public readonly struct SplitOnResult - { - // Used when there is no match. - internal SplitOnResult(Utf8String originalSearchSpace) - { - Before = originalSearchSpace; - After = null; - } - - // Used when a match is found. - internal SplitOnResult(Utf8String originalSearchSpace, Range searchTermMatchRange) - { - (int startIndex, int length) = searchTermMatchRange.GetOffsetAndLength(originalSearchSpace.Length); - - // TODO_UTF8STRING: The below indexer performs correctness checks. We can skip these checks (and even the - // bounds checks more generally) since we know the inputs are all valid and the containing struct is not - // subject to tearing. - - Before = originalSearchSpace[..startIndex]; - After = originalSearchSpace[(startIndex + length)..]; - } - - public Utf8String? After { get; } - public Utf8String Before { get; } - - [EditorBrowsable(EditorBrowsableState.Never)] - public void Deconstruct(out Utf8String before, out Utf8String? after) - { - before = Before; - after = After; - } - } - } -} - -#if !SYSTEM_PRIVATE_CORELIB -namespace System.Diagnostics -{ - [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Struct, Inherited = false)] - internal sealed class StackTraceHiddenAttribute : Attribute - { - public StackTraceHiddenAttribute() { } - } -} -#endif diff --git a/src/libraries/System.Private.CoreLib/src/System/Utf8String.Searching.cs b/src/libraries/System.Private.CoreLib/src/System/Utf8String.Searching.cs deleted file mode 100644 index 166d87d73f726..0000000000000 --- a/src/libraries/System.Private.CoreLib/src/System/Utf8String.Searching.cs +++ /dev/null @@ -1,186 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Text; - -namespace System -{ - public sealed partial class Utf8String - { - /// - /// Attempts to locate the target within this instance. - /// If is found, returns and sets to - /// the location where occurs within this instance. - /// If is not found, returns and sets - /// to . - /// - /// - /// An ordinal search is performed. - /// - public bool TryFind(char value, out Range range) => this.AsSpanSkipNullCheck().TryFind(value, out range); - - /// - /// Attempts to locate the target within this instance. - /// If is found, returns and sets to - /// the location where occurs within this instance. - /// If is not found, returns and sets - /// to . - /// - /// - /// The search is performed using the specified . - /// - public bool TryFind(char value, StringComparison comparisonType, out Range range) => this.AsSpanSkipNullCheck().TryFind(value, comparisonType, out range); - - /// - /// Attempts to locate the target within this instance. - /// If is found, returns and sets to - /// the location where occurs within this instance. - /// If is not found, returns and sets - /// to . - /// - /// - /// An ordinal search is performed. - /// - public bool TryFind(Rune value, out Range range) => this.AsSpanSkipNullCheck().TryFind(value, out range); - - /// - /// Attempts to locate the target within this instance. - /// If is found, returns and sets to - /// the location where occurs within this instance. - /// If is not found, returns and sets - /// to . - /// - /// - /// The search is performed using the specified . - /// - public bool TryFind(Rune value, StringComparison comparisonType, out Range range) => this.AsSpanSkipNullCheck().TryFind(value, comparisonType, out range); - - /// - /// Attempts to locate the target within this instance. - /// If is found, returns and sets to - /// the location where occurs within this instance. - /// If is not found, returns and sets - /// to . - /// - /// - /// An ordinal search is performed. - /// - public bool TryFind(Utf8String value, out Range range) - { - if (value is null) - { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); - } - - return this.AsSpanSkipNullCheck().TryFind(value, out range); - } - - /// - /// Attempts to locate the target within this instance. - /// If is found, returns and sets to - /// the location where occurs within this instance. - /// If is not found, returns and sets - /// to . - /// - /// - /// The search is performed using the specified . - /// - public bool TryFind(Utf8String value, StringComparison comparisonType, out Range range) - { - if (value is null) - { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); - } - - return this.AsSpanSkipNullCheck().TryFind(value, comparisonType, out range); - } - - /// - /// Attempts to locate the last occurrence of the target within this instance. - /// If is found, returns and sets to - /// the location where occurs within this instance. - /// If is not found, returns and sets - /// to . - /// - /// - /// An ordinal search is performed. - /// - public bool TryFindLast(char value, out Range range) => this.AsSpanSkipNullCheck().TryFindLast(value, out range); - - /// - /// Attempts to locate the last occurrence of the target within this instance. - /// If is found, returns and sets to - /// the location where occurs within this instance. - /// If is not found, returns and sets - /// to . - /// - /// - /// The search is performed using the specified . - /// - public bool TryFindLast(char value, StringComparison comparisonType, out Range range) => this.AsSpanSkipNullCheck().TryFindLast(value, comparisonType, out range); - - /// - /// Attempts to locate the last occurrence of the target within this instance. - /// If is found, returns and sets to - /// the location where occurs within this instance. - /// If is not found, returns and sets - /// to . - /// - /// - /// An ordinal search is performed. - /// - public bool TryFindLast(Rune value, out Range range) => this.AsSpanSkipNullCheck().TryFindLast(value, out range); - - /// - /// Attempts to locate the last occurrence of the target within this instance. - /// If is found, returns and sets to - /// the location where occurs within this instance. - /// If is not found, returns and sets - /// to . - /// - /// - /// The search is performed using the specified . - /// - public bool TryFindLast(Rune value, StringComparison comparisonType, out Range range) => this.AsSpanSkipNullCheck().TryFindLast(value, comparisonType, out range); - - /// - /// Attempts to locate the last occurrence of the target within this instance. - /// If is found, returns and sets to - /// the location where occurs within this instance. - /// If is not found, returns and sets - /// to . - /// - /// - /// An ordinal search is performed. - /// - public bool TryFindLast(Utf8String value, out Range range) - { - if (value is null) - { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); - } - - return this.AsSpanSkipNullCheck().TryFindLast(value, out range); - } - - /// - /// Attempts to locate the last occurrence of the target within this instance. - /// If is found, returns and sets to - /// the location where occurs within this instance. - /// If is not found, returns and sets - /// to . - /// - /// - /// The search is performed using the specified . - /// - public bool TryFindLast(Utf8String value, StringComparison comparisonType, out Range range) - { - if (value is null) - { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); - } - - return this.AsSpanSkipNullCheck().TryFindLast(value, comparisonType, out range); - } - } -} diff --git a/src/libraries/System.Private.CoreLib/src/System/Utf8String.cs b/src/libraries/System.Private.CoreLib/src/System/Utf8String.cs deleted file mode 100644 index 30b4cbd93dc6d..0000000000000 --- a/src/libraries/System.Private.CoreLib/src/System/Utf8String.cs +++ /dev/null @@ -1,280 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Buffers; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.CompilerServices; -using System.Text; -using System.Text.Unicode; - -#if SYSTEM_PRIVATE_CORELIB -using Internal.Runtime.CompilerServices; -#endif - -namespace System -{ - /// - /// Represents an immutable string of UTF-8 code units. - /// - public sealed partial class Utf8String : IComparable, IEquatable - { - /* - * STATIC FIELDS - */ - - public static readonly Utf8String Empty = FastAllocate(0); - - /* - * OPERATORS - */ - - /// - /// Compares two instances for equality using a comparer. - /// - public static bool operator ==(Utf8String? left, Utf8String? right) => Equals(left, right); - - /// - /// Compares two instances for inequality using a comparer. - /// - public static bool operator !=(Utf8String? left, Utf8String? right) => !Equals(left, right); - - /// - /// Projects a instance as a . - /// - /// - public static implicit operator Utf8Span(Utf8String? value) => new Utf8Span(value); - - /* - * INDEXERS - */ - - public Utf8String this[Range range] - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - // The two lines immediately below provide no bounds checking. - // The Substring method we call will both perform a bounds check - // and check for an improper split across a multi-byte subsequence. - - int startIdx = range.Start.GetOffset(Length); - int endIdx = range.End.GetOffset(Length); - - return Substring(startIdx, endIdx - startIdx); - } - } - - /* - * METHODS - */ - - /// - /// Similar to , but skips the null check on the input. - /// Throws a if the input is null. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal Utf8Span AsSpanSkipNullCheck() - { - return Utf8Span.UnsafeCreateWithoutValidation(this.AsBytesSkipNullCheck()); - } - - public int CompareTo(Utf8String? other) - { - // TODO_UTF8STRING: This is ordinal, but String.CompareTo uses CurrentCulture. - // Is this acceptable? Should we perhaps just remove the interface? - - return Utf8StringComparer.Ordinal.Compare(this, other); - } - - public int CompareTo(Utf8String? other, StringComparison comparison) - { - // TODO_UTF8STRING: We can avoid the virtual dispatch by moving the switch into this method. - - return Utf8StringComparer.FromComparison(comparison).Compare(this, other); - } - - /// - /// Returns a mutable reference to the element at index - /// of this instance. The index is not bounds-checked. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal ref byte DangerousGetMutableReference(int index) - { - Debug.Assert(index >= 0, "Caller should've performed bounds checking."); - return ref DangerousGetMutableReference((uint)index); - } - - /// - /// Returns a mutable reference to the element at index - /// of this instance. The index is not bounds-checked. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal ref byte DangerousGetMutableReference(nuint index) - { - // Allow retrieving references to the null terminator. - - Debug.Assert(index <= (uint)Length, "Caller should've performed bounds checking."); -#if SYSTEM_PRIVATE_CORELIB - return ref Unsafe.AddByteOffset(ref DangerousGetMutableReference(), index); -#else - return ref Unsafe.AddByteOffset(ref DangerousGetMutableReference(), (nint)index); -#endif - } - - /// - /// Performs an equality comparison using a comparer. - /// - public override bool Equals(object? obj) - { - return (obj is Utf8String other) && this.Equals(other); - } - - /// - /// Performs an equality comparison using a comparer. - /// - public bool Equals(Utf8String? value) - { - // First, a very quick check for referential equality. - - if (ReferenceEquals(this, value)) - { - return true; - } - - // Otherwise, perform a simple bitwise equality check. - - return !(value is null) - && this.Length == value.Length -#if SYSTEM_PRIVATE_CORELIB - && SpanHelpers.SequenceEqual(ref this.DangerousGetMutableReference(), ref value.DangerousGetMutableReference(), (uint)Length); -#else - && this.GetSpan().SequenceEqual(value.GetSpan()); -#endif - } - - /// - /// Performs an equality comparison using the specified . - /// - public bool Equals(Utf8String? value, StringComparison comparison) => Equals(this, value, comparison); - - /// - /// Compares two instances using a comparer. - /// - public static bool Equals(Utf8String? left, Utf8String? right) - { - // First, a very quick check for referential equality. - - if (ReferenceEquals(left, right)) - { - return true; - } - - // Otherwise, perform a simple bitwise equality check. - - return !(left is null) - && !(right is null) - && left.Length == right.Length -#if SYSTEM_PRIVATE_CORELIB - && SpanHelpers.SequenceEqual(ref left.DangerousGetMutableReference(), ref right.DangerousGetMutableReference(), (uint)left.Length); -#else - && left.GetSpan().SequenceEqual(right.GetSpan()); -#endif - } - - /// - /// Performs an equality comparison using the specified . - /// - public static bool Equals(Utf8String? a, Utf8String? b, StringComparison comparison) - { - // TODO_UTF8STRING: This perf can be improved, including removing - // the virtual dispatch by putting the switch directly in this method. - - return Utf8StringComparer.FromComparison(comparison).Equals(a, b); - } - - /// - /// Returns a hash code using a comparison. - /// - public override int GetHashCode() - { - // TODO_UTF8STRING: Consider whether this should use a different seed than String.GetHashCode. - - ulong seed = Marvin.DefaultSeed; -#if SYSTEM_PRIVATE_CORELIB - return Marvin.ComputeHash32(ref DangerousGetMutableReference(), (uint)_length /* in bytes */, (uint)seed, (uint)(seed >> 32)); -#else - return Marvin.ComputeHash32(_bytes, seed); -#endif - } - - /// - /// Returns a hash code using the specified . - /// - public int GetHashCode(StringComparison comparison) - { - // TODO_UTF8STRING: This perf can be improved, including removing - // the virtual dispatch by putting the switch directly in this method. - - return Utf8StringComparer.FromComparison(comparison).GetHashCode(this); - } - - /// - /// Returns if this UTF-8 text consists of all-ASCII data, - /// if there is any non-ASCII data within this UTF-8 text. - /// - /// - /// ASCII text is defined as text consisting only of scalar values in the range [ U+0000..U+007F ]. - /// Empty strings are considered to be all-ASCII. The runtime of this method is O(n). - /// - public bool IsAscii() - { - return this.AsSpan().IsAscii(); - } - - /// - /// Returns if is or zero length; - /// otherwise. - /// - public static bool IsNullOrEmpty([NotNullWhen(false)] Utf8String? value) - { - // Copied from String.IsNullOrEmpty. See that method for detailed comments on why this pattern is used. - return (value is null || 0u >= (uint)value.Length) ? true : false; - } - - public static bool IsNullOrWhiteSpace([NotNullWhen(false)] Utf8String? value) - { - return (value is null) || value.AsSpan().IsEmptyOrWhiteSpace(); - } - - /// - /// Returns the entire as an array of UTF-8 bytes. - /// - public byte[] ToByteArray() => this.AsSpanSkipNullCheck().ToByteArray(); - - /// - /// Converts this instance to a . - /// - public override string ToString() - { - // TODO_UTF8STRING: Optimize the call below, potentially by avoiding the two-pass. - -#if (!NETSTANDARD2_0 && !NETFRAMEWORK) - return Encoding.UTF8.GetString(this.AsBytesSkipNullCheck()); -#else - if (Length == 0) - { - return string.Empty; - } - - unsafe - { - fixed (byte* pBytes = this.AsBytesSkipNullCheck()) - { - return Encoding.UTF8.GetString(pBytes, Length); - } - } -#endif - } - } -} diff --git a/src/libraries/System.Private.CoreLib/src/System/Utf8StringSplitOptions.cs b/src/libraries/System.Private.CoreLib/src/System/Utf8StringSplitOptions.cs deleted file mode 100644 index 0a1426cfbaba4..0000000000000 --- a/src/libraries/System.Private.CoreLib/src/System/Utf8StringSplitOptions.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace System -{ - // TODO_UTF8STRING: This should be removed and we should use regular StringSplitOptions - // once a 'TrimEntries' flag gets added to the type. - - [Flags] - public enum Utf8StringSplitOptions - { - None = 0, - RemoveEmptyEntries = 1, - TrimEntries = 2 - } -} diff --git a/src/libraries/System.Utf8String.Experimental/Directory.Build.props b/src/libraries/System.Utf8String.Experimental/Directory.Build.props deleted file mode 100644 index 1dce756f3e082..0000000000000 --- a/src/libraries/System.Utf8String.Experimental/Directory.Build.props +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - Open - - \ No newline at end of file diff --git a/src/libraries/System.Utf8String.Experimental/README.md b/src/libraries/System.Utf8String.Experimental/README.md deleted file mode 100644 index c4e05f915d6d8..0000000000000 --- a/src/libraries/System.Utf8String.Experimental/README.md +++ /dev/null @@ -1,40 +0,0 @@ -The `Utf8String` and `Char8` types are now available for experimentation. They currently exist in the package __System.Utf8String.Experimental__. Because this is an experimental package, it is unsupported for use in production workloads. - -To install: - -```ps -install-package System.Utf8String.Experimental -prerelease -source https://dotnetfeed.blob.core.windows.net/dotnet-core/index.json -``` - -This package can only be installed into a project targeting a __nightly__ build of coreclr or libraries. Anything under the _master_ column of https://github.com/dotnet/core-sdk would work, as would any coreclr + libraries built from your own dev box (as long as you're building from _master_ instead of _release/..._). Installing this onto a project targeting an official Preview build would not work, as official Preview builds come from the _release_ branch. - -It's possible that installing the package might fail with an error similar to that seen below. - -```txt -install-package : NU1605: Detected package downgrade: Microsoft.NETCore.Platforms from 3.0.0-preview6.19251.6 to 3.0.0-preview6.19223.2. Reference the package directly from the project to select a different version. -``` - -This can occur if the NuGet client attempts to install a newer version of the package than allowed by the .NET Runtime version your application is targeting. For now you can work around this error by specifying the explicit package version in the install command. Match the version passed to the NuGet client (shown below) to the version specified in the error message (shown above). - -```ps -install-package System.Utf8String.Experimental -prerelease -source https://dotnetfeed.blob.core.windows.net/dotnet-core/index.json -version 3.0.0-preview6.19223.2 -``` - -Not all of the APIs are hooked up yet, but we have some preliminary APIs that allow experimentation with the feature, including basic creation and inspection of `Utf8String` instances, wrapping a `ReadOnlySpan` or a `ReadOnlyMemory` around a `Utf8String` instance, and passing a `Utf8String` instance through `HttpClient`. Full list of APIs available at https://github.com/dotnet/runtime/blob/master/src/libraries/System.Utf8String.Experimental/ref/System.Utf8String.Experimental.cs. - -Certain language features also work as expected. - -```cs -Utf8String s1 = new Utf8String(/* ... */); - -// range indexers work -Utf8String s2 = s1[2..5]; - -// as does pinning -fixed (byte* pUtf8 = s1) { /* use 'pUtf8' here */ } - -// and allocating a GCHandle -GCHandle handle = GCHandle.Alloc(s1, GCHandleType.Pinned); -``` - -For more information on the feature and API usage, see https://github.com/dotnet/corefxlab/issues/2350 and https://github.com/dotnet/runtime/issues/933. diff --git a/src/libraries/System.Utf8String.Experimental/System.Utf8String.Experimental.sln b/src/libraries/System.Utf8String.Experimental/System.Utf8String.Experimental.sln deleted file mode 100644 index 9a92feba4d1c6..0000000000000 --- a/src/libraries/System.Utf8String.Experimental/System.Utf8String.Experimental.sln +++ /dev/null @@ -1,60 +0,0 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.27213.1 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Utf8String.Experimental.Tests", "tests\System.Utf8String.Experimental.Tests.csproj", "{72E9FB32-4692-4692-A10B-9F053F8F1A88}" - ProjectSection(ProjectDependencies) = postProject - {D4266847-6692-481B-9459-6141DB7DA339} = {D4266847-6692-481B-9459-6141DB7DA339} - EndProjectSection -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Utf8String.Experimental", "src\System.Utf8String.Experimental.csproj", "{D4266847-6692-481B-9459-6141DB7DA339}" - ProjectSection(ProjectDependencies) = postProject - {7AF57E6B-2CED-45C9-8BCA-5BBA60D018E0} = {7AF57E6B-2CED-45C9-8BCA-5BBA60D018E0} - EndProjectSection -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Utf8String.Experimental", "ref\System.Utf8String.Experimental.csproj", "{7AF57E6B-2CED-45C9-8BCA-5BBA60D018E0}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{1A2F9F4A-A032-433E-B914-ADD5992BB178}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E107E9C1-E893-4E87-987E-04EF0DCEAEFD}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "ref", "{2E666815-2EDB-464B-9DF6-380BF4789AD4}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestUtilities", "..\Common\tests\TestUtilities\TestUtilities.csproj", "{911886E1-C0A6-4830-AAAE-BF320F644704}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {72E9FB32-4692-4692-A10B-9F053F8F1A88}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {72E9FB32-4692-4692-A10B-9F053F8F1A88}.Debug|Any CPU.Build.0 = Debug|Any CPU - {72E9FB32-4692-4692-A10B-9F053F8F1A88}.Release|Any CPU.ActiveCfg = Release|Any CPU - {72E9FB32-4692-4692-A10B-9F053F8F1A88}.Release|Any CPU.Build.0 = Release|Any CPU - {D4266847-6692-481B-9459-6141DB7DA339}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D4266847-6692-481B-9459-6141DB7DA339}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D4266847-6692-481B-9459-6141DB7DA339}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D4266847-6692-481B-9459-6141DB7DA339}.Release|Any CPU.Build.0 = Release|Any CPU - {7AF57E6B-2CED-45C9-8BCA-5BBA60D018E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7AF57E6B-2CED-45C9-8BCA-5BBA60D018E0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7AF57E6B-2CED-45C9-8BCA-5BBA60D018E0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7AF57E6B-2CED-45C9-8BCA-5BBA60D018E0}.Release|Any CPU.Build.0 = Release|Any CPU - {911886E1-C0A6-4830-AAAE-BF320F644704}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {911886E1-C0A6-4830-AAAE-BF320F644704}.Debug|Any CPU.Build.0 = Debug|Any CPU - {911886E1-C0A6-4830-AAAE-BF320F644704}.Release|Any CPU.ActiveCfg = Release|Any CPU - {911886E1-C0A6-4830-AAAE-BF320F644704}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {72E9FB32-4692-4692-A10B-9F053F8F1A88} = {1A2F9F4A-A032-433E-B914-ADD5992BB178} - {D4266847-6692-481B-9459-6141DB7DA339} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD} - {7AF57E6B-2CED-45C9-8BCA-5BBA60D018E0} = {2E666815-2EDB-464B-9DF6-380BF4789AD4} - {911886E1-C0A6-4830-AAAE-BF320F644704} = {1A2F9F4A-A032-433E-B914-ADD5992BB178} - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {7196F6AB-8F22-4E4D-B6D1-3C2CFF86229C} - EndGlobalSection -EndGlobal diff --git a/src/libraries/System.Utf8String.Experimental/pkg/System.Utf8String.Experimental.pkgproj b/src/libraries/System.Utf8String.Experimental/pkg/System.Utf8String.Experimental.pkgproj deleted file mode 100644 index 5de0422cf63b3..0000000000000 --- a/src/libraries/System.Utf8String.Experimental/pkg/System.Utf8String.Experimental.pkgproj +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - net461;netcoreapp2.0;uap10.0.16299;$(AllXamarinFrameworks) - - - - diff --git a/src/libraries/System.Utf8String.Experimental/ref/System.Utf8String.Experimental.Forwards.cs b/src/libraries/System.Utf8String.Experimental/ref/System.Utf8String.Experimental.Forwards.cs deleted file mode 100644 index 5f1d14ec279de..0000000000000 --- a/src/libraries/System.Utf8String.Experimental/ref/System.Utf8String.Experimental.Forwards.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#if !NETSTANDARD2_0 && !NETFRAMEWORK -[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Index))] -[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Range))] - -#if !NETSTANDARD2_1 -[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Text.Rune))] -#endif // !NETSTANDARD2_1 - -#endif // !NETSTANDARD2_0 diff --git a/src/libraries/System.Utf8String.Experimental/ref/System.Utf8String.Experimental.Range.cs b/src/libraries/System.Utf8String.Experimental/ref/System.Utf8String.Experimental.Range.cs deleted file mode 100644 index 7c4116944f7c4..0000000000000 --- a/src/libraries/System.Utf8String.Experimental/ref/System.Utf8String.Experimental.Range.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// ------------------------------------------------------------------------------ -// Changes to this file must follow the https://aka.ms/api-review process. -// ------------------------------------------------------------------------------ - -namespace System -{ - public readonly partial struct Index : System.IEquatable - { - private readonly int _dummyPrimitive; - public Index(int value, bool fromEnd = false) { throw null; } - public static System.Index End { get { throw null; } } - public bool IsFromEnd { get { throw null; } } - public static System.Index Start { get { throw null; } } - public int Value { get { throw null; } } - public bool Equals(System.Index other) { throw null; } - public override bool Equals(object? value) { throw null; } - public static System.Index FromEnd(int value) { throw null; } - public static System.Index FromStart(int value) { throw null; } - public override int GetHashCode() { throw null; } - public int GetOffset(int length) { throw null; } - public static implicit operator System.Index(int value) { throw null; } - public override string ToString() { throw null; } - } - public readonly partial struct Range : System.IEquatable - { - private readonly int _dummyPrimitive; - public Range(System.Index start, System.Index end) { throw null; } - public static System.Range All { get { throw null; } } - public System.Index End { get { throw null; } } - public System.Index Start { get { throw null; } } - public static System.Range EndAt(System.Index end) { throw null; } - public override bool Equals(object? value) { throw null; } - public bool Equals(System.Range other) { throw null; } - public override int GetHashCode() { throw null; } - public (int Offset, int Length) GetOffsetAndLength(int length) { throw null; } - public static System.Range StartAt(System.Index start) { throw null; } - public override string ToString() { throw null; } - } -} diff --git a/src/libraries/System.Utf8String.Experimental/ref/System.Utf8String.Experimental.Rune.cs b/src/libraries/System.Utf8String.Experimental/ref/System.Utf8String.Experimental.Rune.cs deleted file mode 100644 index da7e4be0f2340..0000000000000 --- a/src/libraries/System.Utf8String.Experimental/ref/System.Utf8String.Experimental.Rune.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// ------------------------------------------------------------------------------ -// Changes to this file must follow the https://aka.ms/api-review process. -// ------------------------------------------------------------------------------ - -namespace System.Text -{ - public readonly partial struct Rune : System.IComparable, System.IComparable, System.IEquatable - { - private readonly int _dummyPrimitive; - public Rune(char ch) { throw null; } - public Rune(char highSurrogate, char lowSurrogate) { throw null; } - public Rune(int value) { throw null; } - [System.CLSCompliantAttribute(false)] - public Rune(uint value) { throw null; } - public bool IsAscii { get { throw null; } } - public bool IsBmp { get { throw null; } } - public int Plane { get { throw null; } } - public static System.Text.Rune ReplacementChar { get { throw null; } } - public int Utf16SequenceLength { get { throw null; } } - public int Utf8SequenceLength { get { throw null; } } - public int Value { get { throw null; } } - public int CompareTo(System.Text.Rune other) { throw null; } - public static System.Buffers.OperationStatus DecodeFromUtf16(System.ReadOnlySpan source, out System.Text.Rune result, out int charsConsumed) { throw null; } - public static System.Buffers.OperationStatus DecodeFromUtf8(System.ReadOnlySpan source, out System.Text.Rune result, out int bytesConsumed) { throw null; } - public static System.Buffers.OperationStatus DecodeLastFromUtf16(System.ReadOnlySpan source, out System.Text.Rune result, out int charsConsumed) { throw null; } - public static System.Buffers.OperationStatus DecodeLastFromUtf8(System.ReadOnlySpan source, out System.Text.Rune value, out int bytesConsumed) { throw null; } - public int EncodeToUtf16(System.Span destination) { throw null; } - public int EncodeToUtf8(System.Span destination) { throw null; } - public override bool Equals(object? obj) { throw null; } - public bool Equals(System.Text.Rune other) { throw null; } - public override int GetHashCode() { throw null; } - public static double GetNumericValue(System.Text.Rune value) { throw null; } - public static System.Text.Rune GetRuneAt(string input, int index) { throw null; } - public static System.Globalization.UnicodeCategory GetUnicodeCategory(System.Text.Rune value) { throw null; } - public static bool IsControl(System.Text.Rune value) { throw null; } - public static bool IsDigit(System.Text.Rune value) { throw null; } - public static bool IsLetter(System.Text.Rune value) { throw null; } - public static bool IsLetterOrDigit(System.Text.Rune value) { throw null; } - public static bool IsLower(System.Text.Rune value) { throw null; } - public static bool IsNumber(System.Text.Rune value) { throw null; } - public static bool IsPunctuation(System.Text.Rune value) { throw null; } - public static bool IsSeparator(System.Text.Rune value) { throw null; } - public static bool IsSymbol(System.Text.Rune value) { throw null; } - public static bool IsUpper(System.Text.Rune value) { throw null; } - public static bool IsValid(int value) { throw null; } - [System.CLSCompliantAttribute(false)] - public static bool IsValid(uint value) { throw null; } - public static bool IsWhiteSpace(System.Text.Rune value) { throw null; } - public static bool operator ==(System.Text.Rune left, System.Text.Rune right) { throw null; } - public static explicit operator System.Text.Rune(char ch) { throw null; } - public static explicit operator System.Text.Rune(int value) { throw null; } - [System.CLSCompliantAttribute(false)] - public static explicit operator System.Text.Rune(uint value) { throw null; } - public static bool operator >(System.Text.Rune left, System.Text.Rune right) { throw null; } - public static bool operator >=(System.Text.Rune left, System.Text.Rune right) { throw null; } - public static bool operator !=(System.Text.Rune left, System.Text.Rune right) { throw null; } - public static bool operator <(System.Text.Rune left, System.Text.Rune right) { throw null; } - public static bool operator <=(System.Text.Rune left, System.Text.Rune right) { throw null; } - public static System.Text.Rune ToLower(System.Text.Rune value, System.Globalization.CultureInfo culture) { throw null; } - public static System.Text.Rune ToLowerInvariant(System.Text.Rune value) { throw null; } - public override string ToString() { throw null; } - public static System.Text.Rune ToUpper(System.Text.Rune value, System.Globalization.CultureInfo culture) { throw null; } - public static System.Text.Rune ToUpperInvariant(System.Text.Rune value) { throw null; } - public static bool TryCreate(char highSurrogate, char lowSurrogate, out System.Text.Rune result) { throw null; } - public static bool TryCreate(char ch, out System.Text.Rune result) { throw null; } - public static bool TryCreate(int value, out System.Text.Rune result) { throw null; } - [System.CLSCompliantAttribute(false)] - public static bool TryCreate(uint value, out System.Text.Rune result) { throw null; } - public bool TryEncodeToUtf16(System.Span destination, out int charsWritten) { throw null; } - public bool TryEncodeToUtf8(System.Span destination, out int bytesWritten) { throw null; } - public static bool TryGetRuneAt(string input, int index, out System.Text.Rune value) { throw null; } - int IComparable.CompareTo(object? obj) { throw null; } - } -} diff --git a/src/libraries/System.Utf8String.Experimental/ref/System.Utf8String.Experimental.cs b/src/libraries/System.Utf8String.Experimental/ref/System.Utf8String.Experimental.cs deleted file mode 100644 index a72e76090dead..0000000000000 --- a/src/libraries/System.Utf8String.Experimental/ref/System.Utf8String.Experimental.cs +++ /dev/null @@ -1,442 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// ------------------------------------------------------------------------------ -// Changes to this file must follow the https://aka.ms/api-review process. -// ------------------------------------------------------------------------------ - -namespace System -{ - public readonly partial struct Char8 : System.IComparable, System.IEquatable - { - private readonly int _dummyPrimitive; - public int CompareTo(System.Char8 other) { throw null; } - public bool Equals(System.Char8 other) { throw null; } - public override bool Equals(object? obj) { throw null; } - public override int GetHashCode() { throw null; } - public static bool operator ==(System.Char8 left, System.Char8 right) { throw null; } - public static explicit operator System.Char8(char value) { throw null; } - public static explicit operator char(System.Char8 value) { throw null; } - [System.CLSCompliantAttribute(false)] - public static explicit operator sbyte(System.Char8 value) { throw null; } - public static explicit operator System.Char8(short value) { throw null; } - public static explicit operator System.Char8(int value) { throw null; } - public static explicit operator System.Char8(long value) { throw null; } - [System.CLSCompliantAttribute(false)] - public static explicit operator System.Char8(sbyte value) { throw null; } - [System.CLSCompliantAttribute(false)] - public static explicit operator System.Char8(ushort value) { throw null; } - [System.CLSCompliantAttribute(false)] - public static explicit operator System.Char8(uint value) { throw null; } - [System.CLSCompliantAttribute(false)] - public static explicit operator System.Char8(ulong value) { throw null; } - public static bool operator >(System.Char8 left, System.Char8 right) { throw null; } - public static bool operator >=(System.Char8 left, System.Char8 right) { throw null; } - public static implicit operator System.Char8(byte value) { throw null; } - public static implicit operator byte(System.Char8 value) { throw null; } - public static implicit operator short(System.Char8 value) { throw null; } - public static implicit operator int(System.Char8 value) { throw null; } - public static implicit operator long(System.Char8 value) { throw null; } - [System.CLSCompliantAttribute(false)] - public static implicit operator ushort(System.Char8 value) { throw null; } - [System.CLSCompliantAttribute(false)] - public static implicit operator uint(System.Char8 value) { throw null; } - [System.CLSCompliantAttribute(false)] - public static implicit operator ulong(System.Char8 value) { throw null; } - public static bool operator !=(System.Char8 left, System.Char8 right) { throw null; } - public static bool operator <(System.Char8 left, System.Char8 right) { throw null; } - public static bool operator <=(System.Char8 left, System.Char8 right) { throw null; } - public override string ToString() { throw null; } - } - public static partial class Utf8Extensions - { - public static System.ReadOnlySpan AsBytes(this System.ReadOnlySpan text) { throw null; } - public static System.ReadOnlySpan AsBytes(this System.Utf8String? text) { throw null; } - public static System.ReadOnlySpan AsBytes(this System.Utf8String? text, int start) { throw null; } - public static System.ReadOnlySpan AsBytes(this System.Utf8String? text, int start, int length) { throw null; } - public static System.ReadOnlyMemory AsMemoryBytes(this System.Utf8String? text) { throw null; } - public static System.ReadOnlyMemory AsMemoryBytes(this System.Utf8String? text, System.Index startIndex) { throw null; } - public static System.ReadOnlyMemory AsMemoryBytes(this System.Utf8String? text, int start) { throw null; } - public static System.ReadOnlyMemory AsMemoryBytes(this System.Utf8String? text, int start, int length) { throw null; } - public static System.ReadOnlyMemory AsMemoryBytes(this System.Utf8String? text, System.Range range) { throw null; } - public static System.Text.Utf8Span AsSpan(this System.Utf8String? text) { throw null; } - public static System.Text.Utf8Span AsSpan(this System.Utf8String? text, int start) { throw null; } - public static System.Text.Utf8Span AsSpan(this System.Utf8String? text, int start, int length) { throw null; } - public static System.Utf8String ToUtf8String(this System.Text.Rune rune) { throw null; } - } - public sealed partial class Utf8String : System.IComparable, System.IEquatable - { - public static readonly System.Utf8String Empty; - [System.CLSCompliantAttribute(false)] - public unsafe Utf8String(byte* value) { } - public Utf8String(byte[] value, int startIndex, int length) { } - [System.CLSCompliantAttribute(false)] - public unsafe Utf8String(char* value) { } - public Utf8String(char[] value, int startIndex, int length) { } - public Utf8String(System.ReadOnlySpan value) { } - public Utf8String(System.ReadOnlySpan value) { } - public Utf8String(string value) { } - public ByteEnumerable Bytes { get { throw null; } } - public CharEnumerable Chars { get { throw null; } } - public int Length { get { throw null; } } - public RuneEnumerable Runes { get { throw null; } } - public static bool AreEquivalent(System.Utf8String? utf8Text, string? utf16Text) { throw null; } - public static bool AreEquivalent(System.Text.Utf8Span utf8Text, System.ReadOnlySpan utf16Text) { throw null; } - public static bool AreEquivalent(System.ReadOnlySpan utf8Text, System.ReadOnlySpan utf16Text) { throw null; } - public int CompareTo(System.Utf8String? other) { throw null; } - public int CompareTo(System.Utf8String? other, System.StringComparison comparison) { throw null; } - public bool Contains(char value) { throw null; } - public bool Contains(char value, System.StringComparison comparison) { throw null; } - public bool Contains(System.Text.Rune value) { throw null; } - public bool Contains(System.Text.Rune value, System.StringComparison comparison) { throw null; } - public bool Contains(System.Utf8String value) { throw null; } - public bool Contains(System.Utf8String value, System.StringComparison comparison) { throw null; } -#if !NETSTANDARD2_0 && !NETFRAMEWORK - public static System.Utf8String Create(int length, TState state, System.Buffers.SpanAction action) { throw null; } -#endif - public static System.Utf8String CreateFromRelaxed(System.ReadOnlySpan buffer) { throw null; } - public static System.Utf8String CreateFromRelaxed(System.ReadOnlySpan buffer) { throw null; } -#if !NETSTANDARD2_0 && !NETFRAMEWORK - public static System.Utf8String CreateRelaxed(int length, TState state, System.Buffers.SpanAction action) { throw null; } -#endif - public bool EndsWith(char value) { throw null; } - public bool EndsWith(char value, System.StringComparison comparison) { throw null; } - public bool EndsWith(System.Text.Rune value) { throw null; } - public bool EndsWith(System.Text.Rune value, System.StringComparison comparison) { throw null; } - public bool EndsWith(System.Utf8String value) { throw null; } - public bool EndsWith(System.Utf8String value, System.StringComparison comparison) { throw null; } - public override bool Equals(object? obj) { throw null; } - public static bool Equals(System.Utf8String? a, System.Utf8String? b, System.StringComparison comparison) { throw null; } - public static bool Equals(System.Utf8String? left, System.Utf8String? right) { throw null; } - public bool Equals(System.Utf8String? value) { throw null; } - public bool Equals(System.Utf8String? value, System.StringComparison comparison) { throw null; } - public override int GetHashCode() { throw null; } - public int GetHashCode(System.StringComparison comparison) { throw null; } - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public ref readonly byte GetPinnableReference() { throw null; } - public static implicit operator System.Text.Utf8Span(System.Utf8String? value) { throw null; } - public bool IsAscii() { throw null; } - public bool IsNormalized(System.Text.NormalizationForm normalizationForm = System.Text.NormalizationForm.FormC) { throw null; } - public static bool IsNullOrEmpty([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(false)] System.Utf8String? value) { throw null; } - public static bool IsNullOrWhiteSpace([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(false)] System.Utf8String? value) { throw null; } - public System.Utf8String Normalize(System.Text.NormalizationForm normalizationForm = System.Text.NormalizationForm.FormC) { throw null; } - public static bool operator !=(System.Utf8String? left, System.Utf8String? right) { throw null; } - public static bool operator ==(System.Utf8String? left, System.Utf8String? right) { throw null; } - public SplitResult Split(char separator, System.Utf8StringSplitOptions options = System.Utf8StringSplitOptions.None) { throw null; } - public SplitResult Split(System.Text.Rune separator, System.Utf8StringSplitOptions options = System.Utf8StringSplitOptions.None) { throw null; } - public SplitResult Split(System.Utf8String separator, System.Utf8StringSplitOptions options = System.Utf8StringSplitOptions.None) { throw null; } - public SplitOnResult SplitOn(char separator) { throw null; } - public SplitOnResult SplitOn(char separator, System.StringComparison comparisonType) { throw null; } - public SplitOnResult SplitOn(System.Text.Rune separator) { throw null; } - public SplitOnResult SplitOn(System.Text.Rune separator, System.StringComparison comparisonType) { throw null; } - public SplitOnResult SplitOn(System.Utf8String separator) { throw null; } - public SplitOnResult SplitOn(System.Utf8String separator, System.StringComparison comparisonType) { throw null; } - public SplitOnResult SplitOnLast(char separator) { throw null; } - public SplitOnResult SplitOnLast(char separator, System.StringComparison comparisonType) { throw null; } - public SplitOnResult SplitOnLast(System.Text.Rune separator) { throw null; } - public SplitOnResult SplitOnLast(System.Text.Rune separator, System.StringComparison comparisonType) { throw null; } - public SplitOnResult SplitOnLast(System.Utf8String separator) { throw null; } - public SplitOnResult SplitOnLast(System.Utf8String separator, System.StringComparison comparisonType) { throw null; } - public bool StartsWith(char value) { throw null; } - public bool StartsWith(char value, System.StringComparison comparison) { throw null; } - public bool StartsWith(System.Text.Rune value) { throw null; } - public bool StartsWith(System.Text.Rune value, System.StringComparison comparison) { throw null; } - public bool StartsWith(System.Utf8String value) { throw null; } - public bool StartsWith(System.Utf8String value, System.StringComparison comparison) { throw null; } - public System.Utf8String this[System.Range range] { get { throw null; } } - public byte[] ToByteArray() { throw null; } - public char[] ToCharArray() { throw null; } - public System.Utf8String ToLower(System.Globalization.CultureInfo culture) { throw null; } - public System.Utf8String ToLowerInvariant() { throw null; } - public override string ToString() { throw null; } - public System.Utf8String ToUpper(System.Globalization.CultureInfo culture) { throw null; } - public System.Utf8String ToUpperInvariant() { throw null; } - public System.Utf8String Trim() { throw null; } - public System.Utf8String TrimEnd() { throw null; } - public System.Utf8String TrimStart() { throw null; } - public static bool TryCreateFrom(System.ReadOnlySpan buffer, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Utf8String? value) { throw null; } - public static bool TryCreateFrom(System.ReadOnlySpan buffer, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Utf8String? value) { throw null; } - public bool TryFind(char value, out System.Range range) { throw null; } - public bool TryFind(char value, System.StringComparison comparisonType, out System.Range range) { throw null; } - public bool TryFind(System.Text.Rune value, out System.Range range) { throw null; } - public bool TryFind(System.Text.Rune value, System.StringComparison comparisonType, out System.Range range) { throw null; } - public bool TryFind(System.Utf8String value, out System.Range range) { throw null; } - public bool TryFind(System.Utf8String value, System.StringComparison comparisonType, out System.Range range) { throw null; } - public bool TryFindLast(char value, out System.Range range) { throw null; } - public bool TryFindLast(char value, System.StringComparison comparisonType, out System.Range range) { throw null; } - public bool TryFindLast(System.Text.Rune value, out System.Range range) { throw null; } - public bool TryFindLast(System.Text.Rune value, System.StringComparison comparisonType, out System.Range range) { throw null; } - public bool TryFindLast(System.Utf8String value, out System.Range range) { throw null; } - public bool TryFindLast(System.Utf8String value, System.StringComparison comparisonType, out System.Range range) { throw null; } - public static System.Utf8String UnsafeCreateWithoutValidation(System.ReadOnlySpan utf8Contents) { throw null; } -#if !NETSTANDARD2_0 && !NETFRAMEWORK - public static System.Utf8String UnsafeCreateWithoutValidation(int length, TState state, System.Buffers.SpanAction action) { throw null; } -#endif - public readonly partial struct ByteEnumerable : System.Collections.Generic.IEnumerable - { - private readonly object _dummy; - public Enumerator GetEnumerator() { throw null; } - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { throw null; } - System.Collections.Generic.IEnumerator System.Collections.Generic.IEnumerable.GetEnumerator() { throw null; } - public struct Enumerator : System.Collections.Generic.IEnumerator - { - private readonly object _dummy; - private readonly int _dummyPrimitive; - public readonly byte Current { get { throw null; } } - public bool MoveNext() { throw null; } - void System.IDisposable.Dispose() { } - object System.Collections.IEnumerator.Current { get { throw null; } } - void System.Collections.IEnumerator.Reset() { } - } - } - public readonly partial struct CharEnumerable : System.Collections.Generic.IEnumerable - { - private readonly object _dummy; - public Enumerator GetEnumerator() { throw null; } - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { throw null; } - System.Collections.Generic.IEnumerator System.Collections.Generic.IEnumerable.GetEnumerator() { throw null; } - public struct Enumerator : System.Collections.Generic.IEnumerator - { - private readonly object _dummy; - private readonly int _dummyPrimitive; - public char Current { get { throw null; } } - public bool MoveNext() { throw null; } - void System.IDisposable.Dispose() { } - object System.Collections.IEnumerator.Current { get { throw null; } } - void System.Collections.IEnumerator.Reset() { } - } - } - public readonly partial struct RuneEnumerable : System.Collections.Generic.IEnumerable - { - private readonly object _dummy; - public Enumerator GetEnumerator() { throw null; } - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { throw null; } - System.Collections.Generic.IEnumerator System.Collections.Generic.IEnumerable.GetEnumerator() { throw null; } - public struct Enumerator : System.Collections.Generic.IEnumerator - { - private readonly object _dummy; - private readonly int _dummyPrimitive; - public System.Text.Rune Current { get { throw null; } } - public bool MoveNext() { throw null; } - void System.IDisposable.Dispose() { } - object System.Collections.IEnumerator.Current { get { throw null; } } - void System.Collections.IEnumerator.Reset() { } - } - } - public readonly struct SplitResult : System.Collections.Generic.IEnumerable - { - private readonly object _dummy; - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public void Deconstruct(out System.Utf8String? item1, out System.Utf8String? item2) { throw null; } - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public void Deconstruct(out System.Utf8String? item1, out System.Utf8String? item2, out System.Utf8String? item3) { throw null; } - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public void Deconstruct(out System.Utf8String? item1, out System.Utf8String? item2, out System.Utf8String? item3, out System.Utf8String? item4) { throw null; } - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public void Deconstruct(out System.Utf8String? item1, out System.Utf8String? item2, out System.Utf8String? item3, out System.Utf8String? item4, out System.Utf8String? item5) { throw null; } - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public void Deconstruct(out System.Utf8String? item1, out System.Utf8String? item2, out System.Utf8String? item3, out System.Utf8String? item4, out System.Utf8String? item5, out System.Utf8String? item6) { throw null; } - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public void Deconstruct(out System.Utf8String? item1, out System.Utf8String? item2, out System.Utf8String? item3, out System.Utf8String? item4, out System.Utf8String? item5, out System.Utf8String? item6, out System.Utf8String? item7) { throw null; } - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public void Deconstruct(out System.Utf8String? item1, out System.Utf8String? item2, out System.Utf8String? item3, out System.Utf8String? item4, out System.Utf8String? item5, out System.Utf8String? item6, out System.Utf8String? item7, out System.Utf8String? item8) { throw null; } - public Enumerator GetEnumerator() { throw null; } - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { throw null; } - System.Collections.Generic.IEnumerator System.Collections.Generic.IEnumerable.GetEnumerator() { throw null; } - public struct Enumerator : System.Collections.Generic.IEnumerator - { - private readonly object _dummy; - public System.Utf8String? Current { get { throw null; } } - public bool MoveNext() { throw null; } - void System.IDisposable.Dispose() { } - object? System.Collections.IEnumerator.Current { get { throw null; } } - void System.Collections.IEnumerator.Reset() { throw null; } - } - } - public readonly struct SplitOnResult - { - private readonly object _dummy; - public System.Utf8String? After { get { throw null; } } - public System.Utf8String Before { get { throw null; } } - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public void Deconstruct(out System.Utf8String before, out System.Utf8String? after) { throw null; } - } - } - [System.FlagsAttribute] - public enum Utf8StringSplitOptions - { - None = 0, - RemoveEmptyEntries = 1, - TrimEntries = 2 - } -} -namespace System.Net.Http -{ - public sealed partial class Utf8StringContent : System.Net.Http.HttpContent - { - public Utf8StringContent(System.Utf8String content) { } - public Utf8StringContent(System.Utf8String content, string? mediaType) { } - protected override System.Threading.Tasks.Task CreateContentReadStreamAsync() { throw null; } - protected override System.Threading.Tasks.Task SerializeToStreamAsync(System.IO.Stream stream, System.Net.TransportContext? context) { throw null; } - protected override bool TryComputeLength(out long length) { throw null; } - } -} -namespace System.Text -{ - public readonly ref partial struct Utf8Span - { - private readonly object _dummy; - private readonly int _dummyPrimitive; - public Utf8Span(System.Utf8String? value) { throw null; } - public System.ReadOnlySpan Bytes { get { throw null; } } - public CharEnumerable Chars { get { throw null; } } - public static System.Text.Utf8Span Empty { get { throw null; } } - public bool IsEmpty { get { throw null; } } - public int Length { get { throw null; } } - public RuneEnumerable Runes { get { throw null; } } - public int CompareTo(System.Text.Utf8Span other) { throw null; } - public int CompareTo(System.Text.Utf8Span other, System.StringComparison comparison) { throw null; } - public bool Contains(char value) { throw null; } - public bool Contains(char value, System.StringComparison comparison) { throw null; } - public bool Contains(System.Text.Rune value) { throw null; } - public bool Contains(System.Text.Rune value, System.StringComparison comparison) { throw null; } - public bool Contains(System.Text.Utf8Span value) { throw null; } - public bool Contains(System.Text.Utf8Span value, System.StringComparison comparison) { throw null; } - public bool EndsWith(char value) { throw null; } - public bool EndsWith(char value, System.StringComparison comparison) { throw null; } - public bool EndsWith(System.Text.Rune value) { throw null; } - public bool EndsWith(System.Text.Rune value, System.StringComparison comparison) { throw null; } - public bool EndsWith(System.Text.Utf8Span value) { throw null; } - public bool EndsWith(System.Text.Utf8Span value, System.StringComparison comparison) { throw null; } - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - [System.ObsoleteAttribute("Equals(object) on Utf8Span will always throw an exception. Use Equals(Utf8Span) or == instead.")] - public override bool Equals(object? obj) { throw null; } - public bool Equals(System.Text.Utf8Span other) { throw null; } - public bool Equals(System.Text.Utf8Span other, System.StringComparison comparison) { throw null; } - public static bool Equals(System.Text.Utf8Span left, System.Text.Utf8Span right) { throw null; } - public static bool Equals(System.Text.Utf8Span left, System.Text.Utf8Span right, System.StringComparison comparison) { throw null; } - public override int GetHashCode() { throw null; } - public int GetHashCode(System.StringComparison comparison) { throw null; } - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public ref readonly byte GetPinnableReference() { throw null; } - public bool IsAscii() { throw null; } - public bool IsEmptyOrWhiteSpace() { throw null; } - public bool IsNormalized(System.Text.NormalizationForm normalizationForm = System.Text.NormalizationForm.FormC) { throw null; } - public System.Utf8String Normalize(System.Text.NormalizationForm normalizationForm = System.Text.NormalizationForm.FormC) { throw null; } - public int Normalize(System.Span destination, System.Text.NormalizationForm normalizationForm = System.Text.NormalizationForm.FormC) { throw null; } - public static bool operator !=(System.Text.Utf8Span left, System.Text.Utf8Span right) { throw null; } - public static bool operator ==(System.Text.Utf8Span left, System.Text.Utf8Span right) { throw null; } - public System.Text.Utf8Span this[System.Range range] { get { throw null; } } - public SplitResult Split(char separator, System.Utf8StringSplitOptions options = System.Utf8StringSplitOptions.None) { throw null; } - public SplitResult Split(System.Text.Rune separator, System.Utf8StringSplitOptions options = System.Utf8StringSplitOptions.None) { throw null; } - public SplitResult Split(System.Text.Utf8Span separator, System.Utf8StringSplitOptions options = System.Utf8StringSplitOptions.None) { throw null; } - public SplitOnResult SplitOn(char separator) { throw null; } - public SplitOnResult SplitOn(char separator, System.StringComparison comparisonType) { throw null; } - public SplitOnResult SplitOn(System.Text.Rune separator) { throw null; } - public SplitOnResult SplitOn(System.Text.Rune separator, System.StringComparison comparisonType) { throw null; } - public SplitOnResult SplitOn(System.Text.Utf8Span separator) { throw null; } - public SplitOnResult SplitOn(System.Text.Utf8Span separator, System.StringComparison comparisonType) { throw null; } - public SplitOnResult SplitOnLast(char separator) { throw null; } - public SplitOnResult SplitOnLast(char separator, System.StringComparison comparisonType) { throw null; } - public SplitOnResult SplitOnLast(System.Text.Rune separator) { throw null; } - public SplitOnResult SplitOnLast(System.Text.Rune separator, System.StringComparison comparisonType) { throw null; } - public SplitOnResult SplitOnLast(System.Text.Utf8Span separator) { throw null; } - public SplitOnResult SplitOnLast(System.Text.Utf8Span separator, System.StringComparison comparisonType) { throw null; } - public bool StartsWith(char value) { throw null; } - public bool StartsWith(char value, System.StringComparison comparison) { throw null; } - public bool StartsWith(System.Text.Rune value) { throw null; } - public bool StartsWith(System.Text.Rune value, System.StringComparison comparison) { throw null; } - public bool StartsWith(System.Text.Utf8Span value) { throw null; } - public bool StartsWith(System.Text.Utf8Span value, System.StringComparison comparison) { throw null; } - public System.Text.Utf8Span Trim() { throw null; } - public System.Text.Utf8Span TrimEnd() { throw null; } - public System.Text.Utf8Span TrimStart() { throw null; } - public byte[] ToByteArray() { throw null; } - public char[] ToCharArray() { throw null; } - public int ToChars(System.Span destination) { throw null; } - public System.Utf8String ToLower(System.Globalization.CultureInfo culture) { throw null; } - public int ToLower(System.Span destination, System.Globalization.CultureInfo culture) { throw null; } - public System.Utf8String ToLowerInvariant() { throw null; } - public int ToLowerInvariant(System.Span destination) { throw null; } - public override string ToString() { throw null; } - public System.Utf8String ToUpper(System.Globalization.CultureInfo culture) { throw null; } - public int ToUpper(System.Span destination, System.Globalization.CultureInfo culture) { throw null; } - public System.Utf8String ToUpperInvariant() { throw null; } - public int ToUpperInvariant(System.Span destination) { throw null; } - public System.Utf8String ToUtf8String() { throw null; } - public bool TryFind(char value, out System.Range range) { throw null; } - public bool TryFind(char value, System.StringComparison comparisonType, out System.Range range) { throw null; } - public bool TryFind(System.Text.Rune value, out System.Range range) { throw null; } - public bool TryFind(System.Text.Rune value, System.StringComparison comparisonType, out System.Range range) { throw null; } - public bool TryFind(System.Text.Utf8Span value, out System.Range range) { throw null; } - public bool TryFind(System.Text.Utf8Span value, System.StringComparison comparisonType, out System.Range range) { throw null; } - public bool TryFindLast(char value, out System.Range range) { throw null; } - public bool TryFindLast(char value, System.StringComparison comparisonType, out System.Range range) { throw null; } - public bool TryFindLast(System.Text.Rune value, out System.Range range) { throw null; } - public bool TryFindLast(System.Text.Rune value, System.StringComparison comparisonType, out System.Range range) { throw null; } - public bool TryFindLast(System.Text.Utf8Span value, out System.Range range) { throw null; } - public bool TryFindLast(System.Text.Utf8Span value, System.StringComparison comparisonType, out System.Range range) { throw null; } - public static System.Text.Utf8Span UnsafeCreateWithoutValidation(System.ReadOnlySpan buffer) { throw null; } - public readonly ref struct CharEnumerable - { - private readonly object _dummy; - private readonly int _dummyPrimitive; - public Enumerator GetEnumerator() { throw null; } - public ref struct Enumerator - { - private object _dummy; - private int _dummyPrimitive; - public char Current { get { throw null; } } - public bool MoveNext() { throw null; } - } - } - public readonly ref struct RuneEnumerable - { - private readonly object _dummy; - private readonly int _dummyPrimitive; - public Enumerator GetEnumerator() { throw null; } - public ref struct Enumerator - { - private object _dummy; - private int _dummyPrimitive; - public System.Text.Rune Current { get { throw null; } } - public bool MoveNext() { throw null; } - } - } - public readonly ref struct SplitResult - { - private readonly object _dummy; - private readonly int _dummyPrimitive; - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public void Deconstruct(out System.Text.Utf8Span item1, out System.Text.Utf8Span item2) { throw null; } - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public void Deconstruct(out System.Text.Utf8Span item1, out System.Text.Utf8Span item2, out System.Text.Utf8Span item3) { throw null; } - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public void Deconstruct(out System.Text.Utf8Span item1, out System.Text.Utf8Span item2, out System.Text.Utf8Span item3, out System.Text.Utf8Span item4) { throw null; } - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public void Deconstruct(out System.Text.Utf8Span item1, out System.Text.Utf8Span item2, out System.Text.Utf8Span item3, out System.Text.Utf8Span item4, out System.Text.Utf8Span item5) { throw null; } - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public void Deconstruct(out System.Text.Utf8Span item1, out System.Text.Utf8Span item2, out System.Text.Utf8Span item3, out System.Text.Utf8Span item4, out System.Text.Utf8Span item5, out System.Text.Utf8Span item6) { throw null; } - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public void Deconstruct(out System.Text.Utf8Span item1, out System.Text.Utf8Span item2, out System.Text.Utf8Span item3, out System.Text.Utf8Span item4, out System.Text.Utf8Span item5, out System.Text.Utf8Span item6, out System.Text.Utf8Span item7) { throw null; } - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public void Deconstruct(out System.Text.Utf8Span item1, out System.Text.Utf8Span item2, out System.Text.Utf8Span item3, out System.Text.Utf8Span item4, out System.Text.Utf8Span item5, out System.Text.Utf8Span item6, out System.Text.Utf8Span item7, out System.Text.Utf8Span item8) { throw null; } - public Enumerator GetEnumerator() { throw null; } - public ref struct Enumerator - { - private readonly object _dummy; - private readonly int _dummyPrimitive; - public System.Text.Utf8Span Current { get { throw null; } } - public bool MoveNext() { throw null; } - } - } - public readonly ref struct SplitOnResult - { - private readonly object _dummy; - private readonly int _dummyPrimitive; - public Utf8Span After { get { throw null; } } - public Utf8Span Before { get { throw null; } } - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public void Deconstruct(out System.Text.Utf8Span before, out System.Text.Utf8Span after) { throw null; } - } - } -} diff --git a/src/libraries/System.Utf8String.Experimental/ref/System.Utf8String.Experimental.csproj b/src/libraries/System.Utf8String.Experimental/ref/System.Utf8String.Experimental.csproj deleted file mode 100644 index eb5a1414f8cdf..0000000000000 --- a/src/libraries/System.Utf8String.Experimental/ref/System.Utf8String.Experimental.csproj +++ /dev/null @@ -1,43 +0,0 @@ - - - true - - $(NoWarn);0809;0618 - netstandard2.0;netstandard2.1;netcoreapp3.0;$(NetCoreAppCurrent);net461 - enable - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/libraries/System.Utf8String.Experimental/ref/System.Utf8String.Experimental.net5.0.cs b/src/libraries/System.Utf8String.Experimental/ref/System.Utf8String.Experimental.net5.0.cs deleted file mode 100644 index 85f2598f8de55..0000000000000 --- a/src/libraries/System.Utf8String.Experimental/ref/System.Utf8String.Experimental.net5.0.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// ------------------------------------------------------------------------------ -// Changes to this file must follow the https://aka.ms/api-review process. -// ------------------------------------------------------------------------------ - -namespace System -{ - public static partial class Utf8Extensions - { - public static System.ReadOnlyMemory AsMemory(this System.Utf8String? text) { throw null; } - public static System.ReadOnlyMemory AsMemory(this System.Utf8String? text, System.Index startIndex) { throw null; } - public static System.ReadOnlyMemory AsMemory(this System.Utf8String? text, int start) { throw null; } - public static System.ReadOnlyMemory AsMemory(this System.Utf8String? text, int start, int length) { throw null; } - public static System.ReadOnlyMemory AsMemory(this System.Utf8String? text, System.Range range) { throw null; } - } -} -namespace System.Net.Http -{ - public sealed partial class Utf8StringContent : System.Net.Http.HttpContent - { - protected override System.IO.Stream CreateContentReadStream(System.Threading.CancellationToken cancellationToken) { throw null; } - protected override void SerializeToStream(System.IO.Stream stream, System.Net.TransportContext? context, System.Threading.CancellationToken cancellationToken) { } - protected override System.Threading.Tasks.Task SerializeToStreamAsync(System.IO.Stream stream, System.Net.TransportContext? context, System.Threading.CancellationToken cancellationToken) { throw null; } - } -} diff --git a/src/libraries/System.Utf8String.Experimental/src/Resources/Strings.resx b/src/libraries/System.Utf8String.Experimental/src/Resources/Strings.resx deleted file mode 100644 index 3d5159021118a..0000000000000 --- a/src/libraries/System.Utf8String.Experimental/src/Resources/Strings.resx +++ /dev/null @@ -1,171 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Index was out of range. Must be non-negative and less than the size of the collection. - - - Non-negative number required. - - - UTF-16 surrogate code points (U+D800..U+DFFF) are disallowed. - - - Argument cannot be an empty span. - - - Argument cannot be null or empty. - - - Cannot extract a Unicode scalar value from the specified index in the input. - - - Destination is too short. - - - Illegal enum value: {0}. - - - The string must be null-terminated. - - - The string comparison type passed in is currently not supported. - - - Cannot call Utf8Span.Equals(object). Use Equals(Utf8Span) or operator == instead. - - - UTF-8 searching only supports StringComparison Ordinal and OrdinalIgnoreCase on this platform. - - - The callback populated its buffer with ill-formed UTF-8 data. Callbacks are required to populate the buffer only with well-formed UTF-8 data. - - - Cannot create the desired substring because it would split a multi-byte UTF-8 subsequence. - - - The input buffer contained ill-formed UTF-16 data. - - - The input buffer contained ill-formed UTF-8 data. - - - Object must be of type Rune. - - \ No newline at end of file diff --git a/src/libraries/System.Utf8String.Experimental/src/System.Utf8String.Experimental.csproj b/src/libraries/System.Utf8String.Experimental/src/System.Utf8String.Experimental.csproj deleted file mode 100644 index 8b72b9161c557..0000000000000 --- a/src/libraries/System.Utf8String.Experimental/src/System.Utf8String.Experimental.csproj +++ /dev/null @@ -1,154 +0,0 @@ - - - true - $(NetCoreAppCurrent);netstandard2.0;netstandard2.1;netcoreapp3.0;net461 - enable - $(DefineContants);FEATURE_UTF8STRING - - - - - - $(NoWarn);CS3019;CS0162 - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/libraries/System.Utf8String.Experimental/src/System/Globalization/GlobalizationMode.cs b/src/libraries/System.Utf8String.Experimental/src/System/Globalization/GlobalizationMode.cs deleted file mode 100644 index a59114c85bff0..0000000000000 --- a/src/libraries/System.Utf8String.Experimental/src/System/Globalization/GlobalizationMode.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace System.Globalization -{ - internal static partial class GlobalizationMode - { - internal static bool Invariant { get; } // TODO: should we enable this? - } -} diff --git a/src/libraries/System.Utf8String.Experimental/src/System/IO/Utf8StringStream.cs b/src/libraries/System.Utf8String.Experimental/src/System/IO/Utf8StringStream.cs deleted file mode 100644 index d448a7cc1b909..0000000000000 --- a/src/libraries/System.Utf8String.Experimental/src/System/IO/Utf8StringStream.cs +++ /dev/null @@ -1,141 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Threading; -using System.Threading.Tasks; - -namespace System.IO -{ - internal sealed class Utf8StringStream : Stream - { - private readonly Utf8String _content; - private int _position; - - public Utf8StringStream(Utf8String content) - { - _content = content ?? Utf8String.Empty; - } - - public override bool CanRead => true; - - public override bool CanSeek => true; - - public override bool CanTimeout => true; - - public override bool CanWrite => false; - - public override long Length => _content.Length; - - public override long Position - { - get => _position; - set - { - if ((ulong)value > (uint)_content.Length) - { - throw new ArgumentOutOfRangeException(nameof(value)); - } - - _position = (int)value; - } - } - - public override void Flush() - { - /* no-op */ - } - - public override Task FlushAsync(CancellationToken cancellationToken) - { - /* no-op */ - return Task.CompletedTask; - } - - public override int Read(byte[] buffer, int offset, int count) - { - return Read(new Span(buffer, offset, count)); - } - - public -#if (!NETSTANDARD2_0 && !NETFRAMEWORK) - override -#endif - int Read(Span buffer) - { - ReadOnlySpan contentToWrite = _content.AsBytes(_position); - if (buffer.Length < contentToWrite.Length) - { - contentToWrite = contentToWrite.Slice(buffer.Length); - } - - contentToWrite.CopyTo(buffer); - _position += contentToWrite.Length; - - return contentToWrite.Length; - } - - public override Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) - { - return Task.FromResult(Read(new Span(buffer, offset, count))); - } - -#if (!NETSTANDARD2_0 && !NETFRAMEWORK) - public override ValueTask ReadAsync(Memory buffer, CancellationToken cancellationToken = default) - { - return new ValueTask(Read(buffer.Span)); - } -#endif - - public override int ReadByte() - { - int position = _position; - if ((uint)position >= (uint)_content.Length) - { - return -1; - } - - _position++; - return _content.AsBytes()[position]; - } - - public override long Seek(long offset, SeekOrigin origin) - { - switch (origin) - { - case SeekOrigin.Begin: - break; - case SeekOrigin.Current: - offset += _position; - break; - case SeekOrigin.End: - offset += _content.Length; - break; - default: - throw new ArgumentOutOfRangeException(nameof(origin)); - } - - if ((ulong)offset > (uint)_content.Length) - { - throw new ArgumentOutOfRangeException(nameof(offset)); - } - - _position = (int)offset; - return offset; - } - - public override void SetLength(long value) => throw new NotSupportedException(); - - public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException(); - -#if (!NETSTANDARD2_0 && !NETFRAMEWORK) - public override void Write(ReadOnlySpan buffer) => throw new NotSupportedException(); -#endif - - public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) => throw new NotSupportedException(); - -#if (!NETSTANDARD2_0 && !NETFRAMEWORK) - public override ValueTask WriteAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken = default) => throw new NotSupportedException(); -#endif - public override void WriteByte(byte value) => throw new NotSupportedException(); - } -} diff --git a/src/libraries/System.Utf8String.Experimental/src/System/Net/Http/Utf8StringContent.cs b/src/libraries/System.Utf8String.Experimental/src/System/Net/Http/Utf8StringContent.cs deleted file mode 100644 index f5fc6a1f843b4..0000000000000 --- a/src/libraries/System.Utf8String.Experimental/src/System/Net/Http/Utf8StringContent.cs +++ /dev/null @@ -1,79 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Buffers; -using System.IO; -using System.Net.Http.Headers; -using System.Runtime.InteropServices; -using System.Threading; -using System.Threading.Tasks; - -namespace System.Net.Http -{ - public sealed partial class Utf8StringContent : HttpContent - { - private const string DefaultMediaType = "text/plain"; - - private readonly Utf8String _content; - - public Utf8StringContent(Utf8String content) - : this(content, mediaType: null) - { - } - - public Utf8StringContent(Utf8String content, string? mediaType) - { - if (content is null) - { - throw new ArgumentNullException(nameof(content)); - } - - _content = content; - - // Initialize the 'Content-Type' header with information provided by parameters. - - Headers.ContentType = new MediaTypeHeaderValue(mediaType ?? DefaultMediaType) - { - CharSet = "utf-8" // Encoding.UTF8.WebName - }; - } - - protected override Task CreateContentReadStreamAsync() => - Task.FromResult(new Utf8StringStream(_content)); - -#if (NETSTANDARD2_0 || NETFRAMEWORK) - protected override async Task SerializeToStreamAsync(Stream stream, TransportContext? context) - { - ReadOnlyMemory buffer = _content.AsMemoryBytes(); - if (MemoryMarshal.TryGetArray(buffer, out ArraySegment array)) - { - await stream.WriteAsync(array.Array, array.Offset, array.Count).ConfigureAwait(false); - } - else - { - byte[] localBuffer = ArrayPool.Shared.Rent(buffer.Length); - buffer.Span.CopyTo(localBuffer); - - await stream.WriteAsync(localBuffer, 0, buffer.Length).ConfigureAwait(false); - - ArrayPool.Shared.Return(localBuffer); - } - } -#elif NETSTANDARD2_1 || NETCOREAPP3_0 - protected override Task SerializeToStreamAsync(Stream stream, TransportContext? context) => - stream.WriteAsync(_content.AsMemoryBytes()).AsTask(); -#else - protected override Task SerializeToStreamAsync(Stream stream, TransportContext? context) => - SerializeToStreamAsync(stream, context, default); - - protected override Task SerializeToStreamAsync(Stream stream, TransportContext? context, CancellationToken cancellationToken) => - stream.WriteAsync(_content.AsMemoryBytes(), cancellationToken).AsTask(); -#endif - - protected override bool TryComputeLength(out long length) - { - length = _content.Length; - return true; - } - } -} diff --git a/src/libraries/System.Utf8String.Experimental/src/System/Net/Http/Utf8StringContent.netcoreapp.cs b/src/libraries/System.Utf8String.Experimental/src/System/Net/Http/Utf8StringContent.netcoreapp.cs deleted file mode 100644 index 15eba26150941..0000000000000 --- a/src/libraries/System.Utf8String.Experimental/src/System/Net/Http/Utf8StringContent.netcoreapp.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Buffers; -using System.IO; -using System.Net.Http.Headers; -using System.Runtime.InteropServices; -using System.Threading; -using System.Threading.Tasks; - -namespace System.Net.Http -{ - public sealed partial class Utf8StringContent - { - protected override Stream CreateContentReadStream(CancellationToken cancellationToken) => - new Utf8StringStream(_content); - - protected override void SerializeToStream(Stream stream, TransportContext? context, CancellationToken cancellationToken) => - stream.Write(_content.AsBytes()); - } -} diff --git a/src/libraries/System.Utf8String.Experimental/src/System/Runtime/Intrinsics/Intrinsics.Shims.cs b/src/libraries/System.Utf8String.Experimental/src/System/Runtime/Intrinsics/Intrinsics.Shims.cs deleted file mode 100644 index ff020e0259cfd..0000000000000 --- a/src/libraries/System.Utf8String.Experimental/src/System/Runtime/Intrinsics/Intrinsics.Shims.cs +++ /dev/null @@ -1,149 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace System.Runtime.Intrinsics -{ - internal static class Vector64 - { - public static Vector64 Create(ulong value) => throw new PlatformNotSupportedException(); - public static Vector64 CreateScalar(uint value) => throw new PlatformNotSupportedException(); - public static Vector64 AsByte(this Vector64 vector) where T : struct => throw new PlatformNotSupportedException(); - public static Vector64 AsUInt32(this Vector64 vector) where T : struct => throw new PlatformNotSupportedException(); - public static Vector64 GetLower(this Vector128 vector) where T : struct => throw new PlatformNotSupportedException(); - public static Vector64 AsUInt64(this Vector64 vector) where T : struct => throw new PlatformNotSupportedException(); - } - internal readonly struct Vector64 - where T : struct - { - } - - internal static class Vector128 - { - public static Vector128 Create(long value) => throw new PlatformNotSupportedException(); - public static Vector128 Create(short value) => throw new PlatformNotSupportedException(); - public static Vector128 Create(ulong value) => throw new PlatformNotSupportedException(); - public static Vector128 Create(ushort value) => throw new PlatformNotSupportedException(); - public static Vector128 Create(byte value) => throw new PlatformNotSupportedException(); - public static Vector128 Create(uint value) => throw new PlatformNotSupportedException(); - public static Vector128 CreateScalarUnsafe(ulong value) => throw new PlatformNotSupportedException(); - public static Vector128 AsByte(this Vector128 vector) where T : struct => throw new PlatformNotSupportedException(); - public static Vector128 AsInt16(this Vector128 vector) where T : struct => throw new PlatformNotSupportedException(); - public static Vector128 AsSByte(this Vector128 vector) where T : struct => throw new PlatformNotSupportedException(); - public static Vector128 AsUInt16(this Vector128 vector) where T : struct => throw new PlatformNotSupportedException(); - public static Vector128 AsUInt32(this Vector128 vector) where T : struct => throw new PlatformNotSupportedException(); - public static Vector128 AsUInt64(this Vector128 vector) where T : struct => throw new PlatformNotSupportedException(); - public static T GetElement(this Vector128 vector, int index) where T : struct => throw new PlatformNotSupportedException(); - public static T ToScalar(this Vector64 vector) where T : struct => throw new PlatformNotSupportedException(); - public static unsafe Vector128 CreateScalar(ulong value) => throw new PlatformNotSupportedException(); - public static T ToScalar(this Vector128 vector) where T : struct => throw new PlatformNotSupportedException(); - } - internal readonly struct Vector128 - where T : struct - { - public static Vector128 Zero => throw new PlatformNotSupportedException(); - public static int Count => throw new PlatformNotSupportedException(); - } -} - -namespace System.Runtime.Intrinsics.X86 -{ - internal static class X86Base - { - internal static class X64 - { - public const bool IsSupported = false; - internal static ulong BitScanForward(ulong value) => throw new PlatformNotSupportedException(); - internal static ulong BitScanReverse(ulong value) => throw new PlatformNotSupportedException(); - } - public const bool IsSupported = false; - internal static uint BitScanForward(uint value) => throw new PlatformNotSupportedException(); - internal static uint BitScanReverse(uint value) => throw new PlatformNotSupportedException(); - } - internal abstract class Bmi1 - { - public abstract class X64 - { - public const bool IsSupported = false; - public static ulong TrailingZeroCount(ulong value) => throw new PlatformNotSupportedException(); - } - public const bool IsSupported = false; - public static uint TrailingZeroCount(uint value) => throw new PlatformNotSupportedException(); - } - internal abstract class Lzcnt - { - public abstract class X64 - { - public const bool IsSupported = false; - public static ulong LeadingZeroCount(ulong value) => throw new PlatformNotSupportedException(); - } - public const bool IsSupported = false; - public static uint LeadingZeroCount(uint value) => throw new PlatformNotSupportedException(); - } - internal abstract class Popcnt - { - public abstract class X64 - { - public const bool IsSupported = false; - public static ulong PopCount(ulong value) => throw new PlatformNotSupportedException(); - } - public const bool IsSupported = false; - public static uint PopCount(uint value) => throw new PlatformNotSupportedException(); - } - - internal abstract class Sse2 - { - public abstract class X64 - { - public const bool IsSupported = false; - public static Vector128 ConvertScalarToVector128UInt64(ulong value) => throw new PlatformNotSupportedException(); - public static ulong ConvertToUInt64(Vector128 value) => throw new PlatformNotSupportedException(); - } - public const bool IsSupported = false; - public static Vector128 Add(Vector128 left, Vector128 right) => throw new PlatformNotSupportedException(); - public static Vector128 AddSaturate(Vector128 left, Vector128 right) => throw new PlatformNotSupportedException(); - public static Vector128 AndNot(Vector128 left, Vector128 right) => throw new PlatformNotSupportedException(); - public static Vector128 CompareGreaterThan(Vector128 left, Vector128 right) => throw new PlatformNotSupportedException(); - public static Vector128 CompareLessThan(Vector128 left, Vector128 right) => throw new PlatformNotSupportedException(); - public static Vector128 ConvertScalarToVector128UInt32(uint value) => throw new PlatformNotSupportedException(); - public static uint ConvertToUInt32(Vector128 value) => throw new PlatformNotSupportedException(); - public static unsafe Vector128 LoadAlignedVector128(byte* address) => throw new PlatformNotSupportedException(); - public static unsafe Vector128 LoadAlignedVector128(ushort* address) => throw new PlatformNotSupportedException(); - public static unsafe Vector128 LoadVector128(byte* address) => throw new PlatformNotSupportedException(); - public static unsafe Vector128 LoadVector128(short* address) => throw new PlatformNotSupportedException(); - public static unsafe Vector128 LoadVector128(ushort* address) => throw new PlatformNotSupportedException(); - public static int MoveMask(Vector128 value) => throw new PlatformNotSupportedException(); - public static Vector128 Or(Vector128 left, Vector128 right) => throw new PlatformNotSupportedException(); - public static Vector128 Or(Vector128 left, Vector128 right) => throw new PlatformNotSupportedException(); - public static Vector128 PackUnsignedSaturate(Vector128 left, Vector128 right) => throw new PlatformNotSupportedException(); - public static Vector128 ShiftRightLogical(Vector128 value, byte count) => throw new PlatformNotSupportedException(); - public static unsafe void Store(byte* address, Vector128 source) => throw new PlatformNotSupportedException(); - public static unsafe void StoreAligned(byte* address, Vector128 source) => throw new PlatformNotSupportedException(); - public static unsafe void StoreScalar(ulong* address, Vector128 source) => throw new PlatformNotSupportedException(); - public static Vector128 Subtract(Vector128 left, Vector128 right) => throw new PlatformNotSupportedException(); - public static Vector128 UnpackHigh(Vector128 left, Vector128 right) => throw new PlatformNotSupportedException(); - public static Vector128 UnpackLow(Vector128 left, Vector128 right) => throw new PlatformNotSupportedException(); - } - - internal abstract class Sse41 - { - public abstract class X64 - { - public const bool IsSupported = false; - } - public const bool IsSupported = false; - public static Vector128 Min(Vector128 left, Vector128 right) => throw new PlatformNotSupportedException(); - public static bool TestZ(Vector128 left, Vector128 right) => throw new PlatformNotSupportedException(); - public static bool TestZ(Vector128 left, Vector128 right) => throw new PlatformNotSupportedException(); - } -} - -namespace System.Runtime.CompilerServices -{ - // Calls to methods or references to fields marked with this attribute may be replaced at - // some call sites with jit intrinsic expansions. - // Types marked with this attribute may be specially treated by the runtime/compiler. - [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Field, Inherited = false)] - internal sealed class IntrinsicAttribute : Attribute - { - } -} diff --git a/src/libraries/System.Utf8String.Experimental/src/System/ThrowHelper.cs b/src/libraries/System.Utf8String.Experimental/src/System/ThrowHelper.cs deleted file mode 100644 index 2df780d86fee8..0000000000000 --- a/src/libraries/System.Utf8String.Experimental/src/System/ThrowHelper.cs +++ /dev/null @@ -1,94 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Diagnostics.CodeAnalysis; -using System.Runtime.CompilerServices; - -namespace System -{ - internal static class ThrowHelper - { - [DoesNotReturn] - internal static void ThrowArgumentException(string resource, ExceptionArgument argument) - { - throw new ArgumentException(resource, argument.ToString()); - } - - [DoesNotReturn] - internal static void ThrowArgumentNullException(ExceptionArgument argument) { throw CreateArgumentNullException(argument); } - [MethodImpl(MethodImplOptions.NoInlining)] - private static Exception CreateArgumentNullException(ExceptionArgument argument) { return new ArgumentNullException(argument.ToString()); } - - [DoesNotReturn] - internal static void ThrowArgumentOutOfRangeException() { throw new ArgumentOutOfRangeException(); } - - internal static void ThrowArgumentOutOfRangeException(ExceptionArgument argument) { throw CreateArgumentOutOfRangeException(argument); } - [MethodImpl(MethodImplOptions.NoInlining)] - private static Exception CreateArgumentOutOfRangeException(ExceptionArgument argument) { return new ArgumentOutOfRangeException(argument.ToString()); } - - [DoesNotReturn] - internal static void ThrowValueArgumentOutOfRange_NeedNonNegNumException() - { - throw GetArgumentOutOfRangeException(ExceptionArgument.value, - SR.ArgumentOutOfRange_NeedNonNegNum); - } - - [DoesNotReturn] - internal static void ThrowLengthArgumentOutOfRange_ArgumentOutOfRange_NeedNonNegNum() - { - throw GetArgumentOutOfRangeException(ExceptionArgument.length, - SR.ArgumentOutOfRange_NeedNonNegNum); - } - - [DoesNotReturn] - internal static void ThrowInvalidOperationException() { throw CreateInvalidOperationException(); } - [MethodImpl(MethodImplOptions.NoInlining)] - private static Exception CreateInvalidOperationException() { return new InvalidOperationException(); } - - [DoesNotReturn] - internal static void ThrowArgumentException_DestinationTooShort() - { - throw new ArgumentException(SR.Argument_DestinationTooShort, "destination"); - } - - [DoesNotReturn] - internal static void ThrowArgumentException_CannotExtractScalar(ExceptionArgument argument) - { - throw new ArgumentException(SR.Argument_CannotExtractScalar, argument.ToString()); - } - - internal static void ThrowArgumentOutOfRange_IndexException() - { - throw GetArgumentOutOfRangeException(ExceptionArgument.index, - SR.ArgumentOutOfRange_Index); - } - - private static ArgumentOutOfRangeException GetArgumentOutOfRangeException(ExceptionArgument argument, string resource) - { - return new ArgumentOutOfRangeException(argument.ToString(), resource); - } - - [DoesNotReturn] - internal static void ThrowNotSupportedException(string message) - { - throw new NotSupportedException(message); - } - } - - // - // The convention for this enum is using the argument name as the enum name - // - internal enum ExceptionArgument - { - action, - ch, - comparisonType, - culture, - index, - input, - length, - start, - text, - value, - } -} diff --git a/src/libraries/System.Utf8String.Experimental/src/System/Utf8Extensions.Portable.cs b/src/libraries/System.Utf8String.Experimental/src/System/Utf8Extensions.Portable.cs deleted file mode 100644 index 8a881022fbbc2..0000000000000 --- a/src/libraries/System.Utf8String.Experimental/src/System/Utf8Extensions.Portable.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Runtime.CompilerServices; - -namespace System -{ - public static partial class Utf8Extensions - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static ReadOnlySpan CreateSpan(Utf8String text) => text.GetSpan(); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static ReadOnlySpan CreateSpan(Utf8String text, int start) => - text.GetSpan().Slice(start); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static ReadOnlySpan CreateSpan(Utf8String text, int start, int length) => - text.GetSpan().Slice(start, length); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static ReadOnlyMemory CreateMemoryBytes(Utf8String text, int start, int length) => - text.CreateMemoryBytes(start, length); - } -} diff --git a/src/libraries/System.Utf8String.Experimental/src/System/Utf8String.Portable.cs b/src/libraries/System.Utf8String.Experimental/src/System/Utf8String.Portable.cs deleted file mode 100644 index da0a4de8cc2d1..0000000000000 --- a/src/libraries/System.Utf8String.Experimental/src/System/Utf8String.Portable.cs +++ /dev/null @@ -1,239 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.ComponentModel; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Text.Unicode; - -namespace System -{ - public sealed partial class Utf8String - { - private readonly byte[] _bytes; - - /// - /// Returns the length (in UTF-8 code units, or s) of this instance. - /// - public int Length => _bytes.Length - 1; // -1 because the bytes are always null-terminated - - public Utf8String(ReadOnlySpan value) - { - _bytes = InitializeBuffer(value); - } - - public Utf8String(byte[] value, int startIndex, int length) - { - if (value is null) - { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); - } - - _bytes = InitializeBuffer(new ReadOnlySpan(value, startIndex, length)); - } - - [CLSCompliant(false)] - public unsafe Utf8String(byte* value) - { - if (value is null) - { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); - } - - _bytes = InitializeBuffer(new ReadOnlySpan(value, strlen(value))); - } - - public Utf8String(ReadOnlySpan value) - { - _bytes = InitializeBuffer(value); - } - - public Utf8String(char[] value, int startIndex, int length) - { - if (value is null) - { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); - } - - _bytes = InitializeBuffer(new ReadOnlySpan(value, startIndex, length)); - } - - [CLSCompliant(false)] - public unsafe Utf8String(char* value) - { - if (value == null) - { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); - } - - _bytes = InitializeBuffer(new ReadOnlySpan(value, wcslen(value))); - } - - public Utf8String(string value) - { - if (value is null) - { - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); - } - - _bytes = InitializeBuffer(value.AsSpan()); - } - - private static byte[] InitializeBuffer(ReadOnlySpan value) - { - if (value.IsEmpty) - { - return Empty._bytes; - } - - // Create and populate the Utf8String buffer. - - byte[] newBuffer = AllocateBuffer(value.Length); - value.CopyTo(newBuffer); - - // Now perform validation. - // Reminder: Perform validation over the copy, not over the source. - - if (!Utf8Utility.IsWellFormedUtf8(newBuffer)) - { - throw new ArgumentException( - message: SR.Utf8String_InputContainedMalformedUtf8, - paramName: nameof(value)); - } - - return newBuffer; - } - - private static byte[] InitializeBuffer(ReadOnlySpan value) - { - byte[]? newBuffer = CreateBufferFromUtf16Common(value, replaceInvalidSequences: false); - - if (newBuffer is null) - { - // Input buffer contained invalid UTF-16 data. - - throw new ArgumentException( - message: SR.Utf8String_InputContainedMalformedUtf16, - paramName: nameof(value)); - } - - return newBuffer; - } - - // This should only be called from FastAllocate - private Utf8String(byte[] bytes) - { - _bytes = bytes; - } - - /// - /// Returns a mutable reference to the first byte of this - /// (or the null terminator if the string is empty). - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal ref byte DangerousGetMutableReference() => - ref MemoryMarshal.GetReference(_bytes.AsSpan()); - - /// - /// Returns a mutable that can be used to populate this - /// instance. Only to be used during construction. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal Span DangerousGetMutableSpan() - { - Debug.Assert(Length > 0, $"This should only ever be called on a non-empty {nameof(Utf8String)}."); - return _bytes.AsSpan(0, Length); - } - - /// - /// Returns a for this - /// instance. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal ReadOnlySpan GetSpan() => _bytes.AsSpan(0, Length); - - /// - /// Gets an immutable reference that can be used in a statement. The resulting - /// reference can be pinned and used as a null-terminated LPCUTF8STR. - /// - /// - /// If this instance is empty, returns a reference to the null terminator. - /// - [EditorBrowsable(EditorBrowsableState.Never)] // for compiler use only - public ref readonly byte GetPinnableReference() => ref _bytes.AsSpan().GetPinnableReference(); - - /// - /// Similar to , but skips the null check on the input. - /// Throws a if the input is null. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal ReadOnlySpan AsBytesSkipNullCheck() => GetSpan(); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal ReadOnlyMemory CreateMemoryBytes(int start, int length) => - _bytes.AsMemory(start, length); - - /// - /// Creates a new zero-initialized instance of the specified length. Actual storage allocated is "length + 1" bytes - /// because instances are null-terminated. - /// - /// - /// The implementation of this method checks its input argument for overflow. - /// - private static Utf8String FastAllocate(int length) - { - // just simulate a "fast allocate", since this is portable - return new Utf8String(AllocateBuffer(length)); - } - - private static byte[] AllocateBuffer(int length) - { - Debug.Assert(length > 0); - - if (length == int.MaxValue) - { - // Ensure we don't overflow below. The VM will throw an OutOfMemoryException - // if we try to create a byte[] this large anyway. - length = int.MaxValue - 1; - } - - // Actual storage allocated is "length + 1" bytes because instances are null-terminated. - return new byte[length + 1]; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static unsafe int wcslen(char* ptr) - { - // IndexOf processes memory in aligned chunks, and thus it won't crash even if it accesses memory beyond the null terminator. - int length = new ReadOnlySpan(ptr, int.MaxValue).IndexOf('\0'); - if (length < 0) - { - ThrowMustBeNullTerminatedString(); - } - - return length; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static unsafe int strlen(byte* ptr) - { - // IndexOf processes memory in aligned chunks, and thus it won't crash even if it accesses memory beyond the null terminator. - int length = new ReadOnlySpan(ptr, int.MaxValue).IndexOf((byte)'\0'); - if (length < 0) - { - ThrowMustBeNullTerminatedString(); - } - - return length; - } - - [DoesNotReturn] - private static void ThrowMustBeNullTerminatedString() - { - throw new ArgumentException(SR.Arg_MustBeNullTerminatedString); - } - } -} diff --git a/src/libraries/System.Utf8String.Experimental/tests/System.Utf8String.Experimental.Tests.csproj b/src/libraries/System.Utf8String.Experimental/tests/System.Utf8String.Experimental.Tests.csproj deleted file mode 100644 index 73efb5b00c82d..0000000000000 --- a/src/libraries/System.Utf8String.Experimental/tests/System.Utf8String.Experimental.Tests.csproj +++ /dev/null @@ -1,53 +0,0 @@ - - - true - true - $(NetCoreAppCurrent);net461 - true - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/libraries/System.Utf8String.Experimental/tests/System/BoundedUtf8Span.cs b/src/libraries/System.Utf8String.Experimental/tests/System/BoundedUtf8Span.cs deleted file mode 100644 index 26f07e5889b2f..0000000000000 --- a/src/libraries/System.Utf8String.Experimental/tests/System/BoundedUtf8Span.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Buffers; -using System.Text; - -using static System.Tests.Utf8TestUtilities; - -namespace System.Tests -{ - /// - /// Allows creating instances that wrap . - /// Useful for ensuring an API under test doesn't read past the end of the span. - /// - public sealed class BoundedUtf8Span : IDisposable - { - private readonly BoundedMemory _boundedMemory; - - public BoundedUtf8Span(string utf16Data, PoisonPagePlacement placement = PoisonPagePlacement.After) - : this(utf16Data.AsSpan(), placement) - { - } - - public BoundedUtf8Span(ReadOnlySpan utf16Data, PoisonPagePlacement placement = PoisonPagePlacement.After) - : this(u8(utf16Data.ToString()).AsBytes(), placement) - { - } - - public BoundedUtf8Span(ReadOnlySpan utf8Data, PoisonPagePlacement placement = PoisonPagePlacement.After) - { - _boundedMemory = BoundedMemory.AllocateFromExistingData(utf8Data, placement); - } - - public Utf8Span Span => Utf8Span.UnsafeCreateWithoutValidation(_boundedMemory.Span); - - public void Dispose() - { - _boundedMemory.Dispose(); - } - } -} diff --git a/src/libraries/System.Utf8String.Experimental/tests/System/Char8Tests.cs b/src/libraries/System.Utf8String.Experimental/tests/System/Char8Tests.cs deleted file mode 100644 index d5f00ac25564d..0000000000000 --- a/src/libraries/System.Utf8String.Experimental/tests/System/Char8Tests.cs +++ /dev/null @@ -1,112 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Globalization; -using Xunit; - -namespace System.Tests -{ - [SkipOnMono("The features from System.Utf8String.Experimental namespace are experimental.")] - public unsafe partial class Char8Tests - { - [Theory] - [InlineData(10, 20, -1)] - [InlineData(20, 10, 1)] - [InlineData(30, 30, 0)] - public static void CompareTo(int a, int b, int expectedSign) - { - Assert.Equal(expectedSign, Math.Sign(((Char8)a).CompareTo((Char8)b))); - } - - [Theory] - [InlineData(-1)] - [InlineData(0xFF)] - [InlineData(0x80)] - [InlineData(0x00)] - [InlineData(0x1234)] - [InlineData(0x12345678)] - [InlineData(0x1234567812345678)] - public static void CastOperators(long value) - { - // Only the low byte is preserved when casting through Char8. - - Assert.Equal((byte)value, (byte)(Char8)(byte)value); - Assert.Equal((sbyte)value, (sbyte)(Char8)(sbyte)value); - Assert.Equal((char)(value & 0xFF), (char)(Char8)(char)value); - Assert.Equal((short)(value & 0xFF), (short)(Char8)(short)value); - Assert.Equal((ushort)(value & 0xFF), (ushort)(Char8)(ushort)value); - Assert.Equal((int)(value & 0xFF), (int)(Char8)(int)value); - Assert.Equal((uint)(value & 0xFF), (uint)(Char8)(uint)value); - Assert.Equal((long)(value & 0xFF), (long)(Char8)(long)value); - Assert.Equal((ulong)(value & 0xFF), (ulong)(Char8)(ulong)value); - } - - [Fact] - public static void EqualsObject() - { - Assert.False(((Char8)42).Equals((object)null)); - Assert.False(((Char8)42).Equals((object)(int)42)); - Assert.False(((Char8)42).Equals((object)(Char8)43)); - Assert.True(((Char8)42).Equals((object)(Char8)42)); - } - - [Fact] - public static void EqualsChar8() - { - Assert.True(((Char8)42).Equals(42)); // implicit cast to Char8 - Assert.False(((Char8)42).Equals(43)); // implicit cast to Char8 - } - - [Fact] - public static void GetHashCode_ReturnsValue() - { - for (int i = 0; i <= byte.MaxValue; i++) - { - Assert.Equal(i, ((Char8)i).GetHashCode()); - } - } - - [Theory] - [InlineData(10, 20, false)] - [InlineData(20, 10, false)] - [InlineData(30, 30, true)] - public static void OperatorEquals(int a, int b, bool expected) - { - Assert.Equal(expected, (Char8)a == (Char8)b); - Assert.NotEqual(expected, (Char8)a != (Char8)b); - } - - [Theory] - [InlineData(10, 20, true)] - [InlineData(20, 10, false)] - [InlineData(29, 30, true)] - [InlineData(30, 30, false)] - [InlineData(31, 30, false)] - public static void OperatorLessThan(int a, int b, bool expected) - { - Assert.Equal(expected, (Char8)a < (Char8)b); - Assert.NotEqual(expected, (Char8)a >= (Char8)b); - } - - [Theory] - [InlineData(10, 20, false)] - [InlineData(20, 10, true)] - [InlineData(29, 30, false)] - [InlineData(30, 30, false)] - [InlineData(31, 30, true)] - public static void OperatorGreaterThan(int a, int b, bool expected) - { - Assert.Equal(expected, (Char8)a > (Char8)b); - Assert.NotEqual(expected, (Char8)a <= (Char8)b); - } - - [Fact] - public static void ToString_ReturnsHexValue() - { - for (int i = 0; i <= byte.MaxValue; i++) - { - Assert.Equal(i.ToString("X2", CultureInfo.InvariantCulture), ((Char8)i).ToString()); - } - } - } -} diff --git a/src/libraries/System.Utf8String.Experimental/tests/System/MemoryTests.cs b/src/libraries/System.Utf8String.Experimental/tests/System/MemoryTests.cs deleted file mode 100644 index f6185fd5baa6c..0000000000000 --- a/src/libraries/System.Utf8String.Experimental/tests/System/MemoryTests.cs +++ /dev/null @@ -1,77 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Buffers; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using Xunit; - -using static System.Tests.Utf8TestUtilities; - -namespace System.Tests -{ - [SkipOnMono("The features from System.Utf8String.Experimental namespace are experimental.")] - public partial class MemoryTests - { - [Fact] - public static unsafe void MemoryOfByte_WithUtf8String_Pin() - { - Utf8String theString = u8("Hello"); - ReadOnlyMemory rom = theString.AsMemoryBytes(); - MemoryHandle memHandle = default; - try - { - memHandle = Unsafe.As, Memory>(ref rom).Pin(); - Assert.True(memHandle.Pointer == Unsafe.AsPointer(ref Unsafe.AsRef(in theString.GetPinnableReference()))); - } - finally - { - memHandle.Dispose(); - } - } - - [Fact] - public static void MemoryOfByte_WithUtf8String_ToString() - { - ReadOnlyMemory rom = u8("Hello").AsMemoryBytes(); - Assert.Equal("System.Memory[5]", Unsafe.As, Memory>(ref rom).ToString()); - } - - [Fact] - public static unsafe void ReadOnlyMemoryOfByte_WithUtf8String_Pin() - { - Utf8String theString = u8("Hello"); - ReadOnlyMemory rom = theString.AsMemoryBytes(); - MemoryHandle memHandle = default; - try - { - memHandle = rom.Pin(); - Assert.True(memHandle.Pointer == Unsafe.AsPointer(ref Unsafe.AsRef(in theString.GetPinnableReference()))); - } - finally - { - memHandle.Dispose(); - } - } - - [Fact] - public static void ReadOnlyMemoryOfByte_WithUtf8String_ToString() - { - Assert.Equal("System.ReadOnlyMemory[5]", u8("Hello").AsMemoryBytes().ToString()); - } - - [Fact] - public static void ReadOnlySpanOfByte_ToString() - { - ReadOnlySpan span = stackalloc byte[] { (byte)'H', (byte)'i' }; - Assert.Equal("System.ReadOnlySpan[2]", span.ToString()); - } - - [Fact] - public static void SpanOfByte_ToString() - { - Span span = stackalloc byte[] { (byte)'H', (byte)'i' }; - Assert.Equal("System.Span[2]", span.ToString()); - } - } -} diff --git a/src/libraries/System.Utf8String.Experimental/tests/System/MemoryTests.netcoreapp.cs b/src/libraries/System.Utf8String.Experimental/tests/System/MemoryTests.netcoreapp.cs deleted file mode 100644 index dd5919baa89ac..0000000000000 --- a/src/libraries/System.Utf8String.Experimental/tests/System/MemoryTests.netcoreapp.cs +++ /dev/null @@ -1,94 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Buffers; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using Xunit; - -using static System.Tests.Utf8TestUtilities; - -namespace System.Tests -{ - public partial class MemoryTests - { - [Fact] - public static void MemoryMarshal_TryGetArrayOfByte_Utf8String() - { - ReadOnlyMemory rom = u8("Hello").AsMemoryBytes(); - - Assert.False(MemoryMarshal.TryGetArray(rom, out ArraySegment segment)); - Assert.True(default(ArraySegment).Equals(segment)); - } - - [Fact] - public static void MemoryMarshal_TryGetArrayOfChar8_Utf8String() - { - ReadOnlyMemory rom = u8("Hello").AsMemory(); - - Assert.False(MemoryMarshal.TryGetArray(rom, out ArraySegment segment)); - Assert.True(default(ArraySegment).Equals(segment)); - } - - [Fact] - public static unsafe void MemoryOfChar8_WithUtf8String_Pin() - { - Utf8String theString = u8("Hello"); - ReadOnlyMemory rom = theString.AsMemory(); - MemoryHandle memHandle = default; - try - { - memHandle = Unsafe.As, Memory>(ref rom).Pin(); - Assert.True(memHandle.Pointer == Unsafe.AsPointer(ref Unsafe.AsRef(in theString.GetPinnableReference()))); - } - finally - { - memHandle.Dispose(); - } - } - - [Fact] - public static void MemoryOfChar8_WithUtf8String_ToString() - { - ReadOnlyMemory rom = u8("Hello").AsMemory(); - Assert.Equal("Hello", Unsafe.As, Memory>(ref rom).ToString()); - } - - [Fact] - public static unsafe void ReadOnlyMemoryOfChar8_WithUtf8String_Pin() - { - Utf8String theString = u8("Hello"); - ReadOnlyMemory rom = theString.AsMemory(); - MemoryHandle memHandle = default; - try - { - memHandle = rom.Pin(); - Assert.True(memHandle.Pointer == Unsafe.AsPointer(ref Unsafe.AsRef(in theString.GetPinnableReference()))); - } - finally - { - memHandle.Dispose(); - } - } - - [Fact] - public static void ReadOnlyMemoryOfChar8_WithUtf8String_ToString() - { - Assert.Equal("Hello", u8("Hello").AsMemory().ToString()); - } - - [Fact] - public static void ReadOnlySpanOfChar8_ToString() - { - ReadOnlySpan span = stackalloc Char8[] { (Char8)'H', (Char8)'i' }; - Assert.Equal("Hi", span.ToString()); - } - - [Fact] - public static void SpanOfChar8_ToString() - { - Span span = stackalloc Char8[] { (Char8)'H', (Char8)'i' }; - Assert.Equal("Hi", span.ToString()); - } - } -} diff --git a/src/libraries/System.Utf8String.Experimental/tests/System/MemoryTests.netfx.cs b/src/libraries/System.Utf8String.Experimental/tests/System/MemoryTests.netfx.cs deleted file mode 100644 index 4c26154e48b8d..0000000000000 --- a/src/libraries/System.Utf8String.Experimental/tests/System/MemoryTests.netfx.cs +++ /dev/null @@ -1,42 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Runtime.InteropServices; -using Xunit; - -using static System.Tests.Utf8TestUtilities; - -namespace System.Tests -{ - public partial class MemoryTests - { - [Fact] - public static void MemoryMarshal_TryGetArrayOfByte_Utf8String() - { - ReadOnlyMemory rom = u8("Hello").AsMemoryBytes(); - - Assert.True(MemoryMarshal.TryGetArray(rom, out ArraySegment segment)); - Assert.NotNull(segment.Array); - Assert.Equal(0, segment.Offset); - Assert.Equal(5, segment.Count); - } - - [Fact] - public static void ReadOnlySpanOfChar8_ToString() - { - // unable to override ReadOnlySpan.ToString on netfx - - ReadOnlySpan span = stackalloc Char8[] { (Char8)'H', (Char8)'i' }; - Assert.Equal("System.ReadOnlySpan[2]", span.ToString()); - } - - [Fact] - public static void SpanOfChar8_ToString() - { - // unable to override Span.ToString on netfx - - Span span = stackalloc Char8[] { (Char8)'H', (Char8)'i' }; - Assert.Equal("System.Span[2]", span.ToString()); - } - } -} diff --git a/src/libraries/System.Utf8String.Experimental/tests/System/Net/Http/Utf8StringContentTests.cs b/src/libraries/System.Utf8String.Experimental/tests/System/Net/Http/Utf8StringContentTests.cs deleted file mode 100644 index 9ea0a4ccb6321..0000000000000 --- a/src/libraries/System.Utf8String.Experimental/tests/System/Net/Http/Utf8StringContentTests.cs +++ /dev/null @@ -1,44 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.IO; -using System.Text; -using System.Threading.Tasks; -using Xunit; - -using static System.Tests.Utf8TestUtilities; - -namespace System.Net.Http.Tests -{ - [SkipOnMono("The features from System.Utf8String.Experimental namespace are experimental.")] - public partial class Utf8StringContentTests - { - [Fact] - public static void Ctor_NullContent_Throws() - { - Assert.Throws("content", () => new Utf8StringContent(null)); - Assert.Throws("content", () => new Utf8StringContent(null, "application/json")); - } - - [Theory] - [InlineData(null, "text/plain")] - [InlineData("application/json", "application/json")] - public static void Ctor_SetsContentTypeHeader(string mediaTypeForCtor, string expectedMediaType) - { - HttpContent httpContent = new Utf8StringContent(u8("Hello"), mediaTypeForCtor); - - Assert.Equal(expectedMediaType, httpContent.Headers.ContentType.MediaType); - Assert.Equal(Encoding.UTF8.WebName, httpContent.Headers.ContentType.CharSet); - } - - [Fact] - public static async Task Ctor_CopyToAsync_GetStream() - { - MemoryStream memoryStream = new MemoryStream(); - - await new Utf8StringContent(u8("Hello")).CopyToAsync(memoryStream); - - Assert.Equal(u8("Hello").ToByteArray(), memoryStream.ToArray()); - } - } -} diff --git a/src/libraries/System.Utf8String.Experimental/tests/System/Net/Http/Utf8StringContentTests.netcoreapp.cs b/src/libraries/System.Utf8String.Experimental/tests/System/Net/Http/Utf8StringContentTests.netcoreapp.cs deleted file mode 100644 index 249bd063004db..0000000000000 --- a/src/libraries/System.Utf8String.Experimental/tests/System/Net/Http/Utf8StringContentTests.netcoreapp.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.IO; -using System.Text; -using System.Threading.Tasks; -using Xunit; - -using static System.Tests.Utf8TestUtilities; - -namespace System.Net.Http.Tests -{ - public partial class Utf8StringContentTests - { - [Fact] - public static void Ctor_CopyTo_GetStream() - { - var memoryStream = new MemoryStream(); - - new Utf8StringContent(u8("Hello")).CopyTo(memoryStream, default, default); - - Assert.Equal(u8("Hello").ToByteArray(), memoryStream.ToArray()); - } - - [Fact] - public static void Ctor_ReadAsStream() - { - var content = new Utf8StringContent(u8("Hello")); - Stream stream = content.ReadAsStream(); - - var memoryStream = new MemoryStream(); - stream.CopyTo(memoryStream); - memoryStream.Seek(0, SeekOrigin.Begin); - Assert.Equal(u8("Hello").ToByteArray(), memoryStream.ToArray()); - } - } -} diff --git a/src/libraries/System.Utf8String.Experimental/tests/System/RangeEqualityComparer.cs b/src/libraries/System.Utf8String.Experimental/tests/System/RangeEqualityComparer.cs deleted file mode 100644 index 417844caa2555..0000000000000 --- a/src/libraries/System.Utf8String.Experimental/tests/System/RangeEqualityComparer.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Collections.Generic; -using Xunit; - -namespace System.Tests -{ - /// - /// Given a fixed length, compares two instances for equality. - /// - public sealed class RangeEqualityComparer : IEqualityComparer - { - private int _length; - - public RangeEqualityComparer(int length) - { - Assert.True(length >= 0); - - _length = length; - } - - public bool Equals(Range x, Range y) - { - (int offsetX, int lengthX) = x.GetOffsetAndLength(_length); - (int offsetY, int lengthY) = y.GetOffsetAndLength(_length); - - return offsetX == offsetY && lengthX == lengthY; - } - - public int GetHashCode(Range obj) - { - (int offset, int length) = obj.GetOffsetAndLength(_length); -#if NETCOREAPP - return HashCode.Combine(offset, length); -#else - return Tuple.Create(offset, length).GetHashCode(); -#endif - } - } -} diff --git a/src/libraries/System.Utf8String.Experimental/tests/System/ReflectionTests.cs b/src/libraries/System.Utf8String.Experimental/tests/System/ReflectionTests.cs deleted file mode 100644 index b402ebf7ff506..0000000000000 --- a/src/libraries/System.Utf8String.Experimental/tests/System/ReflectionTests.cs +++ /dev/null @@ -1,27 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Runtime.Serialization; -using Xunit; - -using static System.Tests.Utf8TestUtilities; - -namespace System.Tests -{ - [SkipOnMono("The features from System.Utf8String.Experimental namespace are experimental.")] - public partial class ReflectionTests - { - [Fact] - public static void ActivatorCreateInstance_CanCallParameterfulCtor() - { - Utf8String theString = (Utf8String)Activator.CreateInstance(typeof(Utf8String), "Hello"); - Assert.Equal(u8("Hello"), theString); - } - - [Fact] - public static void ActivatorCreateInstance_CannotCallParameterlessCtor() - { - Assert.Throws(() => Activator.CreateInstance(typeof(Utf8String))); - } - } -} diff --git a/src/libraries/System.Utf8String.Experimental/tests/System/ReflectionTests.netcoreapp.cs b/src/libraries/System.Utf8String.Experimental/tests/System/ReflectionTests.netcoreapp.cs deleted file mode 100644 index f6ce4770e2473..0000000000000 --- a/src/libraries/System.Utf8String.Experimental/tests/System/ReflectionTests.netcoreapp.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Runtime.Serialization; -using Xunit; - -namespace System.Tests -{ - public partial class ReflectionTests - { - [Fact] - public static void FormatterServices_GetUninitializedObject_Throws() - { - // Like String, shouldn't be able to create an uninitialized Utf8String. - - Assert.Throws(() => FormatterServices.GetSafeUninitializedObject(typeof(Utf8String))); - Assert.Throws(() => FormatterServices.GetUninitializedObject(typeof(Utf8String))); - } - } -} diff --git a/src/libraries/System.Utf8String.Experimental/tests/System/Utf8ExtensionsTests.cs b/src/libraries/System.Utf8String.Experimental/tests/System/Utf8ExtensionsTests.cs deleted file mode 100644 index d68746129348c..0000000000000 --- a/src/libraries/System.Utf8String.Experimental/tests/System/Utf8ExtensionsTests.cs +++ /dev/null @@ -1,163 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using Xunit; - -using static System.Tests.Utf8TestUtilities; - -namespace System.Tests -{ - [SkipOnMono("The features from System.Utf8String.Experimental namespace are experimental.")] - public partial class Utf8ExtensionsTests - { - [Fact] - public unsafe void AsBytes_FromSpan_Default() - { - // First, a default span should become a default span. - - Assert.True(default(ReadOnlySpan) == new ReadOnlySpan().AsBytes()); - - // Next, an empty but non-default span should become an empty but non-default span. - - Assert.True(new ReadOnlySpan((void*)0x12345, 0) == new ReadOnlySpan((void*)0x12345, 0).AsBytes()); - } - - [Fact] - public void AsBytes_FromUtf8String() - { - Assert.True(default(ReadOnlySpan) == ((Utf8String)null).AsBytes()); - } - - [Fact] - public void AsBytes_FromUtf8String_WithStart() - { - Assert.True(default(ReadOnlySpan) == ((Utf8String)null).AsBytes(0)); - Assert.True(u8("Hello").AsBytes(5).IsEmpty); - - SpanAssert.Equal(new byte[] { (byte)'e', (byte)'l', (byte)'l', (byte)'o' }, u8("Hello").AsBytes(1)); - } - - [Fact] - public void AsBytes_FromUtf8String_WithStart_ArgOutOfRange() - { - Assert.Throws("start", () => ((Utf8String)null).AsBytes(1)); - Assert.Throws("start", () => u8("Hello").AsBytes(-1)); - Assert.Throws("start", () => u8("Hello").AsBytes(6)); - } - - [Fact] - public void AsBytes_FromUtf8String_WithStartAndLength() - { - Assert.True(default(ReadOnlySpan) == ((Utf8String)null).AsBytes(0, 0)); - Assert.True(u8("Hello").AsBytes(5, 0).IsEmpty); - - SpanAssert.Equal(new byte[] { (byte)'e', (byte)'l', (byte)'l' }, u8("Hello").AsBytes(1, 3)); - } - - [Fact] - public void AsBytes_FromUtf8String_WithStartAndLength_ArgOutOfRange() - { - Assert.Throws("start", () => ((Utf8String)null).AsBytes(0, 1)); - Assert.Throws("start", () => ((Utf8String)null).AsBytes(1, 0)); - Assert.Throws("start", () => u8("Hello").AsBytes(5, 1)); - Assert.Throws("start", () => u8("Hello").AsBytes(4, -2)); - } - - [Fact] - public unsafe void AsMemoryBytes_FromUtf8String() - { - Assert.True(default(ReadOnlyMemory).Equals(((Utf8String)null).AsMemoryBytes())); - - Utf8String theString = u8("Hello"); - fixed (byte* pTheString = theString) - { - fixed (byte* pTheStringAsMemoryBytes = theString.AsMemoryBytes().Span) - { - Assert.True(pTheString == pTheStringAsMemoryBytes); - } - } - } - - [Fact] - public void AsMemoryBytes_FromUtf8String_WithStart() - { - Assert.True(default(ReadOnlyMemory).Equals(((Utf8String)null).AsMemoryBytes(0))); - Assert.True(u8("Hello").AsMemoryBytes(5).IsEmpty); - - SpanAssert.Equal(new byte[] { (byte)'e', (byte)'l', (byte)'l', (byte)'o' }, u8("Hello").AsMemoryBytes(1).Span); - } - - [Fact] - public void AsMemoryBytes_FromUtf8String_WithStart_ArgOutOfRange() - { - Assert.Throws("start", () => ((Utf8String)null).AsMemoryBytes(1)); - Assert.Throws("start", () => u8("Hello").AsMemoryBytes(-1)); - Assert.Throws("start", () => u8("Hello").AsMemoryBytes(6)); - } - - [Fact] - public void AsMemoryBytes_FromUtf8String_WithStartAndLength() - { - Assert.True(default(ReadOnlyMemory).Equals(((Utf8String)null).AsMemoryBytes(0, 0))); - Assert.True(u8("Hello").AsMemoryBytes(5, 0).IsEmpty); - - SpanAssert.Equal(new byte[] { (byte)'e', (byte)'l', (byte)'l' }, u8("Hello").AsMemoryBytes(1, 3).Span); - } - - [Fact] - public void AsMemoryBytes_FromUtf8String_WithStartAndLength_ArgOutOfRange() - { - Assert.Throws("start", () => ((Utf8String)null).AsMemoryBytes(0, 1)); - Assert.Throws("start", () => ((Utf8String)null).AsMemoryBytes(1, 0)); - Assert.Throws("start", () => u8("Hello").AsMemoryBytes(5, 1)); - Assert.Throws("start", () => u8("Hello").AsMemoryBytes(4, -2)); - } - - [Fact] - public void AsSpan_FromUtf8String() - { - Assert.True(((Utf8String)null).AsSpan().Bytes == default); // referential equality check - - Utf8String theString = u8("Hello"); - - Assert.True(Unsafe.AreSame(ref Unsafe.AsRef(in theString.GetPinnableReference()), ref Unsafe.AsRef(in theString.AsSpan().GetPinnableReference()))); - Assert.Equal(5, theString.AsSpan().Length); - } - - [Fact] - public void AsSpan_FromUtf8String_WithStart() - { - Assert.True(((Utf8String)null).AsSpan(0).Bytes == default); // referential equality check - Assert.True(u8("Hello").AsSpan(5).IsEmpty); - Assert.Equal(new byte[] { (byte)'e', (byte)'l', (byte)'l', (byte)'o' }, u8("Hello").AsSpan(1).Bytes.ToArray()); - } - - [Fact] - public void AsSpan_FromUtf8String_WithStart_ArgOutOfRange() - { - Assert.Throws("start", () => ((Utf8String)null).AsSpan(1)); - Assert.Throws("start", () => u8("Hello").AsSpan(-1)); - Assert.Throws("start", () => u8("Hello").AsSpan(6)); - } - - [Fact] - public void AsSpan_FromUtf8String_WithStartAndLength() - { - Assert.True(((Utf8String)null).AsSpan(0, 0).Bytes == default); // referential equality check - Assert.True(u8("Hello").AsSpan(5, 0).IsEmpty); - Assert.Equal(new byte[] { (byte)'e', (byte)'l', (byte)'l' }, u8("Hello").AsSpan(1, 3).Bytes.ToArray()); - } - - [Fact] - public void AsSpan_FromUtf8String_WithStartAndLength_ArgOutOfRange() - { - Assert.Throws("start", () => ((Utf8String)null).AsSpan(0, 1)); - Assert.Throws("start", () => ((Utf8String)null).AsSpan(1, 0)); - Assert.Throws("start", () => u8("Hello").AsSpan(5, 1)); - Assert.Throws("start", () => u8("Hello").AsSpan(4, -2)); - } - } -} diff --git a/src/libraries/System.Utf8String.Experimental/tests/System/Utf8ExtensionsTests.netcoreapp.cs b/src/libraries/System.Utf8String.Experimental/tests/System/Utf8ExtensionsTests.netcoreapp.cs deleted file mode 100644 index 560946c8b0fcb..0000000000000 --- a/src/libraries/System.Utf8String.Experimental/tests/System/Utf8ExtensionsTests.netcoreapp.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using Xunit; - -using static System.Tests.Utf8TestUtilities; - -namespace System.Tests -{ - public partial class Utf8ExtensionsTests - { - [Fact] - public void AsBytes_FromSpan_Default_netcoreapp() - { - // a span wrapping data should become a span wrapping that same data. - - Utf8String theString = u8("Hello"); - - Assert.True(MemoryMarshal.CreateReadOnlySpan(ref Unsafe.AsRef(in theString.GetPinnableReference()), 5) == (theString.AsMemory().Span).AsBytes()); - } - - [Fact] - public void AsBytes_FromUtf8String_netcoreapp() - { - Utf8String theString = u8("Hello"); - Assert.True(MemoryMarshal.CreateReadOnlySpan(ref Unsafe.AsRef(in theString.GetPinnableReference()), 5) == theString.AsBytes()); - } - - [Fact] - public void AsMemory_FromUtf8String() - { - Assert.True(default(ReadOnlyMemory).Equals(((Utf8String)null).AsMemory())); - - Utf8String theString = u8("Hello"); - Assert.True(MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in theString.GetPinnableReference())), 5) == theString.AsMemory().Span); - } - - [Fact] - public void AsMemory_FromUtf8String_WithStart() - { - Assert.True(default(ReadOnlyMemory).Equals(((Utf8String)null).AsMemory(0))); - Assert.True(u8("Hello").AsMemory(5).IsEmpty); - - SpanAssert.Equal(new Char8[] { (Char8)'e', (Char8)'l', (Char8)'l', (Char8)'o' }, u8("Hello").AsMemory(1).Span); - } - - [Fact] - public void AsMemory_FromUtf8String_WithStart_ArgOutOfRange() - { - Assert.Throws("start", () => ((Utf8String)null).AsMemory(1)); - Assert.Throws("start", () => u8("Hello").AsMemory(-1)); - Assert.Throws("start", () => u8("Hello").AsMemory(6)); - } - - [Fact] - public void AsMemory_FromUtf8String_WithStartAndLength() - { - Assert.True(default(ReadOnlyMemory).Equals(((Utf8String)null).AsMemory(0, 0))); - Assert.True(u8("Hello").AsMemory(5, 0).IsEmpty); - - SpanAssert.Equal(new Char8[] { (Char8)'e', (Char8)'l', (Char8)'l' }, u8("Hello").AsMemory(1, 3).Span); - } - - [Fact] - public void AsMemory_FromUtf8String_WithStartAndLength_ArgOutOfRange() - { - Assert.Throws("start", () => ((Utf8String)null).AsMemory(0, 1)); - Assert.Throws("start", () => ((Utf8String)null).AsMemory(1, 0)); - Assert.Throws("start", () => u8("Hello").AsMemory(5, 1)); - Assert.Throws("start", () => u8("Hello").AsMemory(4, -2)); - } - } -} diff --git a/src/libraries/System.Utf8String.Experimental/tests/System/Utf8SpanTests.Comparison.cs b/src/libraries/System.Utf8String.Experimental/tests/System/Utf8SpanTests.Comparison.cs deleted file mode 100644 index 7cc4f55009ba5..0000000000000 --- a/src/libraries/System.Utf8String.Experimental/tests/System/Utf8SpanTests.Comparison.cs +++ /dev/null @@ -1,125 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Globalization; -using System.Tests; -using Microsoft.DotNet.RemoteExecutor; -using Xunit; - -using static System.Tests.Utf8TestUtilities; - -namespace System.Text.Tests -{ - public partial class Utf8SpanTests - { - [Fact] - public static void Equals_Object_ThrowsNotSupported() - { - Utf8Span span = Utf8Span.Empty; - - Assert.Throws(() => Utf8Span.Empty.Equals((object)null)); - Assert.Throws(() => Utf8Span.Empty.Equals(new object())); - } - - [Fact] - public static void Equals_Ordinal() - { - // First make sure referential equality passes - - Utf8Span span1 = u8("Hello!"); - Utf8Span span2 = span1; - AssertEqualOrdinal(span1, span2); - - // Now make sure deep equality passes - - span2 = Utf8Span.UnsafeCreateWithoutValidation(Encoding.UTF8.GetBytes("Hello!")); - AssertEqualOrdinal(span1, span2); - - // Now mutate one of the inputs and make sure they're inequal - - span2 = u8("Bello!"); - AssertNotEqualOrdinal(span1, span2); - - // Finally, make sure null / null and null / empty are treated as the same - - AssertEqualOrdinal(Utf8Span.Empty, Utf8Span.Empty); - AssertEqualOrdinal(Utf8Span.Empty, u8("")); - } - - [PlatformSpecific(TestPlatforms.Windows)] - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNlsGlobalization))] - [InlineData(null, null, StringComparison.OrdinalIgnoreCase, null, true)] - [InlineData("encyclopaedia", "encyclopædia", StringComparison.OrdinalIgnoreCase, null, false)] - [InlineData("encyclopaedia", "encyclopædia", StringComparison.InvariantCulture, null, true)] - [InlineData("encyclopaedia", "ENCYCLOPÆDIA", StringComparison.InvariantCulture, null, false)] - [InlineData("encyclopaedia", "encyclopædia", StringComparison.InvariantCultureIgnoreCase, null, true)] - [InlineData("encyclopaedia", "ENCYCLOPÆDIA", StringComparison.InvariantCultureIgnoreCase, null, true)] - [InlineData("Weiß", "WEISS", StringComparison.OrdinalIgnoreCase, null, false)] - [InlineData("Weiß", "WEISS", StringComparison.InvariantCulture, null, false)] - [InlineData("Weiß", "WEISS", StringComparison.InvariantCultureIgnoreCase, null, true)] - [InlineData("Weiß", "WEISS", StringComparison.CurrentCulture, "de-DE", false)] - [InlineData("Weiß", "WEISS", StringComparison.CurrentCultureIgnoreCase, "de-DE", true)] - [InlineData("γένεσις", "ΓΈΝΕΣΙΣ", StringComparison.InvariantCultureIgnoreCase, null, true)] - [InlineData("ıI", "iI", StringComparison.CurrentCulture, "tr-TR", false)] - [InlineData("ıI", "iI", StringComparison.CurrentCultureIgnoreCase, "tr-TR", false)] - [InlineData("İI", "iI", StringComparison.CurrentCultureIgnoreCase, "tr-TR", true)] - public static void Equals_NonOrdinal(string str1, string str2, StringComparison comparison, string culture, bool shouldCompareAsEqual) - { - using (new ThreadCultureChange(culture)) - { - using BoundedUtf8Span boundedSpan1 = new BoundedUtf8Span(str1); - using BoundedUtf8Span boundedSpan2 = new BoundedUtf8Span(str2); - - Utf8Span span1 = boundedSpan1.Span; - Utf8Span span2 = boundedSpan2.Span; - - Assert.Equal(shouldCompareAsEqual, span1.Equals(span2, comparison)); - Assert.Equal(shouldCompareAsEqual, span2.Equals(span1, comparison)); - Assert.Equal(shouldCompareAsEqual, Utf8Span.Equals(span1, span2, comparison)); - Assert.Equal(shouldCompareAsEqual, Utf8Span.Equals(span2, span1, comparison)); - } - } - - private static void AssertEqualOrdinal(Utf8Span span1, Utf8Span span2) - { - Assert.True(span1.Equals(span2)); - Assert.True(span2.Equals(span1)); - - Assert.True(span1.Equals(span2, StringComparison.Ordinal)); - Assert.True(span2.Equals(span1, StringComparison.Ordinal)); - - Assert.True(Utf8Span.Equals(span1, span2)); - Assert.True(Utf8Span.Equals(span2, span1)); - - Assert.True(Utf8Span.Equals(span1, span2, StringComparison.Ordinal)); - Assert.True(Utf8Span.Equals(span2, span1, StringComparison.Ordinal)); - - Assert.True(span1 == span2); - Assert.True(span2 == span1); - - Assert.False(span1 != span2); - Assert.False(span2 != span1); - } - - private static void AssertNotEqualOrdinal(Utf8Span span1, Utf8Span span2) - { - Assert.False(span1.Equals(span2)); - Assert.False(span2.Equals(span1)); - - Assert.False(span1.Equals(span2, StringComparison.Ordinal)); - Assert.False(span2.Equals(span1, StringComparison.Ordinal)); - - Assert.False(Utf8Span.Equals(span1, span2)); - Assert.False(Utf8Span.Equals(span2, span1)); - - Assert.False(Utf8Span.Equals(span1, span2, StringComparison.Ordinal)); - Assert.False(Utf8Span.Equals(span2, span1, StringComparison.Ordinal)); - - Assert.False(span1 == span2); - Assert.False(span2 == span1); - - Assert.True(span1 != span2); - Assert.True(span2 != span1); - } - } -} diff --git a/src/libraries/System.Utf8String.Experimental/tests/System/Utf8SpanTests.Conversion.cs b/src/libraries/System.Utf8String.Experimental/tests/System/Utf8SpanTests.Conversion.cs deleted file mode 100644 index 802794c1e69a0..0000000000000 --- a/src/libraries/System.Utf8String.Experimental/tests/System/Utf8SpanTests.Conversion.cs +++ /dev/null @@ -1,241 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Collections.Generic; -using System.Globalization; -using System.Tests; -using Xunit; - -using static System.Tests.Utf8TestUtilities; - -using ustring = System.Utf8String; - -namespace System.Text.Tests -{ - public partial class Utf8SpanTests - { - [Theory] - [MemberData(nameof(NormalizationData))] - public static void Normalize(string utf16Source, string utf16Expected, NormalizationForm normalizationForm) - { - using BoundedUtf8Span boundedSpan = new BoundedUtf8Span(utf16Source); - Utf8Span utf8Source = boundedSpan.Span; - - // Quick IsNormalized tests - - Assert.Equal(utf16Source == utf16Expected, utf8Source.IsNormalized(normalizationForm)); - - // Normalize and return new Utf8String instances - - ustring utf8Normalized = utf8Source.Normalize(normalizationForm); - Assert.True(ustring.AreEquivalent(utf8Normalized, utf16Expected)); - - // Normalize to byte arrays which are too small, expect -1 (failure) - - Assert.Equal(-1, utf8Source.Normalize(new byte[utf8Normalized.Length - 1], normalizationForm)); - - // Normalize to byte arrays which are the correct length, expect success, - // then compare buffer contents for ordinal equality. - - foreach (int bufferLength in new int[] { utf8Normalized.Length /* just right */, utf8Normalized.Length + 1 /* with extra room */}) - { - byte[] dest = new byte[bufferLength]; - Assert.Equal(utf8Normalized.Length, utf8Source.Normalize(dest, normalizationForm)); - Utf8Span normalizedSpan = Utf8Span.UnsafeCreateWithoutValidation(dest.AsSpan().Slice(0, utf8Normalized.Length)); - Assert.True(utf8Normalized.AsSpan() == normalizedSpan); // ordinal equality - Assert.True(normalizedSpan.IsNormalized(normalizationForm)); - } - } - - [Theory] - [MemberData(nameof(CaseConversionData))] - public static void ToLower(string testData) - { - static void RunTest(string testData, string expected, CultureInfo culture) - { - using BoundedUtf8Span boundedSpan = new BoundedUtf8Span(testData); - Utf8Span inputSpan = boundedSpan.Span; - - // First try the allocating APIs - - ustring expectedUtf8 = u8(expected) ?? ustring.Empty; - ustring actualUtf8; - - if (culture is null) - { - actualUtf8 = inputSpan.ToLowerInvariant(); - } - else - { - actualUtf8 = inputSpan.ToLower(culture); - } - - Assert.Equal(expectedUtf8, actualUtf8); - - // Next, try the non-allocating APIs with too small a buffer - - if (expectedUtf8.Length > 0) - { - byte[] bufferTooSmall = new byte[expectedUtf8.Length - 1]; - - if (culture is null) - { - Assert.Equal(-1, inputSpan.ToLowerInvariant(bufferTooSmall)); - } - else - { - Assert.Equal(-1, inputSpan.ToLower(bufferTooSmall, culture)); - } - } - - // Then the non-allocating APIs with a properly sized buffer - - foreach (int bufferSize in new[] { expectedUtf8.Length, expectedUtf8.Length + 1 }) - { - byte[] buffer = new byte[expectedUtf8.Length]; - - if (culture is null) - { - Assert.Equal(expectedUtf8.Length, inputSpan.ToLowerInvariant(buffer)); - } - else - { - Assert.Equal(expectedUtf8.Length, inputSpan.ToLower(buffer, culture)); - } - - Assert.True(expectedUtf8.AsBytes().SequenceEqual(buffer)); - } - } - - RunTest(testData, testData?.ToLowerInvariant(), null); - RunTest(testData, testData?.ToLower(CultureInfo.InvariantCulture), CultureInfo.InvariantCulture); - RunTest(testData, testData?.ToLower(CultureInfo.GetCultureInfo("en-US")), CultureInfo.GetCultureInfo("en-US")); - RunTest(testData, testData?.ToLower(CultureInfo.GetCultureInfo("tr-TR")), CultureInfo.GetCultureInfo("tr-TR")); - } - - [Theory] - [MemberData(nameof(CaseConversionData))] - public static void ToUpper(string testData) - { - static void RunTest(string testData, string expected, CultureInfo culture) - { - using BoundedUtf8Span boundedSpan = new BoundedUtf8Span(testData); - Utf8Span inputSpan = boundedSpan.Span; - - // First try the allocating APIs - - ustring expectedUtf8 = u8(expected) ?? ustring.Empty; - ustring actualUtf8; - - if (culture is null) - { - actualUtf8 = inputSpan.ToUpperInvariant(); - } - else - { - actualUtf8 = inputSpan.ToUpper(culture); - } - - Assert.Equal(expectedUtf8, actualUtf8); - - // Next, try the non-allocating APIs with too small a buffer - - if (expectedUtf8.Length > 0) - { - byte[] bufferTooSmall = new byte[expectedUtf8.Length - 1]; - - if (culture is null) - { - Assert.Equal(-1, inputSpan.ToUpperInvariant(bufferTooSmall)); - } - else - { - Assert.Equal(-1, inputSpan.ToUpper(bufferTooSmall, culture)); - } - } - - // Then the non-allocating APIs with a properly sized buffer - - foreach (int bufferSize in new[] { expectedUtf8.Length, expectedUtf8.Length + 1 }) - { - byte[] buffer = new byte[bufferSize]; - - if (culture is null) - { - Assert.Equal(expectedUtf8.Length, inputSpan.ToUpperInvariant(buffer)); - } - else - { - Assert.Equal(expectedUtf8.Length, inputSpan.ToUpper(buffer, culture)); - } - - Assert.True(expectedUtf8.AsBytes().SequenceEqual(buffer.AsSpan(0, expectedUtf8.Length))); - } - } - - RunTest(testData, testData?.ToUpperInvariant(), null); - RunTest(testData, testData?.ToUpper(CultureInfo.InvariantCulture), CultureInfo.InvariantCulture); - RunTest(testData, testData?.ToUpper(CultureInfo.GetCultureInfo("en-US")), CultureInfo.GetCultureInfo("en-US")); - RunTest(testData, testData?.ToUpper(CultureInfo.GetCultureInfo("tr-TR")), CultureInfo.GetCultureInfo("tr-TR")); - } - - public static IEnumerable CaseConversionData() - { - string[] testCases = new string[] - { - null, - string.Empty, - "Hello", - "iı", // dotted and dotless I - "İI", // dotted and dotless I - }; - - foreach (string testCase in testCases) - { - yield return new object[] { testCase }; - } - } - - public static IEnumerable NormalizationData() - { - // These test cases are from the Unicode Standard Annex #15, Figure 6 - // https://unicode.org/reports/tr15/ - - var testCases = new[] - { - new - { - Source = "\ufb01", // "fi" (LATIN SMALL LIGATURE FI) - NFD = "\ufb01", // same as source - NFC = "\ufb01", // same as source - NFKD = "fi", // compatibility decomposed into ASCII chars - NFKC = "fi", // compatibility decomposed into ASCII chars - }, - new - { - Source = "2\u2075", // "2⁵" (SUPERSCRIPT FIVE) - NFD = "2\u2075", // same as source - NFC = "2\u2075", // same as source - NFKD = "25", // compatibility decomposed into ASCII chars - NFKC = "25", // compatibility decomposed into ASCII chars - }, - new - { - Source = "\u1e9b\u0323", // 'ẛ' (LATIN SMALL LETTER LONG S WITH DOT ABOVE) + COMBINING DOT BELOW - NFD = "\u017f\u0323\u0307", // 'ſ' (LATIN SMALL LETTER LONG S) + COMBINING DOT BELOW + COMBINING DOT ABOVE - NFC = "\u1e9b\u0323", // same as source - NFKD = "s\u0323\u0307", // ASCII 's' + COMBINING DOT BELOW + COMBINING DOT ABOVE - NFKC = "\u1e69", // "ṩ" (LATIN SMALL LETTER S WITH DOT BELOW AND DOT ABOVE) - } - }; - - foreach (var testCase in testCases) - { - yield return new object[] { testCase.Source, testCase.NFD, NormalizationForm.FormD }; - yield return new object[] { testCase.Source, testCase.NFC, NormalizationForm.FormC }; - yield return new object[] { testCase.Source, testCase.NFKD, NormalizationForm.FormKD }; - yield return new object[] { testCase.Source, testCase.NFKC, NormalizationForm.FormKC }; - } - } - } -} diff --git a/src/libraries/System.Utf8String.Experimental/tests/System/Utf8SpanTests.Ctor.cs b/src/libraries/System.Utf8String.Experimental/tests/System/Utf8SpanTests.Ctor.cs deleted file mode 100644 index 6dc0e30ca477c..0000000000000 --- a/src/libraries/System.Utf8String.Experimental/tests/System/Utf8SpanTests.Ctor.cs +++ /dev/null @@ -1,134 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using Xunit; - -using static System.Tests.Utf8TestUtilities; - -using ustring = System.Utf8String; - -namespace System.Text.Tests -{ - public unsafe partial class Utf8SpanTests - { - [Fact] - public static void Ctor_EmptyUtf8String() - { - // Arrange - - ustring str = ustring.Empty; - - // Act - - Utf8Span span = new Utf8Span(str); - - // Assert - // GetPinnableReference should be 'null' to match behavior of empty ROS.GetPinnableReference(); - - Assert.True(span.IsEmpty); - Assert.Equal(IntPtr.Zero, (IntPtr)(void*)Unsafe.AsPointer(ref Unsafe.AsRef(in span.GetPinnableReference()))); - Assert.True(Unsafe.AreSame(ref Unsafe.AsRef(in str.GetPinnableReference()), ref MemoryMarshal.GetReference(span.Bytes))); - Assert.Equal(0, span.Length); - } - - [Fact] - public static void Ctor_NonEmptyUtf8String() - { - // Arrange - - ustring str = u8("Hello!"); - - // Act - - Utf8Span span = new Utf8Span(str); - - // Assert - - Assert.False(span.IsEmpty); - Assert.True(Unsafe.AreSame(ref Unsafe.AsRef(in str.GetPinnableReference()), ref Unsafe.AsRef(in span.GetPinnableReference()))); - Assert.True(Unsafe.AreSame(ref Unsafe.AsRef(in str.GetPinnableReference()), ref MemoryMarshal.GetReference(span.Bytes))); - Assert.Equal(6, span.Length); - } - - [Fact] - public static void Ctor_NullUtf8String() - { - // Arrange - - ustring str = null; - - // Act - - Utf8Span span = new Utf8Span(str); - - // Assert - // GetPinnableReference should be 'null' to match behavior of empty ROS.GetPinnableReference(); - - Assert.True(span.IsEmpty); - Assert.Equal(IntPtr.Zero, (IntPtr)(void*)Unsafe.AsPointer(ref Unsafe.AsRef(in span.GetPinnableReference()))); - Assert.Equal(IntPtr.Zero, (IntPtr)(void*)Unsafe.AsPointer(ref MemoryMarshal.GetReference(span.Bytes))); - Assert.Equal(0, span.Length); - } - - [Fact] - public static void Ctor_UnsafeFromByteSpan_NonEmpty() - { - // Arrange - - ReadOnlySpan original = new byte[] { 1, 2, 3, 4, 5 }; - - // Act - - Utf8Span span = Utf8Span.UnsafeCreateWithoutValidation(original); - - // Assert - - Assert.False(span.IsEmpty); - Assert.True(Unsafe.AreSame(ref Unsafe.AsRef(in original.GetPinnableReference()), ref Unsafe.AsRef(in span.GetPinnableReference()))); - Assert.True(Unsafe.AreSame(ref Unsafe.AsRef(in original.GetPinnableReference()), ref MemoryMarshal.GetReference(span.Bytes))); - Assert.Equal(5, span.Length); - } - - [Fact] - public static void Ctor_UnsafeFromByteSpan_NonNullEmptyArray() - { - // Arrange - - ReadOnlySpan original = new byte[0]; - - // Act - - Utf8Span span = Utf8Span.UnsafeCreateWithoutValidation(original); - - // Assert - // GetPinnableReference should be 'null' to match behavior of empty ROS.GetPinnableReference(); - - Assert.True(span.IsEmpty); - Assert.Equal(IntPtr.Zero, (IntPtr)(void*)Unsafe.AsPointer(ref Unsafe.AsRef(in span.GetPinnableReference()))); - Assert.True(Unsafe.AreSame(ref MemoryMarshal.GetReference(original), ref MemoryMarshal.GetReference(span.Bytes))); - Assert.Equal(0, span.Length); - } - - [Fact] - public static void Ctor_UnsafeFromByteSpan_Default() - { - // Arrange - - ReadOnlySpan original = default; - - // Act - - Utf8Span span = Utf8Span.UnsafeCreateWithoutValidation(original); - - // Assert - // GetPinnableReference should be 'null' to match behavior of empty ROS.GetPinnableReference(); - - Assert.True(span.IsEmpty); - Assert.Equal(IntPtr.Zero, (IntPtr)(void*)Unsafe.AsPointer(ref Unsafe.AsRef(in span.GetPinnableReference()))); - Assert.Equal(IntPtr.Zero, (IntPtr)(void*)Unsafe.AsPointer(ref MemoryMarshal.GetReference(span.Bytes))); - Assert.Equal(0, span.Length); - } - } -} diff --git a/src/libraries/System.Utf8String.Experimental/tests/System/Utf8SpanTests.Enumeration.cs b/src/libraries/System.Utf8String.Experimental/tests/System/Utf8SpanTests.Enumeration.cs deleted file mode 100644 index cafeca20576be..0000000000000 --- a/src/libraries/System.Utf8String.Experimental/tests/System/Utf8SpanTests.Enumeration.cs +++ /dev/null @@ -1,81 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Tests; -using Xunit; - -namespace System.Text.Tests -{ - public unsafe partial class Utf8SpanTests - { - [Fact] - public static void CharsProperty_FromData() - { - using BoundedUtf8Span boundedSpan = new BoundedUtf8Span("\U00000012\U00000123\U00001234\U00101234\U00000012\U00000123\U00001234\U00101234"); - Utf8Span span = boundedSpan.Span; - - var charsEnumerator = span.Chars.GetEnumerator(); - - Assert.True(charsEnumerator.MoveNext()); - Assert.Equal('\U00000012', charsEnumerator.Current); - Assert.True(charsEnumerator.MoveNext()); - Assert.Equal('\U00000123', charsEnumerator.Current); - Assert.True(charsEnumerator.MoveNext()); - Assert.Equal('\U00001234', charsEnumerator.Current); - Assert.True(charsEnumerator.MoveNext()); - Assert.Equal('\uDBC4', charsEnumerator.Current); - Assert.True(charsEnumerator.MoveNext()); - Assert.Equal('\uDE34', charsEnumerator.Current); - Assert.True(charsEnumerator.MoveNext()); - Assert.Equal('\U00000012', charsEnumerator.Current); - Assert.True(charsEnumerator.MoveNext()); - Assert.Equal('\U00000123', charsEnumerator.Current); - Assert.True(charsEnumerator.MoveNext()); - Assert.Equal('\U00001234', charsEnumerator.Current); - Assert.True(charsEnumerator.MoveNext()); - Assert.Equal('\uDBC4', charsEnumerator.Current); - Assert.True(charsEnumerator.MoveNext()); - Assert.Equal('\uDE34', charsEnumerator.Current); - Assert.False(charsEnumerator.MoveNext()); - } - - [Fact] - public static void CharsProperty_FromEmpty() - { - Assert.False(Utf8Span.Empty.Chars.GetEnumerator().MoveNext()); - } - - [Fact] - public static void RunesProperty_FromData() - { - using BoundedUtf8Span boundedSpan = new BoundedUtf8Span("\U00000012\U00000123\U00001234\U00101234\U00000012\U00000123\U00001234\U00101234"); - Utf8Span span = boundedSpan.Span; - - var runesEnumerator = span.Runes.GetEnumerator(); - - Assert.True(runesEnumerator.MoveNext()); - Assert.Equal(new Rune(0x0012), runesEnumerator.Current); - Assert.True(runesEnumerator.MoveNext()); - Assert.Equal(new Rune(0x0123), runesEnumerator.Current); - Assert.True(runesEnumerator.MoveNext()); - Assert.Equal(new Rune(0x1234), runesEnumerator.Current); - Assert.True(runesEnumerator.MoveNext()); - Assert.Equal(new Rune(0x101234), runesEnumerator.Current); - Assert.True(runesEnumerator.MoveNext()); - Assert.Equal(new Rune(0x0012), runesEnumerator.Current); - Assert.True(runesEnumerator.MoveNext()); - Assert.Equal(new Rune(0x0123), runesEnumerator.Current); - Assert.True(runesEnumerator.MoveNext()); - Assert.Equal(new Rune(0x1234), runesEnumerator.Current); - Assert.True(runesEnumerator.MoveNext()); - Assert.Equal(new Rune(0x101234), runesEnumerator.Current); - Assert.False(runesEnumerator.MoveNext()); - } - - [Fact] - public static void RunesProperty_FromEmpty() - { - Assert.False(Utf8Span.Empty.Runes.GetEnumerator().MoveNext()); - } - } -} diff --git a/src/libraries/System.Utf8String.Experimental/tests/System/Utf8SpanTests.Manipulation.TestData.cs b/src/libraries/System.Utf8String.Experimental/tests/System/Utf8SpanTests.Manipulation.TestData.cs deleted file mode 100644 index 94a85ae9ac169..0000000000000 --- a/src/libraries/System.Utf8String.Experimental/tests/System/Utf8SpanTests.Manipulation.TestData.cs +++ /dev/null @@ -1,129 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Buffers; -using System.Collections.Generic; -using System.Globalization; -using System.Tests; - -using static System.Tests.Utf8TestUtilities; - -using ustring = System.Utf8String; - -namespace System.Text.Tests -{ - public partial class Utf8SpanTests - { - public static IEnumerable SplitData_CharSeparator() - { - foreach (SplitTestData entry in SplitData_All()) - { - if (!TryParseSearchTermAsChar(entry.SearchTerm, out char searchChar)) - { - continue; - } - - yield return new object[] - { - entry.Source, - searchChar, - entry.ExpectedRanges - }; - } - } - - public static IEnumerable SplitData_RuneSeparator() - { - foreach (SplitTestData entry in SplitData_All()) - { - if (!TryParseSearchTermAsRune(entry.SearchTerm, out Rune searchRune)) - { - continue; - } - - yield return new object[] - { - entry.Source, - searchRune, - entry.ExpectedRanges - }; - } - } - - public static IEnumerable SplitData_Utf8SpanSeparator() - { - foreach (SplitTestData entry in SplitData_All()) - { - if (!TryParseSearchTermAsUtf8String(entry.SearchTerm, out ustring searchTerm)) - { - continue; - } - - yield return new object[] - { - entry.Source, - searchTerm, - entry.ExpectedRanges - }; - } - } - - private static IEnumerable SplitData_All() - { - SplitTestData[] testDataEntries = new SplitTestData[] - { - new SplitTestData - { - // Empty source, searching for anything results in no match - Source = null, - SearchTerm = '\0', - ExpectedRanges = new[] { 0..0 } - }, - new SplitTestData - { - // If no match, then return original span - Source = u8("Hello"), - SearchTerm = 'x', - ExpectedRanges = new[] { Range.All } - }, - new SplitTestData - { - // Match returns multiple spans (some may be empty) - Source = u8("Hello"), - SearchTerm = 'l', - ExpectedRanges = new[] { 0..2, 3..3, 4..5 } - }, - new SplitTestData - { - // Match returns multiple spans (non-empty) - Source = u8("Hello"), - SearchTerm = "ell", - ExpectedRanges = new[] { 0..1, ^1.. } - }, - new SplitTestData - { - // Match returns multiple spans (non-empty, with whitespace) - Source = u8("aax aaa xxax \u2028\u2029"), // includes LS, PS as whitespace - SearchTerm = 'x', - ExpectedRanges = new[] { 0..2, 3..8, 9..9, 10..11, 12.. } - }, - new SplitTestData - { - // Matching on U+1F600 GRINNING FACE (with whitespace) - Source = u8("x \U0001F600 y"), - SearchTerm = new Rune(0x1F600), - ExpectedRanges = new[] { 0..2, ^2.. } - }, - }; - - return testDataEntries; - } - - public class SplitTestData - { - public ustring Source; - public object SearchTerm; - public Range[] ExpectedRanges; - } - } -} diff --git a/src/libraries/System.Utf8String.Experimental/tests/System/Utf8SpanTests.Manipulation.cs b/src/libraries/System.Utf8String.Experimental/tests/System/Utf8SpanTests.Manipulation.cs deleted file mode 100644 index 01eee60d8f01c..0000000000000 --- a/src/libraries/System.Utf8String.Experimental/tests/System/Utf8SpanTests.Manipulation.cs +++ /dev/null @@ -1,328 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Linq; -using System.Buffers; -using System.Collections.Generic; -using System.Tests; -using Xunit; - -using static System.Tests.Utf8TestUtilities; - -using ustring = System.Utf8String; - -namespace System.Text.Tests -{ - public partial class Utf8SpanTests - { - private delegate Utf8Span.SplitResult Utf8SpanSplitDelegate(Utf8Span span, Utf8StringSplitOptions splitOptions); - - [Fact] - public static void Split_EmptySearchSpan_Throws() - { - // Shouldn't be able to split on an empty UTF-8 span. - // Such an enumerator would iterate forever, so we forbid it. - - var ex = Assert.Throws(() => { u8("Hello").AsSpan().Split(Utf8Span.Empty); }); - Assert.Equal("separator", ex.ParamName); - } - - [Fact] - public static void Split_InvalidChar_Throws() - { - // Shouldn't be able to split on a standalone surrogate char - // Other search methods (TryFind) return false when given a standalone surrogate char as input, - // but the Split methods returns a complex data structure instead of a simple bool. So to keep - // the logic of that data structure relatively simple we'll forbid the bad char at the call site. - - var ex = Assert.Throws(() => { u8("Hello").AsSpan().Split('\ud800'); }); - Assert.Equal("separator", ex.ParamName); - } - - [Fact] - public static void Split_Char_NullInput() - { - // First, make sure that .Split(',') yields a single-element [ ]. - - Utf8Span source = Utf8Span.Empty; - - var enumerator = source.Split(',').GetEnumerator(); - Assert.True(enumerator.MoveNext()); - Assert.True(source.Bytes == enumerator.Current.Bytes); // referential equality - Assert.False(enumerator.MoveNext()); - - // Next, make sure that if "remove empty entries" is specified, yields the empty set [ ]. - - enumerator = source.Split(',', Utf8StringSplitOptions.RemoveEmptyEntries).GetEnumerator(); - Assert.False(enumerator.MoveNext()); - } - - [Theory] - [MemberData(nameof(SplitData_CharSeparator))] - public static void Split_Char(ustring source, char separator, Range[] expectedRanges) - { - SplitTest_Common(source, (span, splitOptions) => span.Split(separator, splitOptions), expectedRanges); - } - - [Fact] - public static void Split_Deconstruct() - { - using BoundedUtf8Span boundedSpan = new BoundedUtf8Span("a,b,c,d,e"); - Utf8Span span = boundedSpan.Span; - - // Note referential equality checks below (since we want to know exact slices - // into the original buffer), not deep (textual) equality checks. - - { - (Utf8Span a, Utf8Span b) = span.Split('x'); // not found - Assert.True(a.Bytes == span.Bytes, "Expected referential equality of input."); - Assert.True(b.Bytes == default); - } - - { - (Utf8Span a, Utf8Span b) = span.Split(','); - Assert.True(a.Bytes == span.Bytes[..1]); // "a" - Assert.True(b.Bytes == span.Bytes[2..]); // "b,c,d,e" - } - - { - (Utf8Span a, Utf8Span b, Utf8Span c, Utf8Span d, Utf8Span e) = span.Split(','); - Assert.True(a.Bytes == span.Bytes[0..1]); // "a" - Assert.True(b.Bytes == span.Bytes[2..3]); // "b" - Assert.True(c.Bytes == span.Bytes[4..5]); // "c" - Assert.True(d.Bytes == span.Bytes[6..7]); // "d" - Assert.True(e.Bytes == span.Bytes[8..9]); // "e" - } - - { - (Utf8Span a, Utf8Span b, Utf8Span c, Utf8Span d, Utf8Span e, Utf8Span f, Utf8Span g, Utf8Span h) = span.Split(','); - Assert.True(a.Bytes == span.Bytes[0..1]); // "a" - Assert.True(b.Bytes == span.Bytes[2..3]); // "b" - Assert.True(c.Bytes == span.Bytes[4..5]); // "c" - Assert.True(d.Bytes == span.Bytes[6..7]); // "d" - Assert.True(e.Bytes == span.Bytes[8..9]); // "e" - Assert.True(f.Bytes == default); - Assert.True(g.Bytes == default); - Assert.True(h.Bytes == default); - } - } - - [Fact] - public static void Split_Deconstruct_WithOptions() - { - using BoundedUtf8Span boundedSpan = new BoundedUtf8Span("a, , b, c,, d, e"); - Utf8Span span = boundedSpan.Span; - - // Note referential equality checks below (since we want to know exact slices - // into the original buffer), not deep (textual) equality checks. - - { - (Utf8Span a, Utf8Span b) = span.Split(',', Utf8StringSplitOptions.RemoveEmptyEntries); - Assert.True(a.Bytes == span.Bytes[..1]); // "a" - Assert.True(b.Bytes == span.Bytes[2..]); // " , b, c,, d, e" - } - - { - (Utf8Span a, Utf8Span x, Utf8Span b, Utf8Span c, Utf8Span d, Utf8Span e) = span.Split(',', Utf8StringSplitOptions.RemoveEmptyEntries); - Assert.True(a.Bytes == span.Bytes[0..1]); // "a" - Assert.True(x.Bytes == span.Bytes[2..3]); // " " - Assert.True(b.Bytes == span.Bytes[4..6]); // " b" - Assert.True(c.Bytes == span.Bytes[7..9]); // " c" - Assert.True(d.Bytes == span.Bytes[11..13]); // " d" - Assert.True(e.Bytes == span.Bytes[14..]); // " e" - } - - { - (Utf8Span a, Utf8Span b, Utf8Span c, Utf8Span d, Utf8Span e, Utf8Span f, Utf8Span g, Utf8Span h) = span.Split(',', Utf8StringSplitOptions.RemoveEmptyEntries | Utf8StringSplitOptions.TrimEntries); - Assert.True(a.Bytes == span.Bytes[0..1]); // "a" - Assert.True(b.Bytes == span.Bytes[5..6]); // "b" - Assert.True(c.Bytes == span.Bytes[8..9]); // "c" - Assert.True(d.Bytes == span.Bytes[12..13]); // "d" - Assert.True(e.Bytes == span.Bytes[15..]); // "e" - Assert.True(f.Bytes == default); - Assert.True(g.Bytes == default); - Assert.True(h.Bytes == default); - } - } - - [Theory] - [MemberData(nameof(SplitData_RuneSeparator))] - public static void Split_Rune(ustring source, Rune separator, Range[] expectedRanges) - { - SplitTest_Common(source, (span, splitOptions) => span.Split(separator, splitOptions), expectedRanges); - } - - [Theory] - [MemberData(nameof(SplitData_Utf8SpanSeparator))] - public static void Split_Utf8Span(ustring source, ustring separator, Range[] expectedRanges) - { - SplitTest_Common(source, (span, splitOptions) => span.Split(separator.AsSpan(), splitOptions), expectedRanges); - } - - private static void SplitTest_Common(ustring source, Utf8SpanSplitDelegate splitAction, Range[] expectedRanges) - { - using BoundedUtf8Span boundedSpan = new BoundedUtf8Span(source.AsBytes()); - Utf8Span span = boundedSpan.Span; - int totalSpanLengthInBytes = span.Length; - source = null; // to avoid inadvertently using this for the remainder of the method - - // First, run the split with default options and make sure the ranges are equivalent - - List actualRanges = new List(); - foreach (Utf8Span slice in splitAction(span, Utf8StringSplitOptions.None)) - { - actualRanges.Add(GetRangeOfSubspan(span, slice)); - } - - Assert.Equal(expectedRanges, actualRanges, new RangeEqualityComparer(totalSpanLengthInBytes)); - - // Next, run the split with empty entries removed - - actualRanges = new List(); - foreach (Utf8Span slice in splitAction(span, Utf8StringSplitOptions.RemoveEmptyEntries)) - { - actualRanges.Add(GetRangeOfSubspan(span, slice)); - } - - Assert.Equal(expectedRanges.Where(range => !range.IsEmpty(totalSpanLengthInBytes)), actualRanges, new RangeEqualityComparer(totalSpanLengthInBytes)); - - // Next, run the split with results trimmed (but allowing empty results) - - expectedRanges = (Range[])expectedRanges.Clone(); // clone the array since we're about to mutate it - for (int i = 0; i < expectedRanges.Length; i++) - { - expectedRanges[i] = GetRangeOfSubspan(span, span[expectedRanges[i]].Trim()); - } - - actualRanges = new List(); - foreach (Utf8Span slice in splitAction(span, Utf8StringSplitOptions.TrimEntries)) - { - actualRanges.Add(GetRangeOfSubspan(span, slice)); - } - - Assert.Equal(expectedRanges, actualRanges, new RangeEqualityComparer(totalSpanLengthInBytes)); - - // Finally, run the split both trimmed and with empty entries removed - - actualRanges = new List(); - foreach (Utf8Span slice in splitAction(span, Utf8StringSplitOptions.TrimEntries | Utf8StringSplitOptions.RemoveEmptyEntries)) - { - actualRanges.Add(GetRangeOfSubspan(span, slice)); - } - - Assert.Equal(expectedRanges.Where(range => !range.IsEmpty(totalSpanLengthInBytes)), actualRanges, new RangeEqualityComparer(totalSpanLengthInBytes)); - } - - [Theory] - [MemberData(nameof(Trim_TestData))] - public static void Trim(string input) - { - // Arrange - - using BoundedUtf8Span boundedSpan = new BoundedUtf8Span(input); - Utf8Span span = boundedSpan.Span; - - // Act - - Utf8Span trimmed = span.Trim(); - - // Assert - // Compute the trim manually and ensure it matches the trimmed span's characteristics. - - ReadOnlySpan utf8Bytes = span.Bytes; - while (!utf8Bytes.IsEmpty) - { - OperationStatus status = Rune.DecodeFromUtf8(utf8Bytes, out Rune decodedRune, out int bytesConsumed); - Assert.Equal(OperationStatus.Done, status); - - if (!Rune.IsWhiteSpace(decodedRune)) - { - break; - } - - utf8Bytes = utf8Bytes.Slice(bytesConsumed); - } - while (!utf8Bytes.IsEmpty) - { - OperationStatus status = Rune.DecodeLastFromUtf8(utf8Bytes, out Rune decodedRune, out int bytesConsumed); - Assert.Equal(OperationStatus.Done, status); - - if (!Rune.IsWhiteSpace(decodedRune)) - { - break; - } - - utf8Bytes = utf8Bytes[..^bytesConsumed]; - } - - Assert.True(trimmed.Bytes == utf8Bytes); // must be an exact buffer match (address + length) - } - - [Theory] - [MemberData(nameof(Trim_TestData))] - public static void TrimEnd(string input) - { - // Arrange - - using BoundedUtf8Span boundedSpan = new BoundedUtf8Span(input); - Utf8Span span = boundedSpan.Span; - - // Act - - Utf8Span trimmed = span.TrimEnd(); - - // Assert - // Compute the trim manually and ensure it matches the trimmed span's characteristics. - - ReadOnlySpan utf8Bytes = span.Bytes; - while (!utf8Bytes.IsEmpty) - { - OperationStatus status = Rune.DecodeLastFromUtf8(utf8Bytes, out Rune decodedRune, out int bytesConsumed); - Assert.Equal(OperationStatus.Done, status); - - if (!Rune.IsWhiteSpace(decodedRune)) - { - break; - } - - utf8Bytes = utf8Bytes[..^bytesConsumed]; - } - - Assert.True(trimmed.Bytes == utf8Bytes); // must be an exact buffer match (address + length) - } - - [Theory] - [MemberData(nameof(Trim_TestData))] - public static void TrimStart(string input) - { - // Arrange - - using BoundedUtf8Span boundedSpan = new BoundedUtf8Span(input); - Utf8Span span = boundedSpan.Span; - - // Act - - Utf8Span trimmed = span.TrimStart(); - - // Assert - // Compute the trim manually and ensure it matches the trimmed span's characteristics. - - ReadOnlySpan utf8Bytes = span.Bytes; - while (!utf8Bytes.IsEmpty) - { - OperationStatus status = Rune.DecodeFromUtf8(utf8Bytes, out Rune decodedRune, out int bytesConsumed); - Assert.Equal(OperationStatus.Done, status); - - if (!Rune.IsWhiteSpace(decodedRune)) - { - break; - } - - utf8Bytes = utf8Bytes.Slice(bytesConsumed); - } - - Assert.True(trimmed.Bytes == utf8Bytes); // must be an exact buffer match (address + length) - } - } -} diff --git a/src/libraries/System.Utf8String.Experimental/tests/System/Utf8SpanTests.Searching.TestData.cs b/src/libraries/System.Utf8String.Experimental/tests/System/Utf8SpanTests.Searching.TestData.cs deleted file mode 100644 index b7010c34c4843..0000000000000 --- a/src/libraries/System.Utf8String.Experimental/tests/System/Utf8SpanTests.Searching.TestData.cs +++ /dev/null @@ -1,575 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Collections.Generic; -using System.Globalization; - -using static System.Tests.Utf8TestUtilities; - -using ustring = System.Utf8String; - -namespace System.Text.Tests -{ - public partial class Utf8SpanTests - { - public static IEnumerable TryFindData_Char_Ordinal() - { - foreach (TryFindTestData entry in TryFindData_All()) - { - if (!entry.Options.HasFlag(TryFindTestDataOptions.TestOrdinal) || entry.Options.HasFlag(TryFindTestDataOptions.TestIgnoreCaseOnly)) - { - continue; - } - - if (!TryParseSearchTermAsChar(entry.SearchTerm, out char searchChar)) - { - continue; - } - - yield return new object[] - { - entry.Source, - searchChar, - entry.ExpectedFirstMatch, - entry.ExpectedLastMatch, - }; - } - } - - public static IEnumerable TryFindData_Char_WithComparison() - { - foreach (TryFindTestData entry in TryFindData_All()) - { - if (!TryParseSearchTermAsChar(entry.SearchTerm, out char searchChar)) - { - continue; - } - - if (entry.Options.HasFlag(TryFindTestDataOptions.TestOrdinal)) - { - if (!entry.Options.HasFlag(TryFindTestDataOptions.TestIgnoreCaseOnly)) - { - yield return new object[] - { - entry.Source, - searchChar, - StringComparison.Ordinal, - null /* culture */, - entry.ExpectedFirstMatch, - entry.ExpectedLastMatch, - }; - } - if (!entry.Options.HasFlag(TryFindTestDataOptions.TestCaseSensitiveOnly)) - { - yield return new object[] - { - entry.Source, - searchChar, - StringComparison.OrdinalIgnoreCase, - null /* culture */, - entry.ExpectedFirstMatch, - entry.ExpectedLastMatch, - }; - } - } - - foreach (CultureInfo culture in entry.AdditionalCultures ?? Array.Empty()) - { - if (culture == CultureInfo.InvariantCulture) - { - if (!entry.Options.HasFlag(TryFindTestDataOptions.TestIgnoreCaseOnly)) - { - yield return new object[] - { - entry.Source, - searchChar, - StringComparison.InvariantCulture, - null /* culture */, - entry.ExpectedFirstMatch, - entry.ExpectedLastMatch, - }; - } - if (!entry.Options.HasFlag(TryFindTestDataOptions.TestCaseSensitiveOnly)) - { - yield return new object[] - { - entry.Source, - searchChar, - StringComparison.InvariantCultureIgnoreCase, - null /* culture */, - entry.ExpectedFirstMatch, - entry.ExpectedLastMatch, - }; - } - } - - if (!entry.Options.HasFlag(TryFindTestDataOptions.TestIgnoreCaseOnly)) - { - yield return new object[] - { - entry.Source, - searchChar, - StringComparison.CurrentCulture, - culture, - entry.ExpectedFirstMatch, - entry.ExpectedLastMatch, - }; - } - if (!entry.Options.HasFlag(TryFindTestDataOptions.TestCaseSensitiveOnly)) - { - yield return new object[] - { - entry.Source, - searchChar, - StringComparison.CurrentCultureIgnoreCase, - culture, - entry.ExpectedFirstMatch, - entry.ExpectedLastMatch, - }; - } - } - } - } - - public static IEnumerable TryFindData_Rune_Ordinal() - { - foreach (TryFindTestData entry in TryFindData_All()) - { - if (!entry.Options.HasFlag(TryFindTestDataOptions.TestOrdinal) || entry.Options.HasFlag(TryFindTestDataOptions.TestIgnoreCaseOnly)) - { - continue; - } - - if (!TryParseSearchTermAsRune(entry.SearchTerm, out Rune searchRune)) - { - continue; - } - - yield return new object[] - { - entry.Source, - searchRune, - entry.ExpectedFirstMatch, - entry.ExpectedLastMatch, - }; - } - } - - public static IEnumerable TryFindData_Rune_WithComparison() - { - foreach (TryFindTestData entry in TryFindData_All()) - { - if (!TryParseSearchTermAsRune(entry.SearchTerm, out Rune searchRune)) - { - continue; - } - - if (entry.Options.HasFlag(TryFindTestDataOptions.TestOrdinal)) - { - if (!entry.Options.HasFlag(TryFindTestDataOptions.TestIgnoreCaseOnly)) - { - yield return new object[] - { - entry.Source, - searchRune, - StringComparison.Ordinal, - null /* culture */, - entry.ExpectedFirstMatch, - entry.ExpectedLastMatch, - }; - } - if (!entry.Options.HasFlag(TryFindTestDataOptions.TestCaseSensitiveOnly)) - { - yield return new object[] - { - entry.Source, - searchRune, - StringComparison.OrdinalIgnoreCase, - null /* culture */, - entry.ExpectedFirstMatch, - entry.ExpectedLastMatch, - }; - } - } - - foreach (CultureInfo culture in entry.AdditionalCultures ?? Array.Empty()) - { - if (culture == CultureInfo.InvariantCulture) - { - if (!entry.Options.HasFlag(TryFindTestDataOptions.TestIgnoreCaseOnly)) - { - yield return new object[] - { - entry.Source, - searchRune, - StringComparison.InvariantCulture, - null /* culture */, - entry.ExpectedFirstMatch, - entry.ExpectedLastMatch, - }; - } - if (!entry.Options.HasFlag(TryFindTestDataOptions.TestCaseSensitiveOnly)) - { - yield return new object[] - { - entry.Source, - searchRune, - StringComparison.InvariantCultureIgnoreCase, - null /* culture */, - entry.ExpectedFirstMatch, - entry.ExpectedLastMatch, - }; - } - } - - if (!entry.Options.HasFlag(TryFindTestDataOptions.TestIgnoreCaseOnly)) - { - yield return new object[] - { - entry.Source, - searchRune, - StringComparison.CurrentCulture, - culture, - entry.ExpectedFirstMatch, - entry.ExpectedLastMatch, - }; - } - if (!entry.Options.HasFlag(TryFindTestDataOptions.TestCaseSensitiveOnly)) - { - yield return new object[] - { - entry.Source, - searchRune, - StringComparison.CurrentCultureIgnoreCase, - culture, - entry.ExpectedFirstMatch, - entry.ExpectedLastMatch, - }; - } - } - } - } - - public static IEnumerable TryFindData_Utf8Span_Ordinal() - { - foreach (TryFindTestData entry in TryFindData_All()) - { - if (!entry.Options.HasFlag(TryFindTestDataOptions.TestOrdinal) || entry.Options.HasFlag(TryFindTestDataOptions.TestIgnoreCaseOnly)) - { - continue; - } - - if (!TryParseSearchTermAsUtf8String(entry.SearchTerm, out ustring searchTerm)) - { - continue; - } - - yield return new object[] - { - entry.Source, - searchTerm, - entry.ExpectedFirstMatch, - entry.ExpectedLastMatch, - }; - } - } - - public static IEnumerable TryFindData_Utf8Span_WithComparison() - { - foreach (TryFindTestData entry in TryFindData_All()) - { - if (!TryParseSearchTermAsUtf8String(entry.SearchTerm, out ustring searchTerm)) - { - continue; - } - - if (entry.Options.HasFlag(TryFindTestDataOptions.TestOrdinal)) - { - if (!entry.Options.HasFlag(TryFindTestDataOptions.TestIgnoreCaseOnly)) - { - yield return new object[] - { - entry.Source, - searchTerm, - StringComparison.Ordinal, - null /* culture */, - entry.ExpectedFirstMatch, - entry.ExpectedLastMatch, - }; - } - if (!entry.Options.HasFlag(TryFindTestDataOptions.TestCaseSensitiveOnly)) - { - yield return new object[] - { - entry.Source, - searchTerm, - StringComparison.OrdinalIgnoreCase, - null /* culture */, - entry.ExpectedFirstMatch, - entry.ExpectedLastMatch, - }; - } - } - - foreach (CultureInfo culture in entry.AdditionalCultures ?? Array.Empty()) - { - if (culture == CultureInfo.InvariantCulture) - { - if (!entry.Options.HasFlag(TryFindTestDataOptions.TestIgnoreCaseOnly)) - { - yield return new object[] - { - entry.Source, - searchTerm, - StringComparison.InvariantCulture, - null /* culture */, - entry.ExpectedFirstMatch, - entry.ExpectedLastMatch, - }; - } - if (!entry.Options.HasFlag(TryFindTestDataOptions.TestCaseSensitiveOnly)) - { - yield return new object[] - { - entry.Source, - searchTerm, - StringComparison.InvariantCultureIgnoreCase, - null /* culture */, - entry.ExpectedFirstMatch, - entry.ExpectedLastMatch, - }; - } - } - - if (!entry.Options.HasFlag(TryFindTestDataOptions.TestIgnoreCaseOnly)) - { - yield return new object[] - { - entry.Source, - searchTerm, - StringComparison.CurrentCulture, - culture, - entry.ExpectedFirstMatch, - entry.ExpectedLastMatch, - }; - } - if (!entry.Options.HasFlag(TryFindTestDataOptions.TestCaseSensitiveOnly)) - { - yield return new object[] - { - entry.Source, - searchTerm, - StringComparison.CurrentCultureIgnoreCase, - culture, - entry.ExpectedFirstMatch, - entry.ExpectedLastMatch, - }; - } - } - } - } - - private static IEnumerable TryFindData_All() - { - CultureInfo inv = CultureInfo.InvariantCulture; - CultureInfo en_US = CultureInfo.GetCultureInfo("en-US"); - CultureInfo tr_TR = CultureInfo.GetCultureInfo("tr-TR"); - CultureInfo hu_HU = CultureInfo.GetCultureInfo("hu-HU"); - - TryFindTestData[] testDataEntries = new TryFindTestData[] - { - new TryFindTestData - { - // Searching for the empty string within the empty string should result in 0..0 / ^0..^0 across all comparers and all cultures - Source = null, - SearchTerm = null, - Options = TryFindTestDataOptions.TestOrdinal, - AdditionalCultures = new CultureInfo[] { inv, en_US, tr_TR, hu_HU }, - ExpectedFirstMatch = 0..0, - ExpectedLastMatch = ^0..^0, - }, - new TryFindTestData - { - // Searching for the empty string within a non-empty string should result in 0..0 / ^0..^0 across all comparers and all cultures - Source = u8("Hello"), - SearchTerm = null, - Options = TryFindTestDataOptions.TestOrdinal, - AdditionalCultures = new CultureInfo[] { inv, en_US, tr_TR, hu_HU }, - ExpectedFirstMatch = 0..0, - ExpectedLastMatch = ^0..^0, - }, - new TryFindTestData - { - // Searching for a non-empty string within an empty string should fail across all comparers and all cultures - Source = null, - SearchTerm = u8("Hello"), - Options = TryFindTestDataOptions.TestOrdinal, - AdditionalCultures = new CultureInfo[] { inv, en_US, tr_TR, hu_HU }, - ExpectedFirstMatch = null, - ExpectedLastMatch = null, - }, - new TryFindTestData - { - // Searching for the null terminator shouldn't match unless the input contains a null terminator - Source = u8("Hello"), - SearchTerm = '\0', - Options = TryFindTestDataOptions.TestOrdinal, - AdditionalCultures = null, - ExpectedFirstMatch = null, - ExpectedLastMatch = null, - }, - new TryFindTestData - { - // Searching for the null terminator shouldn't match unless the input contains a null terminator - Source = u8("H\0ell\0o"), - SearchTerm = '\0', - Options = TryFindTestDataOptions.TestOrdinal, - AdditionalCultures = null, - ExpectedFirstMatch = 1..2, - ExpectedLastMatch = ^2..^1, - }, - new TryFindTestData - { - // Simple ASCII search with success (case-sensitive) - Source = u8("Hello"), - SearchTerm = 'l', - Options = TryFindTestDataOptions.TestOrdinal | TryFindTestDataOptions.TestCaseSensitiveOnly, - AdditionalCultures = new CultureInfo[] { inv }, - ExpectedFirstMatch = 2..3, - ExpectedLastMatch = 3..4, - }, - new TryFindTestData - { - // Simple ASCII search with failure (case-sensitive) - Source = u8("Hello"), - SearchTerm = 'L', - Options = TryFindTestDataOptions.TestOrdinal | TryFindTestDataOptions.TestCaseSensitiveOnly, - AdditionalCultures = new CultureInfo[] { inv }, - ExpectedFirstMatch = null, - ExpectedLastMatch = null, - }, - new TryFindTestData - { - // Simple ASCII search with success (case-insensitive) - Source = u8("Hello"), - SearchTerm = 'L', - Options = TryFindTestDataOptions.TestOrdinal | TryFindTestDataOptions.TestIgnoreCaseOnly, - AdditionalCultures = new CultureInfo[] { inv }, - ExpectedFirstMatch = 2..3, - ExpectedLastMatch = 3..4, - }, - new TryFindTestData - { - // U+1F600 GRINNING FACE, should match an exact Rune search - Source = u8("x\U0001F600y"), - SearchTerm = new Rune(0x1F600), - Options = TryFindTestDataOptions.TestOrdinal, - AdditionalCultures = new CultureInfo[] { inv }, - ExpectedFirstMatch = 1..5, - ExpectedLastMatch = 1..5, - }, - new TryFindTestData - { - // U+1F600 GRINNING FACE, shouldn't match looking for individual UTF-16 surrogate chars - Source = u8("x\ud83d\ude00y"), - SearchTerm = '\ud83d', - Options = TryFindTestDataOptions.TestOrdinal, - AdditionalCultures = new CultureInfo[] { inv }, - ExpectedFirstMatch = null, - ExpectedLastMatch = null, - }, - new TryFindTestData - { - // U+1F600 GRINNING FACE, shouldn't match on the standalone [ F0 ] byte that begins the multi-byte sequence - Source = u8("x\ud83d\ude00y"), - SearchTerm = '\u00f0', - Options = TryFindTestDataOptions.TestOrdinal, - AdditionalCultures = new CultureInfo[] { inv }, - ExpectedFirstMatch = null, - ExpectedLastMatch = null, - }, - new TryFindTestData - { - // hu_HU shouldn't match "d" within "dz" - Source = u8("ab_dz_ba"), - SearchTerm = 'd', - Options = TryFindTestDataOptions.None, - AdditionalCultures = new CultureInfo[] { hu_HU }, - ExpectedFirstMatch = null, - ExpectedLastMatch = null, - }, - new TryFindTestData - { - // Turkish I, case-sensitive - Source = u8("\u0069\u0130\u0131\u0049"), // iİıI - SearchTerm = 'i', - Options = TryFindTestDataOptions.TestCaseSensitiveOnly, - AdditionalCultures = new CultureInfo[] { tr_TR }, - ExpectedFirstMatch = 0..1, - ExpectedLastMatch = 0..1, - }, - new TryFindTestData - { - // Turkish I, case-insensitive - Source = u8("\u0069\u0130\u0131\u0049"), // iİıI - SearchTerm = 'i', - Options = TryFindTestDataOptions.TestIgnoreCaseOnly, - AdditionalCultures = new CultureInfo[] { tr_TR }, - ExpectedFirstMatch = 0..1, - ExpectedLastMatch = 1..3, - }, - new TryFindTestData - { - // denormalized forms, no match - Source = u8("a\u0308e\u0308A\u0308E\u0308"), // äëÄË (denormalized) - SearchTerm = 'e', // shouldn't match letter paired with diacritic - Options = TryFindTestDataOptions.None, - AdditionalCultures = new CultureInfo[] { inv }, - ExpectedFirstMatch = null, - ExpectedLastMatch = null, - }, - new TryFindTestData - { - // denormalized forms, case-sensitive - Source = u8("a\u0308e\u0308A\u0308E\u0308"), // äëÄË (denormalized) - SearchTerm = '\u00eb', // ë, normalized form - Options = TryFindTestDataOptions.TestCaseSensitiveOnly, - AdditionalCultures = new CultureInfo[] { inv }, - ExpectedFirstMatch = 3..6, - ExpectedLastMatch = 3..6, - }, - new TryFindTestData - { - // denormalized forms, case-insensitive - Source = u8("a\u0308e\u0308A\u0308E\u0308"), // äëÄË (denormalized) - SearchTerm = '\u00eb', // ë, normalized form - Options = TryFindTestDataOptions.TestIgnoreCaseOnly, - AdditionalCultures = new CultureInfo[] { inv }, - ExpectedFirstMatch = 3..6, - ExpectedLastMatch = ^3.., - }, - }; - - return testDataEntries; - } - - public class TryFindTestData - { - public ustring Source; - public object SearchTerm; - public TryFindTestDataOptions Options; - public CultureInfo[] AdditionalCultures; - public Range? ExpectedFirstMatch; - public Range? ExpectedLastMatch; - } - - [Flags] - public enum TryFindTestDataOptions - { - None = 0, - TestOrdinal = 1 << 0, - TestCaseSensitiveOnly = 1 << 1, - TestIgnoreCaseOnly = 2 << 1, - } - } -} diff --git a/src/libraries/System.Utf8String.Experimental/tests/System/Utf8SpanTests.Searching.cs b/src/libraries/System.Utf8String.Experimental/tests/System/Utf8SpanTests.Searching.cs deleted file mode 100644 index 67409d978b5a4..0000000000000 --- a/src/libraries/System.Utf8String.Experimental/tests/System/Utf8SpanTests.Searching.cs +++ /dev/null @@ -1,461 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Globalization; -using System.Tests; -using Xunit; - -using static System.Tests.Utf8TestUtilities; - -using ustring = System.Utf8String; - -namespace System.Text.Tests -{ - /* - * Please keep these tests in sync with those in Utf8StringTests.Searching.cs. - */ - - public unsafe partial class Utf8SpanTests - { - [Theory] - [MemberData(nameof(TryFindData_Char_Ordinal))] - public static void TryFind_Char_Ordinal(ustring source, char searchTerm, Range? expectedForwardMatch, Range? expectedBackwardMatch) - { - using BoundedUtf8Span boundedSpan = new BoundedUtf8Span(source.AsBytes()); - Utf8Span searchSpan = boundedSpan.Span; - source = null; // to avoid accidentally using this for the remainder of the test - - // First, search forward - - bool wasFound = searchSpan.TryFind(searchTerm, out Range actualForwardMatch); - Assert.Equal(expectedForwardMatch.HasValue, wasFound); - - if (wasFound) - { - AssertRangesEqual(searchSpan.Length, expectedForwardMatch.Value, actualForwardMatch); - } - - // Also check Contains / StartsWith / SplitOn - - Assert.Equal(wasFound, searchSpan.Contains(searchTerm)); - Assert.Equal(wasFound && searchSpan.Bytes[..actualForwardMatch.Start].IsEmpty, searchSpan.StartsWith(searchTerm)); - - (var before, var after) = searchSpan.SplitOn(searchTerm); - if (wasFound) - { - Assert.True(searchSpan.Bytes[..actualForwardMatch.Start] == before.Bytes); // check for referential equality - Assert.True(searchSpan.Bytes[actualForwardMatch.End..] == after.Bytes); // check for referential equality - } - else - { - Assert.True(searchSpan.Bytes == before.Bytes); // check for reference equality - Assert.True(after.IsNull()); - } - - // Now search backward - - wasFound = searchSpan.TryFindLast(searchTerm, out Range actualBackwardMatch); - Assert.Equal(expectedBackwardMatch.HasValue, wasFound); - - if (wasFound) - { - AssertRangesEqual(searchSpan.Length, expectedBackwardMatch.Value, actualBackwardMatch); - } - - // Also check EndsWith / SplitOnLast - - Assert.Equal(wasFound && searchSpan.Bytes[actualBackwardMatch.End..].IsEmpty, searchSpan.EndsWith(searchTerm)); - - (before, after) = searchSpan.SplitOnLast(searchTerm); - if (wasFound) - { - Assert.True(searchSpan.Bytes[..actualBackwardMatch.Start] == before.Bytes); // check for referential equality - Assert.True(searchSpan.Bytes[actualBackwardMatch.End..] == after.Bytes); // check for referential equality - } - else - { - Assert.True(searchSpan.Bytes == before.Bytes); // check for reference equality - Assert.True(after.IsNull()); - } - } - - [PlatformSpecific(TestPlatforms.Windows)] - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNlsGlobalization))] - [MemberData(nameof(TryFindData_Char_WithComparison))] - public static void TryFind_Char_WithComparison(ustring source, char searchTerm, StringComparison comparison, CultureInfo currentCulture, Range? expectedForwardMatch, Range? expectedBackwardMatch) - { - RunOnDedicatedThread(() => - { - using BoundedUtf8Span boundedSpan = new BoundedUtf8Span(source.AsBytes()); - Utf8Span searchSpan = boundedSpan.Span; - source = null; // to avoid accidentally using this for the remainder of the test - - if (currentCulture != null) - { - CultureInfo.CurrentCulture = currentCulture; - } - - if (IsTryFindSupported(comparison)) - { - // First, search forward - - bool wasFound = searchSpan.TryFind(searchTerm, comparison, out Range actualForwardMatch); - Assert.Equal(expectedForwardMatch.HasValue, wasFound); - - if (wasFound) - { - AssertRangesEqual(searchSpan.Length, expectedForwardMatch.Value, actualForwardMatch); - } - - // Also check Contains / StartsWith / SplitOn - - Assert.Equal(wasFound, searchSpan.Contains(searchTerm, comparison)); - Assert.Equal(wasFound && searchSpan.Bytes[..actualForwardMatch.Start].IsEmpty, searchSpan.StartsWith(searchTerm, comparison)); - - (var before, var after) = searchSpan.SplitOn(searchTerm, comparison); - if (wasFound) - { - Assert.True(searchSpan.Bytes[..actualForwardMatch.Start] == before.Bytes); // check for referential equality - Assert.True(searchSpan.Bytes[actualForwardMatch.End..] == after.Bytes); // check for referential equality - } - else - { - Assert.True(searchSpan.Bytes == before.Bytes); // check for reference equality - Assert.True(after.IsNull()); - } - - // Now search backward - - wasFound = searchSpan.TryFindLast(searchTerm, comparison, out Range actualBackwardMatch); - Assert.Equal(expectedBackwardMatch.HasValue, wasFound); - - if (wasFound) - { - AssertRangesEqual(searchSpan.Length, expectedBackwardMatch.Value, actualBackwardMatch); - } - - // Also check EndsWith / SplitOnLast - - Assert.Equal(wasFound && searchSpan.Bytes[actualBackwardMatch.End..].IsEmpty, searchSpan.EndsWith(searchTerm, comparison)); - - (before, after) = searchSpan.SplitOnLast(searchTerm, comparison); - if (wasFound) - { - Assert.True(searchSpan.Bytes[..actualBackwardMatch.Start] == before.Bytes); // check for referential equality - Assert.True(searchSpan.Bytes[actualBackwardMatch.End..] == after.Bytes); // check for referential equality - } - else - { - Assert.True(searchSpan.Bytes == before.Bytes); // check for reference equality - Assert.True(after.IsNull()); - } - } - else - { - Assert.Throws(() => boundedSpan.Span.TryFind(searchTerm, comparison, out var _)); - Assert.Throws(() => boundedSpan.Span.TryFindLast(searchTerm, comparison, out var _)); - Assert.Throws(() => boundedSpan.Span.SplitOn(searchTerm, comparison)); - Assert.Throws(() => boundedSpan.Span.SplitOnLast(searchTerm, comparison)); - - Assert.Equal(expectedForwardMatch.HasValue, searchSpan.Contains(searchTerm, comparison)); - Assert.Equal(expectedForwardMatch.HasValue && searchSpan.Bytes[..expectedForwardMatch.Value.Start].IsEmpty, searchSpan.StartsWith(searchTerm, comparison)); - Assert.Equal(expectedBackwardMatch.HasValue && searchSpan.Bytes[expectedBackwardMatch.Value.End..].IsEmpty, searchSpan.EndsWith(searchTerm, comparison)); - } - }); - } - - [Theory] - [MemberData(nameof(TryFindData_Rune_Ordinal))] - public static void TryFind_Rune_Ordinal(ustring source, Rune searchTerm, Range? expectedForwardMatch, Range? expectedBackwardMatch) - { - using BoundedUtf8Span boundedSpan = new BoundedUtf8Span(source.AsBytes()); - Utf8Span searchSpan = boundedSpan.Span; - source = null; // to avoid accidentally using this for the remainder of the test - - // First, search forward - - bool wasFound = searchSpan.TryFind(searchTerm, out Range actualForwardMatch); - Assert.Equal(expectedForwardMatch.HasValue, wasFound); - - if (wasFound) - { - AssertRangesEqual(searchSpan.Length, expectedForwardMatch.Value, actualForwardMatch); - } - - // Also check Contains / StartsWith / SplitOn - - Assert.Equal(wasFound, searchSpan.Contains(searchTerm)); - Assert.Equal(wasFound && searchSpan.Bytes[..actualForwardMatch.Start].IsEmpty, searchSpan.StartsWith(searchTerm)); - - (var before, var after) = searchSpan.SplitOn(searchTerm); - if (wasFound) - { - Assert.True(searchSpan.Bytes[..actualForwardMatch.Start] == before.Bytes); // check for referential equality - Assert.True(searchSpan.Bytes[actualForwardMatch.End..] == after.Bytes); // check for referential equality - } - else - { - Assert.True(searchSpan.Bytes == before.Bytes); // check for reference equality - Assert.True(after.IsNull()); - } - - // Now search backward - - wasFound = searchSpan.TryFindLast(searchTerm, out Range actualBackwardMatch); - Assert.Equal(expectedBackwardMatch.HasValue, wasFound); - - if (wasFound) - { - AssertRangesEqual(searchSpan.Length, expectedBackwardMatch.Value, actualBackwardMatch); - } - - // Also check EndsWith / SplitOnLast - - Assert.Equal(wasFound && searchSpan.Bytes[actualBackwardMatch.End..].IsEmpty, searchSpan.EndsWith(searchTerm)); - - (before, after) = searchSpan.SplitOnLast(searchTerm); - if (wasFound) - { - Assert.True(searchSpan.Bytes[..actualBackwardMatch.Start] == before.Bytes); // check for referential equality - Assert.True(searchSpan.Bytes[actualBackwardMatch.End..] == after.Bytes); // check for referential equality - } - else - { - Assert.True(searchSpan.Bytes == before.Bytes); // check for reference equality - Assert.True(after.IsNull()); - } - } - - [PlatformSpecific(TestPlatforms.Windows)] - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNlsGlobalization))] - [MemberData(nameof(TryFindData_Rune_WithComparison))] - public static void TryFind_Rune_WithComparison(ustring source, Rune searchTerm, StringComparison comparison, CultureInfo currentCulture, Range? expectedForwardMatch, Range? expectedBackwardMatch) - { - RunOnDedicatedThread(() => - { - using BoundedUtf8Span boundedSpan = new BoundedUtf8Span(source.AsBytes()); - Utf8Span searchSpan = boundedSpan.Span; - source = null; // to avoid accidentally using this for the remainder of the test - - if (currentCulture != null) - { - CultureInfo.CurrentCulture = currentCulture; - } - - if (IsTryFindSupported(comparison)) - { - // First, search forward - - bool wasFound = searchSpan.TryFind(searchTerm, comparison, out Range actualForwardMatch); - Assert.Equal(expectedForwardMatch.HasValue, wasFound); - - if (wasFound) - { - AssertRangesEqual(searchSpan.Length, expectedForwardMatch.Value, actualForwardMatch); - } - - // Also check Contains / StartsWith / SplitOn - - Assert.Equal(wasFound, searchSpan.Contains(searchTerm, comparison)); - Assert.Equal(wasFound && searchSpan.Bytes[..actualForwardMatch.Start].IsEmpty, searchSpan.StartsWith(searchTerm, comparison)); - - (var before, var after) = searchSpan.SplitOn(searchTerm, comparison); - if (wasFound) - { - Assert.True(searchSpan.Bytes[..actualForwardMatch.Start] == before.Bytes); // check for referential equality - Assert.True(searchSpan.Bytes[actualForwardMatch.End..] == after.Bytes); // check for referential equality - } - else - { - Assert.True(searchSpan.Bytes == before.Bytes); // check for reference equality - Assert.True(after.IsNull()); - } - - // Now search backward - - wasFound = searchSpan.TryFindLast(searchTerm, comparison, out Range actualBackwardMatch); - Assert.Equal(expectedBackwardMatch.HasValue, wasFound); - - if (wasFound) - { - AssertRangesEqual(searchSpan.Length, expectedBackwardMatch.Value, actualBackwardMatch); - } - - // Also check EndsWith / SplitOnLast - - Assert.Equal(wasFound && searchSpan.Bytes[actualBackwardMatch.End..].IsEmpty, searchSpan.EndsWith(searchTerm, comparison)); - - (before, after) = searchSpan.SplitOnLast(searchTerm, comparison); - if (wasFound) - { - Assert.True(searchSpan.Bytes[..actualBackwardMatch.Start] == before.Bytes); // check for referential equality - Assert.True(searchSpan.Bytes[actualBackwardMatch.End..] == after.Bytes); // check for referential equality - } - else - { - Assert.True(searchSpan.Bytes == before.Bytes); // check for reference equality - Assert.True(after.IsNull()); - } - } - else - { - Assert.Throws(() => boundedSpan.Span.TryFind(searchTerm, comparison, out var _)); - Assert.Throws(() => boundedSpan.Span.TryFindLast(searchTerm, comparison, out var _)); - Assert.Throws(() => boundedSpan.Span.SplitOn(searchTerm, comparison)); - Assert.Throws(() => boundedSpan.Span.SplitOnLast(searchTerm, comparison)); - - Assert.Equal(expectedForwardMatch.HasValue, searchSpan.Contains(searchTerm, comparison)); - Assert.Equal(expectedForwardMatch.HasValue && searchSpan.Bytes[..expectedForwardMatch.Value.Start].IsEmpty, searchSpan.StartsWith(searchTerm, comparison)); - Assert.Equal(expectedBackwardMatch.HasValue && searchSpan.Bytes[expectedBackwardMatch.Value.End..].IsEmpty, searchSpan.EndsWith(searchTerm, comparison)); - } - }); - } - - [Theory] - [MemberData(nameof(TryFindData_Utf8Span_Ordinal))] - public static void TryFind_Utf8Span_Ordinal(ustring source, ustring searchTerm, Range? expectedForwardMatch, Range? expectedBackwardMatch) - { - using BoundedUtf8Span boundedSpan = new BoundedUtf8Span(source.AsBytes()); - Utf8Span searchSpan = boundedSpan.Span; - source = null; // to avoid accidentally using this for the remainder of the test - - // First, search forward - - bool wasFound = searchSpan.TryFind(searchTerm, out Range actualForwardMatch); - Assert.Equal(expectedForwardMatch.HasValue, wasFound); - - if (wasFound) - { - AssertRangesEqual(searchSpan.Length, expectedForwardMatch.Value, actualForwardMatch); - } - - // Also check Contains / StartsWith / SplitOn - - Assert.Equal(wasFound, searchSpan.Contains(searchTerm)); - Assert.Equal(wasFound && searchSpan.Bytes[..actualForwardMatch.Start].IsEmpty, searchSpan.StartsWith(searchTerm)); - - (var before, var after) = searchSpan.SplitOn(searchTerm); - if (wasFound) - { - Assert.True(searchSpan.Bytes[..actualForwardMatch.Start] == before.Bytes); // check for referential equality - Assert.True(searchSpan.Bytes[actualForwardMatch.End..] == after.Bytes); // check for referential equality - } - else - { - Assert.True(searchSpan.Bytes == before.Bytes); // check for reference equality - Assert.True(after.IsNull()); - } - - // Now search backward - - wasFound = searchSpan.TryFindLast(searchTerm, out Range actualBackwardMatch); - Assert.Equal(expectedBackwardMatch.HasValue, wasFound); - - if (wasFound) - { - AssertRangesEqual(searchSpan.Length, expectedBackwardMatch.Value, actualBackwardMatch); - } - - // Also check EndsWith / SplitOnLast - - Assert.Equal(wasFound && searchSpan.Bytes[actualBackwardMatch.End..].IsEmpty, searchSpan.EndsWith(searchTerm)); - - (before, after) = searchSpan.SplitOnLast(searchTerm); - if (wasFound) - { - Assert.True(searchSpan.Bytes[..actualBackwardMatch.Start] == before.Bytes); // check for referential equality - Assert.True(searchSpan.Bytes[actualBackwardMatch.End..] == after.Bytes); // check for referential equality - } - else - { - Assert.True(searchSpan.Bytes == before.Bytes); // check for reference equality - Assert.True(after.IsNull()); - } - } - - [PlatformSpecific(TestPlatforms.Windows)] - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNlsGlobalization))] - [MemberData(nameof(TryFindData_Utf8Span_WithComparison))] - public static void TryFind_Utf8Span_WithComparison(ustring source, ustring searchTerm, StringComparison comparison, CultureInfo currentCulture, Range? expectedForwardMatch, Range? expectedBackwardMatch) - { - RunOnDedicatedThread(() => - { - using BoundedUtf8Span boundedSpan = new BoundedUtf8Span(source.AsBytes()); - Utf8Span searchSpan = boundedSpan.Span; - source = null; // to avoid accidentally using this for the remainder of the test - - if (currentCulture != null) - { - CultureInfo.CurrentCulture = currentCulture; - } - - if (IsTryFindSupported(comparison)) - { - // First, search forward - - bool wasFound = searchSpan.TryFind(searchTerm, comparison, out Range actualForwardMatch); - Assert.Equal(expectedForwardMatch.HasValue, wasFound); - - if (wasFound) - { - AssertRangesEqual(searchSpan.Length, expectedForwardMatch.Value, actualForwardMatch); - } - - // Also check Contains / StartsWith / SplitOn - - Assert.Equal(wasFound, searchSpan.Contains(searchTerm, comparison)); - Assert.Equal(wasFound && searchSpan.Bytes[..actualForwardMatch.Start].IsEmpty, searchSpan.StartsWith(searchTerm, comparison)); - - (var before, var after) = searchSpan.SplitOn(searchTerm, comparison); - if (wasFound) - { - Assert.True(searchSpan.Bytes[..actualForwardMatch.Start] == before.Bytes); // check for referential equality - Assert.True(searchSpan.Bytes[actualForwardMatch.End..] == after.Bytes); // check for referential equality - } - else - { - Assert.True(searchSpan.Bytes == before.Bytes); // check for reference equality - Assert.True(after.IsNull()); - } - - // Now search backward - - wasFound = searchSpan.TryFindLast(searchTerm, comparison, out Range actualBackwardMatch); - Assert.Equal(expectedBackwardMatch.HasValue, wasFound); - - if (wasFound) - { - AssertRangesEqual(searchSpan.Length, expectedBackwardMatch.Value, actualBackwardMatch); - } - - // Also check EndsWith / SplitOnLast - - Assert.Equal(wasFound && searchSpan.Bytes[actualBackwardMatch.End..].IsEmpty, searchSpan.EndsWith(searchTerm, comparison)); - - (before, after) = searchSpan.SplitOnLast(searchTerm, comparison); - if (wasFound) - { - Assert.True(searchSpan.Bytes[..actualBackwardMatch.Start] == before.Bytes); // check for referential equality - Assert.True(searchSpan.Bytes[actualBackwardMatch.End..] == after.Bytes); // check for referential equality - } - else - { - Assert.True(searchSpan.Bytes == before.Bytes); // check for reference equality - Assert.True(after.IsNull()); - } - } - else - { - Assert.Throws(() => boundedSpan.Span.TryFind(searchTerm, comparison, out var _)); - Assert.Throws(() => boundedSpan.Span.TryFindLast(searchTerm, comparison, out var _)); - Assert.Throws(() => boundedSpan.Span.SplitOn(searchTerm, comparison)); - Assert.Throws(() => boundedSpan.Span.SplitOnLast(searchTerm, comparison)); - - Assert.Equal(expectedForwardMatch.HasValue, searchSpan.Contains(searchTerm, comparison)); - Assert.Equal(expectedForwardMatch.HasValue && searchSpan.Bytes[..expectedForwardMatch.Value.Start].IsEmpty, searchSpan.StartsWith(searchTerm, comparison)); - Assert.Equal(expectedBackwardMatch.HasValue && searchSpan.Bytes[expectedBackwardMatch.Value.End..].IsEmpty, searchSpan.EndsWith(searchTerm, comparison)); - } - }); - } - } -} diff --git a/src/libraries/System.Utf8String.Experimental/tests/System/Utf8SpanTests.TestData.cs b/src/libraries/System.Utf8String.Experimental/tests/System/Utf8SpanTests.TestData.cs deleted file mode 100644 index 5c5eb903e0e32..0000000000000 --- a/src/libraries/System.Utf8String.Experimental/tests/System/Utf8SpanTests.TestData.cs +++ /dev/null @@ -1,178 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Buffers; -using System.Collections.Generic; -using System.Linq; - -using static System.Tests.Utf8TestUtilities; - -using ustring = System.Utf8String; - -namespace System.Text.Tests -{ - public unsafe partial class Utf8SpanTests - { - /// - /// All s, U+0000..U+D800 and U+E000..U+10FFFF. - /// - private static IEnumerable AllRunes - { - get - { - for (uint i = 0; i < 0xD800; i++) - { - yield return new Rune(i); - } - for (uint i = 0xE000; i <= 0x10FFFF; i++) - { - yield return new Rune(i); - } - } - } - - /// - /// All s where returns . - /// - private static readonly Lazy WhiteSpaceRunes = new Lazy(() => AllRunes.Where(Rune.IsWhiteSpace).ToArray()); - - public static IEnumerable Trim_TestData() - { - string[] testData = new string[] - { - null, // null - "", // empty - "\0", // contains null character - shouldn't be trimmed - "Hello", // simple non-whitespace ASCII data - "\u0009Hello\u000d", // C0 whitespace characters - "\u0009\u0008\u0009Hello\u000e\u000b", // C0 whitespace + non-whitespace characters - " Hello! ", // simple space chars (plus !, since it's adjacent to U+0020 SPACE) - "\u0085\u0084\u0086\u0085", // U+0085 NEXT LINE (NEL), surrounded by adjacent non-whitespace chars - }; - - foreach (string entry in testData) - { - yield return new object[] { entry }; - } - - // A string with every possible whitespace character, just to test the limits - - StringBuilder builder = new StringBuilder(); - foreach (Rune whitespaceRune in WhiteSpaceRunes.Value) - { - builder.Append(whitespaceRune); - } - builder.Append("xyz"); - foreach (Rune whitespaceRune in WhiteSpaceRunes.Value) - { - builder.Append(whitespaceRune); - } - - yield return new object[] { builder.ToString() }; - } - - private static bool TryParseSearchTermAsChar(object searchTerm, out char parsed) - { - if (searchTerm is char ch) - { - parsed = ch; - return true; - } - else if (searchTerm is Rune r) - { - if (r.IsBmp) - { - parsed = (char)r.Value; - return true; - } - } - else if (searchTerm is string str) - { - if (str.Length == 1) - { - parsed = str[0]; - return true; - } - } - else if (searchTerm is ustring ustr) - { - var enumerator = ustr.Chars.GetEnumerator(); - if (enumerator.MoveNext()) - { - parsed = enumerator.Current; - if (!enumerator.MoveNext()) - { - return true; - } - } - } - - parsed = default; // failed to turn the search term into a single char - return false; - } - - private static bool TryParseSearchTermAsRune(object searchTerm, out Rune parsed) - { - if (searchTerm is char ch) - { - return Rune.TryCreate(ch, out parsed); - } - else if (searchTerm is Rune r) - { - parsed = r; - return true; - } - else if (searchTerm is string str) - { - if (Rune.DecodeFromUtf16(str.AsSpan(), out parsed, out int charsConsumed) == OperationStatus.Done - && charsConsumed == str.Length) - { - return true; - } - } - else if (searchTerm is ustring ustr) - { - if (Rune.DecodeFromUtf8(ustr.AsBytes(), out parsed, out int bytesConsumed) == OperationStatus.Done - && bytesConsumed == ustr.Length) - { - return true; - } - } - - parsed = default; // failed to turn the search term into a single Rune - return false; - } - - private static bool TryParseSearchTermAsUtf8String(object searchTerm, out ustring parsed) - { - if (searchTerm is char ch) - { - if (Rune.TryCreate(ch, out Rune rune)) - { - parsed = rune.ToUtf8String(); - return true; - } - } - else if (searchTerm is Rune r) - { - parsed = r.ToUtf8String(); - return true; - } - else if (searchTerm is string str) - { - if (ustring.TryCreateFrom(str.AsSpan(), out parsed)) - { - return true; - } - } - else if (searchTerm is ustring ustr) - { - parsed = ustr; - return true; - } - - parsed = default; // failed to turn the search term into a ustring - return false; - } - } -} diff --git a/src/libraries/System.Utf8String.Experimental/tests/System/Utf8SpanTests.cs b/src/libraries/System.Utf8String.Experimental/tests/System/Utf8SpanTests.cs deleted file mode 100644 index b6d611097ebd2..0000000000000 --- a/src/libraries/System.Utf8String.Experimental/tests/System/Utf8SpanTests.cs +++ /dev/null @@ -1,353 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Buffers; -using System.Collections.Generic; -using System.Globalization; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Tests; -using Xunit; - -using static System.Tests.Utf8TestUtilities; - -using ustring = System.Utf8String; - -namespace System.Text.Tests -{ - [SkipOnMono("The features from System.Utf8String.Experimental namespace are experimental.")] - public unsafe partial class Utf8SpanTests - { - [Fact] - public static void BytesProperty_FromCustomBytes() - { - byte[] bytes = Encoding.UTF8.GetBytes("Hello!"); - Assert.True(bytes.AsSpan() == Utf8Span.UnsafeCreateWithoutValidation(bytes).Bytes); - } - - [Fact] - public static void BytesProperty_FromEmpty() - { - Assert.True(Utf8Span.Empty.Bytes == ReadOnlySpan.Empty); - } - - [Fact] - public static void BytesProperty_FromUtf8String() - { - ustring ustr = u8("Hello!"); - Utf8Span uspan = new Utf8Span(ustr); - - Assert.True(ustr.AsBytes() == uspan.Bytes); - } - - [Fact] - public static void EmptyProperty() - { - // Act - - Utf8Span span = Utf8Span.Empty; - - // Assert - // GetPinnableReference should be 'null' to match behavior of empty ROS.GetPinnableReference(); - - Assert.True(span.IsEmpty); - Assert.Equal(IntPtr.Zero, (IntPtr)(void*)Unsafe.AsPointer(ref Unsafe.AsRef(in span.GetPinnableReference()))); - Assert.Equal(IntPtr.Zero, (IntPtr)(void*)Unsafe.AsPointer(ref MemoryMarshal.GetReference(span.Bytes))); - Assert.Equal(0, span.Length); - } - - [Fact] - public static void GetHashCode_Ordinal() - { - // Generate 17 all-null strings and make sure they have unique hash codes. - // Assuming Marvin32 is a good PRF and has a full 32-bit output domain, we should - // expect this test to fail only once every ~30 million runs due to the birthday paradox. - // That should be good enough for inclusion as a unit test. - - HashSet seenHashCodes = new HashSet(); - - for (int i = 0; i <= 16; i++) - { - using BoundedUtf8Span boundedSpan = new BoundedUtf8Span(new byte[i]); - Utf8Span span = boundedSpan.Span; - - Assert.True(seenHashCodes.Add(span.GetHashCode()), "This hash code was previously seen."); - } - } - - [PlatformSpecific(TestPlatforms.Windows)] - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNlsGlobalization))] - public static void GetHashCode_WithComparison() - { - // Since hash code generation is randomized, it's possible (though unlikely) that - // we might see unanticipated collisions. It's ok if this unit test fails once in - // every few million runs, but if the unit test becomes truly flaky then that would - // be indicative of a larger problem with hash code generation. - // - // These tests also make sure that the hash code is computed over the buffer rather - // than over the reference. - - // Ordinal - - { - using BoundedUtf8Span boundedSpan = new BoundedUtf8Span("ababaaAA"); - Utf8Span span = boundedSpan.Span; - - Assert.Equal(span[0..2].GetHashCode(StringComparison.Ordinal), span[2..4].GetHashCode(StringComparison.Ordinal)); - Assert.NotEqual(span[4..6].GetHashCode(StringComparison.Ordinal), span[6..8].GetHashCode(StringComparison.Ordinal)); - Assert.Equal(Utf8Span.Empty.GetHashCode(StringComparison.Ordinal), span[^0..].GetHashCode(StringComparison.Ordinal)); // null should equal empty - } - - // OrdinalIgnoreCase - - { - using BoundedUtf8Span boundedSpan = new BoundedUtf8Span("ababaaAA"); - Utf8Span span = boundedSpan.Span; - - Assert.Equal(span[0..2].GetHashCode(StringComparison.OrdinalIgnoreCase), span[2..4].GetHashCode(StringComparison.OrdinalIgnoreCase)); - Assert.Equal(span[4..6].GetHashCode(StringComparison.OrdinalIgnoreCase), span[6..8].GetHashCode(StringComparison.OrdinalIgnoreCase)); - Assert.NotEqual(span[0..2].GetHashCode(StringComparison.OrdinalIgnoreCase), span[6..8].GetHashCode(StringComparison.OrdinalIgnoreCase)); - Assert.Equal(Utf8Span.Empty.GetHashCode(StringComparison.OrdinalIgnoreCase), span[^0..].GetHashCode(StringComparison.OrdinalIgnoreCase)); // null should equal empty - } - - // InvariantCulture - - { - using BoundedUtf8Span boundedSpan = new BoundedUtf8Span("ae\u00e6AE\u00c6"); // U+00E6 = 'æ' LATIN SMALL LETTER AE, U+00E6 = 'Æ' LATIN CAPITAL LETTER AE - Utf8Span span = boundedSpan.Span; - - Assert.Equal(span[0..2].GetHashCode(StringComparison.InvariantCulture), span[2..4].GetHashCode(StringComparison.InvariantCulture)); - Assert.NotEqual(span[0..2].GetHashCode(StringComparison.InvariantCulture), span[4..6].GetHashCode(StringComparison.InvariantCulture)); - Assert.Equal(Utf8Span.Empty.GetHashCode(StringComparison.InvariantCulture), span[^0..].GetHashCode(StringComparison.InvariantCulture)); // null should equal empty - } - - // InvariantCultureIgnoreCase - - { - using BoundedUtf8Span boundedSpan = new BoundedUtf8Span("ae\u00e6AE\u00c6EA"); - Utf8Span span = boundedSpan.Span; - - Assert.Equal(span[0..2].GetHashCode(StringComparison.InvariantCultureIgnoreCase), span[2..4].GetHashCode(StringComparison.InvariantCultureIgnoreCase)); - Assert.Equal(span[0..2].GetHashCode(StringComparison.InvariantCultureIgnoreCase), span[6..8].GetHashCode(StringComparison.InvariantCultureIgnoreCase)); - Assert.NotEqual(span[0..2].GetHashCode(StringComparison.InvariantCultureIgnoreCase), span[8..10].GetHashCode(StringComparison.InvariantCultureIgnoreCase)); - Assert.Equal(Utf8Span.Empty.GetHashCode(StringComparison.InvariantCultureIgnoreCase), span[^0..].GetHashCode(StringComparison.InvariantCultureIgnoreCase)); // null should equal empty - } - - // Invariant culture should not match Turkish I case conversion - - { - using BoundedUtf8Span boundedSpan = new BoundedUtf8Span("i\u0130"); // U+0130 = 'İ' LATIN CAPITAL LETTER I WITH DOT ABOVE - Utf8Span span = boundedSpan.Span; - - Assert.NotEqual(span[0..1].GetHashCode(StringComparison.InvariantCultureIgnoreCase), span[1..3].GetHashCode(StringComparison.InvariantCultureIgnoreCase)); - } - - // CurrentCulture (we'll use tr-TR) - - RunOnDedicatedThread(() => - { - using BoundedUtf8Span boundedSpan = new BoundedUtf8Span("i\u0131\u0130Ii\u0131\u0130I"); // U+0131 = 'ı' LATIN SMALL LETTER DOTLESS I - Utf8Span span = boundedSpan.Span; - - CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo("tr-TR"); - - Assert.Equal(span[0..6].GetHashCode(StringComparison.CurrentCulture), span[6..12].GetHashCode(StringComparison.CurrentCulture)); - Assert.NotEqual(span[0..1].GetHashCode(StringComparison.CurrentCulture), span[1..3].GetHashCode(StringComparison.CurrentCulture)); - Assert.Equal(Utf8Span.Empty.GetHashCode(StringComparison.CurrentCulture), span[^0..].GetHashCode(StringComparison.CurrentCulture)); // null should equal empty - }); - - // CurrentCultureIgnoreCase (we'll use tr-TR) - - RunOnDedicatedThread(() => - { - using BoundedUtf8Span boundedSpan = new BoundedUtf8Span("i\u0131\u0130Ii\u0131\u0130I"); - Utf8Span span = boundedSpan.Span; - - CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo("tr-TR"); - - Assert.Equal(span[0..6].GetHashCode(StringComparison.CurrentCultureIgnoreCase), span[6..12].GetHashCode(StringComparison.CurrentCultureIgnoreCase)); - Assert.NotEqual(span[0..1].GetHashCode(StringComparison.CurrentCultureIgnoreCase), span[1..3].GetHashCode(StringComparison.CurrentCultureIgnoreCase)); // 'i' shouldn't match 'ı' - Assert.Equal(span[0..1].GetHashCode(StringComparison.CurrentCultureIgnoreCase), span[3..5].GetHashCode(StringComparison.CurrentCultureIgnoreCase)); // 'i' should match 'İ' - Assert.NotEqual(span[0..1].GetHashCode(StringComparison.CurrentCultureIgnoreCase), span[5..6].GetHashCode(StringComparison.CurrentCultureIgnoreCase)); // 'i' shouldn't match 'I' - Assert.Equal(Utf8Span.Empty.GetHashCode(StringComparison.CurrentCultureIgnoreCase), span[^0..].GetHashCode(StringComparison.CurrentCultureIgnoreCase)); // null should equal empty - }); - } - - [Theory] - [InlineData("", true)] - [InlineData("Hello", true)] - [InlineData("\u1234", false)] - public static void IsAscii(string input, bool expected) - { - using BoundedUtf8Span boundedSpan = new BoundedUtf8Span(input); - - Assert.Equal(expected, boundedSpan.Span.IsAscii()); - } - - [Theory] - [InlineData(null, true)] - [InlineData("", true)] - [InlineData(" \u2028\u2029\t\v", true)] - [InlineData(" x\r\n", false)] - [InlineData("\r\nhello\r\n", false)] - [InlineData("\r\n\0\r\n", false)] - [InlineData("\r\n\r\n", true)] - public static void IsEmptyOrWhiteSpace(string input, bool expected) - { - using BoundedUtf8Span boundedSpan = new BoundedUtf8Span(input); - - Assert.Equal(expected, boundedSpan.Span.IsEmptyOrWhiteSpace()); - } - - [Theory] - [InlineData("", "..")] - [InlineData("Hello", "1..")] - [InlineData("Hello", "1..2")] - [InlineData("Hello", "1..^2")] - [InlineData("Hello", "^2..")] - [InlineData("Hello", "^0..")] - [InlineData("résumé", "1..^2")] // include first 'é', exclude last 'é' - [InlineData("résumé", "^2..")] // include only last 'é' - public static void Indexer_Success(string input, string rangeExpression) - { - Range range = ParseRangeExpr(rangeExpression); - - using BoundedUtf8Span boundedSpan = new BoundedUtf8Span(input); - Utf8Span originalSpan = boundedSpan.Span; - Utf8Span slicedSpan = originalSpan[range]; // shouldn't throw - - ref byte startOfOriginalSpan = ref MemoryMarshal.GetReference(originalSpan.Bytes); - ref byte startOfSlicedSpan = ref MemoryMarshal.GetReference(slicedSpan.Bytes); - - // Now ensure the slice was correctly produced by comparing the references directly. - - (int offset, int length) = range.GetOffsetAndLength(originalSpan.Length); - Assert.True(Unsafe.AreSame(ref startOfSlicedSpan, ref Unsafe.Add(ref startOfOriginalSpan, offset))); - Assert.Equal(length, slicedSpan.Length); - } - - [Theory] - [InlineData("résumé", "2..")] // try to split the first 'é' - [InlineData("résumé", "..^1")] // try to split the last 'é' - public static void Indexer_ThrowsIfTryToSplitMultiByteSubsequence(string input, string rangeExpression) - { - Range range = ParseRangeExpr(rangeExpression); - - using BoundedUtf8Span boundedSpan = new BoundedUtf8Span(input); - - Assert.Throws(() => { var _ = boundedSpan.Span[range]; }); - } - - - [Theory] - [MemberData(nameof(TranscodingTestData))] - public static void ToCharArrayTest(string expected) - { - // Arrange - - using BoundedUtf8Span boundedSpan = new BoundedUtf8Span(expected); - Utf8Span span = boundedSpan.Span; - - // Act - - char[] returned = span.ToCharArray(); - - // Assert - - Assert.Equal(expected, returned); // IEnumerable - } - - [Fact] - public static void ToCharArrayTest_Null() - { - Assert.Same(Array.Empty(), Utf8Span.Empty.ToCharArray()); - } - - [Theory] - [MemberData(nameof(TranscodingTestData))] - public static void ToCharsTest(string expected) - { - // Arrange - - using BoundedUtf8Span boundedSpan = new BoundedUtf8Span(expected); - Utf8Span span = boundedSpan.Span; - - // Act & assert, first with improperly-sized buffer - - if (expected.Length > 0) - { - using BoundedMemory boundedMemory = BoundedMemory.Allocate(expected.Length - 1); - Assert.Equal(-1, span.ToChars(boundedMemory.Span)); - } - - // Then with properly-sized buffer and too-large buffer - - for (int i = expected.Length; i <= expected.Length + 1; i++) - { - using BoundedMemory boundedMemory = BoundedMemory.Allocate(i); - Assert.Equal(expected.Length, span.ToChars(boundedMemory.Span)); - Assert.True(boundedMemory.Span.Slice(0, expected.Length).SequenceEqual(expected.AsSpan())); - } - } - - [Fact] - public static void ToCharsTest_Null() - { - for (int i = 0; i <= 1; i++) // test both with properly-sized buffer and with too-large buffer - { - using BoundedMemory boundedMemory = BoundedMemory.Allocate(i); - Assert.Equal(0, Utf8Span.Empty.ToChars(boundedMemory.Span)); - } - } - - [Theory] - [MemberData(nameof(TranscodingTestData))] - public static void ToStringTest(string expected) - { - // Arrange - - using BoundedUtf8Span boundedSpan = new BoundedUtf8Span(expected); - Utf8Span span = boundedSpan.Span; - - // Act & assert - - Assert.Equal(expected, span.ToString()); - } - - [Fact] - public static void ToStringTest_Null() - { - Assert.Same(string.Empty, Utf8Span.Empty.ToString()); - } - - [Theory] - [MemberData(nameof(TranscodingTestData))] - public static void ToUtf8StringTest(string expected) - { - // Arrange - - ustring utf8 = u8(expected); - - using BoundedUtf8Span boundedSpan = new BoundedUtf8Span(expected); - Utf8Span span = boundedSpan.Span; - - // Act & assert - - Assert.Equal(utf8, span.ToUtf8String()); - } - - [Fact] - public static void ToUtf8StringTest_Null() - { - Assert.Same(ustring.Empty, Utf8Span.Empty.ToUtf8String()); - } - - public static IEnumerable TranscodingTestData() - { - yield return new object[] { "" }; // empty - yield return new object[] { "Hello" }; // simple ASCII - yield return new object[] { "a\U00000123b\U00001234c\U00101234d" }; // with multi-byte sequences of varying lengths - yield return new object[] { "\uF8FF\uE000\U000FFFFF" }; // with scalars from the private use areas - } - } -} diff --git a/src/libraries/System.Utf8String.Experimental/tests/System/Utf8StringTests.Comparison.cs b/src/libraries/System.Utf8String.Experimental/tests/System/Utf8StringTests.Comparison.cs deleted file mode 100644 index 4c17c5de74f15..0000000000000 --- a/src/libraries/System.Utf8String.Experimental/tests/System/Utf8StringTests.Comparison.cs +++ /dev/null @@ -1,49 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using Xunit; - -using static System.Tests.Utf8TestUtilities; - -namespace System.Tests -{ - public unsafe partial class Utf8StringTests - { - [Fact] - public static void AreEquivalent_Utf8StringAndString_NullHandling() - { - Assert.True(Utf8String.AreEquivalent((Utf8String)null, (string)null)); - Assert.False(Utf8String.AreEquivalent(Utf8String.Empty, (string)null)); - Assert.False(Utf8String.AreEquivalent((Utf8String)null, string.Empty)); - Assert.True(Utf8String.AreEquivalent(Utf8String.Empty, string.Empty)); - } - - [Theory] - [InlineData("Hello", "hello", false)] - [InlineData("hello", "hello", true)] - [InlineData("hello", "helloo", false)] - [InlineData("hellooo", "helloo", false)] - [InlineData("encyclopaedia", "encyclopaedia", true)] - [InlineData("encyclopaedia", "encyclop\u00e6dia", false)] - [InlineData("encyclop\u00e6dia", "encyclop\u00e6dia", true)] - public static void AreEquivalent_Tests(string utf8Input, string utf16Input, bool expected) - { - Utf8String asUtf8 = u8(utf8Input); - - // Call all three overloads - - Assert.Equal(expected, Utf8String.AreEquivalent(asUtf8, utf16Input)); - Assert.Equal(expected, Utf8String.AreEquivalent(asUtf8.AsSpan(), utf16Input.AsSpan())); - Assert.Equal(expected, Utf8String.AreEquivalent(asUtf8.AsBytes(), utf16Input.AsSpan())); - } - - [Theory] - [InlineData(new byte[] { 0xED, 0xA0, 0x80 }, new char[] { '\uD800' })] // don't support "wobbly" UTF-8 - [InlineData(new byte[] { 0xED, 0xA0, 0x80, 0xED, 0xBF, 0xBF }, new char[] { '\uD800', '\uDFFF' })] // don't support "wobbly" UTF-8 - [InlineData(new byte[] { 0xED }, new char[] { '\uD800' })] // don't support partials - public static void AreEquivalent_IllFormedData_AlwaysReturnsFalse(byte[] asUtf8, char[] asUtf16) - { - Assert.False(Utf8String.AreEquivalent(asUtf8, asUtf16)); - } - } -} diff --git a/src/libraries/System.Utf8String.Experimental/tests/System/Utf8StringTests.Conversion.cs b/src/libraries/System.Utf8String.Experimental/tests/System/Utf8StringTests.Conversion.cs deleted file mode 100644 index c4896fb88189a..0000000000000 --- a/src/libraries/System.Utf8String.Experimental/tests/System/Utf8StringTests.Conversion.cs +++ /dev/null @@ -1,90 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Collections.Generic; -using System.Globalization; -using System.Text; -using System.Text.Tests; -using Xunit; - -using static System.Tests.Utf8TestUtilities; - -namespace System.Tests -{ - public unsafe partial class Utf8StringTests - { - public static IEnumerable NormalizationData() => Utf8SpanTests.NormalizationData(); - - [Theory] - [MemberData(nameof(NormalizationData))] - public static void Normalize(string utf16Source, string utf16Expected, NormalizationForm normalizationForm) - { - Utf8String utf8Source = u8(utf16Source); - - // Quick IsNormalized tests - - Assert.Equal(utf16Source == utf16Expected, utf8Source.IsNormalized(normalizationForm)); - - // Normalize and return new Utf8String instances - - Utf8String utf8Normalized = utf8Source.Normalize(normalizationForm); - Assert.True(Utf8String.AreEquivalent(utf8Normalized, utf16Expected)); - } - - public static IEnumerable CaseConversionData() => Utf8SpanTests.CaseConversionData(); - - [Theory] - [MemberData(nameof(CaseConversionData))] - public static void ToLower(string testData) - { - static void RunTest(string testData, string expected, CultureInfo culture) - { - if (culture is null) - { - Assert.Equal(u8(expected), u8(testData).ToLowerInvariant()); - } - else - { - Assert.Equal(u8(expected), u8(testData).ToLower(culture)); - } - } - - if (testData is null) - { - return; // no point in testing null "this" objects; we'll just null-ref - } - - RunTest(testData, testData.ToLowerInvariant(), null); - RunTest(testData, testData.ToLower(CultureInfo.InvariantCulture), CultureInfo.InvariantCulture); - RunTest(testData, testData.ToLower(CultureInfo.GetCultureInfo("en-US")), CultureInfo.GetCultureInfo("en-US")); - RunTest(testData, testData.ToLower(CultureInfo.GetCultureInfo("tr-TR")), CultureInfo.GetCultureInfo("tr-TR")); - } - - [Theory] - [MemberData(nameof(CaseConversionData))] - public static void ToUpper(string testData) - { - static void RunTest(string testData, string expected, CultureInfo culture) - { - if (culture is null) - { - Assert.Equal(u8(expected), u8(testData).ToUpperInvariant()); - } - else - { - Assert.Equal(u8(expected), u8(testData).ToUpper(culture)); - } - } - - if (testData is null) - { - return; // no point in testing null "this" objects; we'll just null-ref - } - - RunTest(testData, testData.ToUpperInvariant(), null); - RunTest(testData, testData.ToUpper(CultureInfo.InvariantCulture), CultureInfo.InvariantCulture); - RunTest(testData, testData.ToUpper(CultureInfo.GetCultureInfo("en-US")), CultureInfo.GetCultureInfo("en-US")); - RunTest(testData, testData.ToUpper(CultureInfo.GetCultureInfo("tr-TR")), CultureInfo.GetCultureInfo("tr-TR")); - } - } -} diff --git a/src/libraries/System.Utf8String.Experimental/tests/System/Utf8StringTests.Ctor.cs b/src/libraries/System.Utf8String.Experimental/tests/System/Utf8StringTests.Ctor.cs deleted file mode 100644 index f3615ff154777..0000000000000 --- a/src/libraries/System.Utf8String.Experimental/tests/System/Utf8StringTests.Ctor.cs +++ /dev/null @@ -1,344 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Buffers; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using Xunit; - -using static System.Tests.Utf8TestUtilities; - -namespace System.Tests -{ - public unsafe partial class Utf8StringTests - { - [Fact] - public static void Ctor_ByteArrayOffset_Empty_ReturnsEmpty() - { - byte[] inputData = new byte[] { (byte)'H', (byte)'e', (byte)'l', (byte)'l', (byte)'o' }; - AssertSameAsEmpty(new Utf8String(inputData, 3, 0)); - } - - [Fact] - public static void Ctor_ByteArrayOffset_ValidData_ReturnsOriginalContents() - { - byte[] inputData = new byte[] { (byte)'x', (byte)'H', (byte)'e', (byte)'l', (byte)'l', (byte)'o', (byte)'x' }; - Utf8String expected = u8("Hello"); - - var actual = new Utf8String(inputData, 1, 5); - Assert.Equal(expected, actual); - } - - [Fact] - public static void Ctor_ByteArrayOffset_InvalidData_Throws() - { - byte[] inputData = new byte[] { (byte)'x', (byte)'H', (byte)'e', (byte)0xFF, (byte)'l', (byte)'o', (byte)'x' }; - - Assert.Throws(() => new Utf8String(inputData, 0, inputData.Length)); - } - - [Fact] - public static void Ctor_ByteArrayOffset_NullValue_Throws() - { - var exception = Assert.Throws(() => new Utf8String((byte[])null, 0, 0)); - Assert.Equal("value", exception.ParamName); - } - - [Fact] - public static void Ctor_ByteArrayOffset_InvalidStartIndexOrLength_Throws() - { - byte[] inputData = new byte[] { (byte)'H', (byte)'e', (byte)'l', (byte)'l', (byte)'o' }; - - Assert.Throws(() => new Utf8String(inputData, 1, 5)); - } - - [Fact] - public static void Ctor_BytePointer_Null_Throws() - { - var exception = Assert.Throws(() => new Utf8String((byte*)null)); - Assert.Equal("value", exception.ParamName); - } - - [Fact] - public static void Ctor_BytePointer_Empty_ReturnsEmpty() - { - byte[] inputData = new byte[] { 0 }; // standalone null byte - - using (BoundedMemory boundedMemory = BoundedMemory.AllocateFromExistingData(inputData)) - { - AssertSameAsEmpty(new Utf8String((byte*)Unsafe.AsPointer(ref MemoryMarshal.GetReference(boundedMemory.Span)))); - } - } - - [Fact] - public static void Ctor_BytePointer_ValidData_ReturnsOriginalContents() - { - byte[] inputData = new byte[] { (byte)'H', (byte)'e', (byte)'l', (byte)'l', (byte)'o', (byte)'\0' }; - - using (BoundedMemory boundedMemory = BoundedMemory.AllocateFromExistingData(inputData)) - { - Assert.Equal(u8("Hello"), new Utf8String((byte*)Unsafe.AsPointer(ref MemoryMarshal.GetReference(boundedMemory.Span)))); - } - } - - [Fact] - public static void Ctor_BytePointer_InvalidData_Throws() - { - byte[] inputData = new byte[] { (byte)'H', (byte)'e', (byte)0xFF, (byte)'l', (byte)'o', (byte)'\0' }; - - using (BoundedMemory boundedMemory = BoundedMemory.AllocateFromExistingData(inputData)) - { - Assert.Throws(() => new Utf8String((byte*)Unsafe.AsPointer(ref MemoryMarshal.GetReference(boundedMemory.Span)))); - } - } - - [Fact] - public static void Ctor_ByteSpan_Empty_ReturnsEmpty() - { - AssertSameAsEmpty(new Utf8String(ReadOnlySpan.Empty)); - } - - [Fact] - public static void Ctor_ByteSpan_ValidData_ReturnsOriginalContents() - { - byte[] inputData = new byte[] { (byte)'H', (byte)'e', (byte)'l', (byte)'l', (byte)'o' }; - Utf8String expected = u8("Hello"); - - var actual = new Utf8String(inputData.AsSpan()); - Assert.Equal(expected, actual); - } - - [Fact] - public static void Ctor_ByteSpan_InvalidData_Throws() - { - byte[] inputData = new byte[] { (byte)'H', (byte)'e', (byte)0xFF, (byte)'l', (byte)'o' }; - - Assert.Throws(() => new Utf8String(inputData.AsSpan())); - } - - [Fact] - public static void Ctor_CharArrayOffset_Empty_ReturnsEmpty() - { - char[] inputData = "H\U00012345ello".ToCharArray(); // ok to have an empty slice in the middle of a multi-byte subsequence - AssertSameAsEmpty(new Utf8String(inputData, 3, 0)); - } - - [Fact] - public static void Ctor_CharArrayOffset_ValidData_ReturnsAsUtf8() - { - char[] inputData = "H\U00012345\u07ffello".ToCharArray(); - Utf8String expected = u8("\u07ffello"); - - var actual = new Utf8String(inputData, 3, 5); - Assert.Equal(expected, actual); - } - - [Fact] - public static void Ctor_CharArrayOffset_InvalidData_Throws() - { - char[] inputData = "H\ud800ello".ToCharArray(); - - Assert.Throws(() => new Utf8String(inputData, 0, inputData.Length)); - } - - [Fact] - public static void Ctor_CharArrayOffset_NullValue_Throws() - { - var exception = Assert.Throws(() => new Utf8String((char[])null, 0, 0)); - Assert.Equal("value", exception.ParamName); - } - - [Fact] - public static void Ctor_CharArrayOffset_InvalidStartIndexOrLength_Throws() - { - char[] inputData = "Hello".ToCharArray(); - - Assert.Throws(() => new Utf8String(inputData, 1, 5)); - } - - [Fact] - public static void Ctor_CharPointer_Null_Throws() - { - var exception = Assert.Throws(() => new Utf8String((char*)null)); - Assert.Equal("value", exception.ParamName); - } - - [Fact] - public static void Ctor_CharPointer_Empty_ReturnsEmpty() - { - char[] inputData = new char[] { '\0' }; // standalone null char - - using (BoundedMemory boundedMemory = BoundedMemory.AllocateFromExistingData(inputData)) - { - AssertSameAsEmpty(new Utf8String((char*)Unsafe.AsPointer(ref MemoryMarshal.GetReference(boundedMemory.Span)))); - } - } - - [Fact] - public static void Ctor_CharPointer_ValidData_ReturnsOriginalContents() - { - char[] inputData = "Hello\0".ToCharArray(); // need to manually null-terminate - - using (BoundedMemory boundedMemory = BoundedMemory.AllocateFromExistingData(inputData)) - { - Assert.Equal(u8("Hello"), new Utf8String((char*)Unsafe.AsPointer(ref MemoryMarshal.GetReference(boundedMemory.Span)))); - } - } - - [Fact] - public static void Ctor_CharPointer_InvalidData_Throws() - { - char[] inputData = "He\ud800llo\0".ToCharArray(); // need to manually null-terminate - - using (BoundedMemory boundedMemory = BoundedMemory.AllocateFromExistingData(inputData)) - { - Assert.Throws(() => new Utf8String((char*)Unsafe.AsPointer(ref MemoryMarshal.GetReference(boundedMemory.Span)))); - } - } - - [Fact] - public static void Ctor_CharSpan_Empty_ReturnsEmpty() - { - AssertSameAsEmpty(new Utf8String(ReadOnlySpan.Empty)); - } - - [Fact] - public static void Ctor_CharSpan_ValidData_ReturnsOriginalContents() - { - char[] inputData = "Hello".ToCharArray(); - Utf8String expected = u8("Hello"); - - var actual = new Utf8String(inputData.AsSpan()); - Assert.Equal(expected, actual); - } - - [Fact] - public static void Ctor_CharSpan_InvalidData_Throws() - { - char[] inputData = "He\ud800llo".ToCharArray(); - - Assert.Throws(() => new Utf8String(inputData.AsSpan())); - } - - [Fact] - public static void Ctor_String_Null_Throws() - { - var exception = Assert.Throws(() => new Utf8String((string)null)); - Assert.Equal("value", exception.ParamName); - } - - [Fact] - public static void Ctor_String_Empty_ReturnsEmpty() - { - AssertSameAsEmpty(new Utf8String(string.Empty)); - } - - [Fact] - public static void Ctor_String_ValidData_ReturnsOriginalContents() - { - Assert.Equal(u8("Hello"), new Utf8String("Hello")); - } - - [Fact] - public static void Ctor_String_Long_ReturnsOriginalContents() - { - string longString = new string('a', 500); - Assert.Equal(u8(longString), new Utf8String(longString)); - } - - [Fact] - public static void Ctor_String_InvalidData_Throws() - { - Assert.Throws(() => new Utf8String("He\uD800lo")); - } - - [Fact] - public static void Ctor_NonValidating_FromByteSpan() - { - byte[] inputData = new byte[] { (byte)'x', (byte)'y', (byte)'z' }; - Utf8String actual = Utf8String.UnsafeCreateWithoutValidation(inputData); - - Assert.Equal(u8("xyz"), actual); - } - - [Fact] - public static void Ctor_CreateFromRelaxed_Utf16() - { - Assert.Same(Utf8String.Empty, Utf8String.CreateFromRelaxed(ReadOnlySpan.Empty)); - Assert.Equal(u8("xy\uFFFDz"), Utf8String.CreateFromRelaxed("xy\ud800z".AsSpan())); - } - - [Fact] - public static void Ctor_CreateFromRelaxed_Utf8() - { - Assert.Same(Utf8String.Empty, Utf8String.CreateFromRelaxed(ReadOnlySpan.Empty)); - Assert.Equal(u8("xy\uFFFDz"), Utf8String.CreateFromRelaxed(new byte[] { (byte)'x', (byte)'y', 0xF4, 0x80, 0x80, (byte)'z' })); - } - - [Fact] - public static void Ctor_TryCreateFrom_Utf8() - { - Utf8String value; - - // Empty string - - Assert.True(Utf8String.TryCreateFrom(ReadOnlySpan.Empty, out value)); - Assert.Same(Utf8String.Empty, value); - - // Well-formed ASCII contents - - Assert.True(Utf8String.TryCreateFrom(new byte[] { (byte)'H', (byte)'e', (byte)'l', (byte)'l', (byte)'o' }, out value)); - Assert.Equal(u8("Hello"), value); - - // Well-formed non-ASCII contents - - Assert.True(Utf8String.TryCreateFrom(new byte[] { 0xF0, 0x9F, 0x91, 0xBD }, out value)); // U+1F47D EXTRATERRESTRIAL ALIEN - Assert.Equal(u8("\U0001F47D"), value); - - // Ill-formed contents - - Assert.False(Utf8String.TryCreateFrom(new byte[] { 0xF0, 0x9F, 0x91, (byte)'x' }, out value)); - Assert.Null(value); - } - - [Fact] - public static void Ctor_TryCreateFrom_Utf16() - { - Utf8String value; - - // Empty string - - Assert.True(Utf8String.TryCreateFrom(ReadOnlySpan.Empty, out value)); - Assert.Same(Utf8String.Empty, value); - - // Well-formed ASCII contents - - Assert.True(Utf8String.TryCreateFrom("Hello".AsSpan(), out value)); - Assert.Equal(u8("Hello"), value); - - // Well-formed non-ASCII contents - - Assert.True(Utf8String.TryCreateFrom("\U0001F47D".AsSpan(), out value)); // U+1F47D EXTRATERRESTRIAL ALIEN - Assert.Equal(u8("\U0001F47D"), value); - - // Ill-formed contents - - Assert.False(Utf8String.TryCreateFrom("\uD800x".AsSpan(), out value)); - Assert.Null(value); - } - - private static void AssertSameAsEmpty(Utf8String value) - { -#if NETFRAMEWORK - // When OOB, we can't change the actual object returned from a constructor. - // So just assert the underlying "_bytes" is the same. - Assert.Equal(0, value.Length); - Assert.True(Unsafe.AreSame( - ref Unsafe.AsRef(in Utf8String.Empty.GetPinnableReference()), - ref Unsafe.AsRef(in value.GetPinnableReference()))); -#else - Assert.Same(Utf8String.Empty, value); -#endif - } - } -} diff --git a/src/libraries/System.Utf8String.Experimental/tests/System/Utf8StringTests.Ctor.netcoreapp.cs b/src/libraries/System.Utf8String.Experimental/tests/System/Utf8StringTests.Ctor.netcoreapp.cs deleted file mode 100644 index f6c334e6f8006..0000000000000 --- a/src/libraries/System.Utf8String.Experimental/tests/System/Utf8StringTests.Ctor.netcoreapp.cs +++ /dev/null @@ -1,107 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Buffers; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using Xunit; - -using static System.Tests.Utf8TestUtilities; - -namespace System.Tests -{ - public unsafe partial class Utf8StringTests - { - [Fact] - public static void Ctor_NonValidating_FromDelegate() - { - object expectedState = new object(); - SpanAction spanAction = (span, actualState) => - { - Assert.Same(expectedState, actualState); - Assert.NotEqual(0, span.Length); // shouldn't have been called for a zero-length span - - for (int i = 0; i < span.Length; i++) - { - Assert.Equal(0, span[i]); // should've been zero-inited - span[i] = (byte)('a' + (i % 26)); // writes "abc...xyzabc...xyz..." - } - }; - - ArgumentException exception = Assert.Throws(() => Utf8String.UnsafeCreateWithoutValidation(-1, expectedState, spanAction)); - Assert.Equal("length", exception.ParamName); - - exception = Assert.Throws(() => Utf8String.UnsafeCreateWithoutValidation(10, expectedState, action: null)); - Assert.Equal("action", exception.ParamName); - - Assert.Same(Utf8String.Empty, Utf8String.UnsafeCreateWithoutValidation(0, expectedState, spanAction)); - - Assert.Equal(u8("abcde"), Utf8String.UnsafeCreateWithoutValidation(5, expectedState, spanAction)); - } - - [Fact] - public static void Ctor_Validating_FromDelegate() - { - object expectedState = new object(); - SpanAction spanAction = (span, actualState) => - { - Assert.Same(expectedState, actualState); - Assert.NotEqual(0, span.Length); // shouldn't have been called for a zero-length span - - for (int i = 0; i < span.Length; i++) - { - Assert.Equal(0, span[i]); // should've been zero-inited - span[i] = (byte)('a' + (i % 26)); // writes "abc...xyzabc...xyz..." - } - }; - - ArgumentException exception = Assert.Throws(() => Utf8String.Create(-1, expectedState, spanAction)); - Assert.Equal("length", exception.ParamName); - - exception = Assert.Throws(() => Utf8String.Create(10, expectedState, action: null)); - Assert.Equal("action", exception.ParamName); - - Assert.Same(Utf8String.Empty, Utf8String.Create(0, expectedState, spanAction)); - - Assert.Equal(u8("abcde"), Utf8String.Create(5, expectedState, spanAction)); - } - - [Fact] - public static void Ctor_Validating_FromDelegate_ThrowsIfDelegateProvidesInvalidData() - { - SpanAction spanAction = (span, actualState) => - { - span[0] = 0xFF; // never a valid UTF-8 byte - }; - - Assert.Throws(() => Utf8String.Create(10, new object(), spanAction)); - } - - [Fact] - public static void Ctor_CreateRelaxed_FromDelegate() - { - object expectedState = new object(); - SpanAction spanAction = (span, actualState) => - { - Assert.Same(expectedState, actualState); - Assert.NotEqual(0, span.Length); // shouldn't have been called for a zero-length span - - for (int i = 0; i < span.Length; i++) - { - Assert.Equal(0, span[i]); // should've been zero-inited - span[i] = 0xFF; // never a valid UTF-8 byte - } - }; - - ArgumentException exception = Assert.Throws(() => Utf8String.CreateRelaxed(-1, expectedState, spanAction)); - Assert.Equal("length", exception.ParamName); - - exception = Assert.Throws(() => Utf8String.CreateRelaxed(10, expectedState, action: null)); - Assert.Equal("action", exception.ParamName); - - Assert.Same(Utf8String.Empty, Utf8String.CreateRelaxed(0, expectedState, spanAction)); - - Assert.Equal(u8("\uFFFD\uFFFD"), Utf8String.CreateRelaxed(2, expectedState, spanAction)); - } - } -} diff --git a/src/libraries/System.Utf8String.Experimental/tests/System/Utf8StringTests.Enumeration.cs b/src/libraries/System.Utf8String.Experimental/tests/System/Utf8StringTests.Enumeration.cs deleted file mode 100644 index e8ea054578e6f..0000000000000 --- a/src/libraries/System.Utf8String.Experimental/tests/System/Utf8StringTests.Enumeration.cs +++ /dev/null @@ -1,85 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Text; -using Xunit; - -using static System.Tests.Utf8TestUtilities; - -namespace System.Tests -{ - public unsafe partial class Utf8StringTests - { - [Fact] - public static void BytesProperty_FromData() - { - Utf8String ustr = u8("\U00000012\U00000123\U00001234\U00101234\U00000012\U00000123\U00001234\U00101234"); - - Assert.Equal(new byte[] - { - 0x12, - 0xC4, 0xA3, - 0xE1, 0x88, 0xB4, - 0xF4, 0x81, 0x88, 0xB4, - 0x12, - 0xC4, 0xA3, - 0xE1, 0x88, 0xB4, - 0xF4, 0x81, 0x88, 0xB4, - }, ustr.Bytes); - } - - [Fact] - public static void BytesProperty_FromEmpty() - { - Assert.False(Utf8String.Empty.Bytes.GetEnumerator().MoveNext()); - } - - [Fact] - public static void CharsProperty_FromData() - { - Utf8String ustr = u8("\U00000012\U00000123\U00001234\U00101234\U00000012\U00000123\U00001234\U00101234"); - - Assert.Equal(new char[] - { - '\u0012', - '\u0123', - '\u1234', - '\uDBC4', '\uDE34', - '\u0012', - '\u0123', - '\u1234', - '\uDBC4', '\uDE34', - }, ustr.Chars); - } - - [Fact] - public static void CharsProperty_FromEmpty() - { - Assert.False(Utf8String.Empty.Chars.GetEnumerator().MoveNext()); - } - - [Fact] - public static void RunesProperty_FromData() - { - Utf8String ustr = u8("\U00000012\U00000123\U00001234\U00101234\U00000012\U00000123\U00001234\U00101234"); - - Assert.Equal(new Rune[] - { - new Rune(0x0012), - new Rune(0x0123), - new Rune(0x1234), - new Rune(0x101234), - new Rune(0x0012), - new Rune(0x0123), - new Rune(0x1234), - new Rune(0x101234), - }, ustr.Runes); - } - - [Fact] - public static void RunesProperty_FromEmpty() - { - Assert.False(Utf8String.Empty.Runes.GetEnumerator().MoveNext()); - } - } -} diff --git a/src/libraries/System.Utf8String.Experimental/tests/System/Utf8StringTests.Manipulation.cs b/src/libraries/System.Utf8String.Experimental/tests/System/Utf8StringTests.Manipulation.cs deleted file mode 100644 index 74ddd641beaaf..0000000000000 --- a/src/libraries/System.Utf8String.Experimental/tests/System/Utf8StringTests.Manipulation.cs +++ /dev/null @@ -1,210 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Text.Tests; -using Xunit; - -using static System.Tests.Utf8TestUtilities; - -namespace System.Tests -{ - public unsafe partial class Utf8StringTests - { - private delegate Utf8String.SplitResult Utf8StringSplitDelegate(Utf8String ustr, Utf8StringSplitOptions splitOptions); - - [Fact] - public static void Split_Utf8StringSeparator_WithNullOrEmptySeparator_Throws() - { - var ex = Assert.Throws(() => { u8("Hello").Split((Utf8String)null); }); - Assert.Equal("separator", ex.ParamName); - - // Shouldn't be able to split on an empty Utf8String. - // Such an enumerator would iterate forever, so we forbid it. - - ex = Assert.Throws(() => { u8("Hello").Split(Utf8String.Empty); }); - Assert.Equal("separator", ex.ParamName); - } - - [Fact] - public static void Split_InvalidChar_Throws() - { - // Shouldn't be able to split on a standalone surrogate char - // Other search methods (TryFind) return false when given a standalone surrogate char as input, - // but the Split methods returns a complex data structure instead of a simple bool. So to keep - // the logic of that data structure relatively simple we'll forbid the bad char at the call site. - - var ex = Assert.Throws(() => { u8("Hello").Split('\ud800'); }); - Assert.Equal("separator", ex.ParamName); - } - - public static IEnumerable SplitData_CharSeparator => Utf8SpanTests.SplitData_CharSeparator(); - - [Theory] - [MemberData(nameof(SplitData_CharSeparator))] - public static void Split_Char(Utf8String source, char separator, Range[] expectedRanges) - { - SplitTest_Common(source ?? Utf8String.Empty, (ustr, splitOptions) => ustr.Split(separator, splitOptions), expectedRanges); - } - - [Fact] - public static void Split_Deconstruct() - { - Utf8String ustr = u8("a,b,c,d,e"); - - { - (Utf8String a, Utf8String b) = ustr.Split('x'); // not found - Assert.Same(ustr, a); // Expected referential equality of input - Assert.Null(b); - } - - { - (Utf8String a, Utf8String b) = ustr.Split(','); - Assert.Equal(u8("a"), a); - Assert.Equal(u8("b,c,d,e"), b); - } - - { - (Utf8String a, Utf8String b, Utf8String c, Utf8String d, Utf8String e) = ustr.Split(','); - Assert.Equal(u8("a"), a); - Assert.Equal(u8("b"), b); - Assert.Equal(u8("c"), c); - Assert.Equal(u8("d"), d); - Assert.Equal(u8("e"), e); - } - - { - (Utf8String a, Utf8String b, Utf8String c, Utf8String d, Utf8String e, Utf8String f, Utf8String g, Utf8String h) = ustr.Split(','); - Assert.Equal(u8("a"), a); - Assert.Equal(u8("b"), b); - Assert.Equal(u8("c"), c); - Assert.Equal(u8("d"), d); - Assert.Equal(u8("e"), e); - Assert.Null(f); - Assert.Null(g); - Assert.Null(h); - } - } - - [Fact] - public static void Split_Deconstruct_WithOptions() - { - Utf8String ustr = u8("a, , b, c,, d, e"); - - // Note referential equality checks below (since we want to know exact slices - // into the original buffer), not deep (textual) equality checks. - - { - (Utf8String a, Utf8String b) = ustr.Split(',', Utf8StringSplitOptions.RemoveEmptyEntries); - Assert.Equal(u8("a"), a); - Assert.Equal(u8(" , b, c,, d, e"), b); - } - - { - (Utf8String a, Utf8String x, Utf8String b, Utf8String c, Utf8String d, Utf8String e) = ustr.Split(',', Utf8StringSplitOptions.RemoveEmptyEntries); - Assert.Equal(u8("a"), a); // "a" - Assert.Equal(u8(" "), x); // " " - Assert.Equal(u8(" b"), b); // " b" - Assert.Equal(u8(" c"), c); // " c" - Assert.Equal(u8(" d"), d); // " d" - Assert.Equal(u8(" e"), e); // " e" - } - - { - (Utf8String a, Utf8String b, Utf8String c, Utf8String d, Utf8String e, Utf8String f, Utf8String g, Utf8String h) = ustr.Split(',', Utf8StringSplitOptions.RemoveEmptyEntries | Utf8StringSplitOptions.TrimEntries); - Assert.Equal(u8("a"), a); - Assert.Equal(u8("b"), b); - Assert.Equal(u8("c"), c); - Assert.Equal(u8("d"), d); - Assert.Equal(u8("e"), e); - Assert.Null(f); - Assert.Null(g); - Assert.Null(h); - } - } - - public static IEnumerable SplitData_RuneSeparator() => Utf8SpanTests.SplitData_RuneSeparator(); - - [Theory] - [MemberData(nameof(SplitData_RuneSeparator))] - public static void Split_Rune(Utf8String source, Rune separator, Range[] expectedRanges) - { - SplitTest_Common(source ?? Utf8String.Empty, (ustr, splitOptions) => ustr.Split(separator, splitOptions), expectedRanges); - } - - public static IEnumerable SplitData_Utf8StringSeparator() => Utf8SpanTests.SplitData_Utf8SpanSeparator(); - - [Theory] - [MemberData(nameof(SplitData_Utf8StringSeparator))] - public static void Split_Utf8String(Utf8String source, Utf8String separator, Range[] expectedRanges) - { - SplitTest_Common(source ?? Utf8String.Empty, (ustr, splitOptions) => ustr.Split(separator, splitOptions), expectedRanges); - } - - private static void SplitTest_Common(Utf8String source, Utf8StringSplitDelegate splitAction, Range[] expectedRanges) - { - // First, run the split with default options and make sure the results are equivalent - - Assert.Equal( - expected: expectedRanges.Select(range => source[range]), - actual: splitAction(source, Utf8StringSplitOptions.None)); - - // Next, run the split with empty entries removed - - Assert.Equal( - expected: expectedRanges.Select(range => source[range]).Where(ustr => ustr.Length != 0), - actual: splitAction(source, Utf8StringSplitOptions.RemoveEmptyEntries)); - - // Next, run the split with results trimmed (but allowing empty results) - - Assert.Equal( - expected: expectedRanges.Select(range => source[range].Trim()), - actual: splitAction(source, Utf8StringSplitOptions.TrimEntries)); - - // Finally, run the split both trimmed and with empty entries removed - - Assert.Equal( - expected: expectedRanges.Select(range => source[range].Trim()).Where(ustr => ustr.Length != 0), - actual: splitAction(source, Utf8StringSplitOptions.TrimEntries | Utf8StringSplitOptions.RemoveEmptyEntries)); - } - - public static IEnumerable Trim_TestData() => Utf8SpanTests.Trim_TestData(); - - [Theory] - [MemberData(nameof(Trim_TestData))] - public static void Trim(string input) - { - if (input is null) - { - return; // don't want to null ref - } - - Utf8String utf8Input = u8(input); - - void RunTest(Func utf8TrimAction, Func utf16TrimAction) - { - Utf8String utf8Trimmed = utf8TrimAction(utf8Input); - string utf16Trimmed = utf16TrimAction(input); - - if (utf16Trimmed.Length == input.Length) - { - Assert.Same(utf8Input, utf8Trimmed); // Trimming should no-op, return original input - } - else if (utf16Trimmed.Length == 0) - { - Assert.Same(Utf8String.Empty, utf8Trimmed); // Trimming an all-whitespace input, return Empty - } - else - { - Assert.True(Utf8String.AreEquivalent(utf8Trimmed, utf16Trimmed)); - } - } - - RunTest(ustr => ustr.Trim(), str => str.Trim()); - RunTest(ustr => ustr.TrimStart(), str => str.TrimStart()); - RunTest(ustr => ustr.TrimEnd(), str => str.TrimEnd()); - } - } -} diff --git a/src/libraries/System.Utf8String.Experimental/tests/System/Utf8StringTests.Searching.cs b/src/libraries/System.Utf8String.Experimental/tests/System/Utf8StringTests.Searching.cs deleted file mode 100644 index 53307936c5e63..0000000000000 --- a/src/libraries/System.Utf8String.Experimental/tests/System/Utf8StringTests.Searching.cs +++ /dev/null @@ -1,512 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Collections.Generic; -using System.Globalization; -using System.Text; -using System.Text.Tests; -using Xunit; - -using static System.Tests.Utf8TestUtilities; - -using ustring = System.Utf8String; - -namespace System.Tests -{ - /* - * Please keep these tests in sync with those in Utf8SpanTests.Searching.cs. - */ - - public unsafe partial class Utf8StringTests - { - public static IEnumerable TryFindData_Char_Ordinal() => Utf8SpanTests.TryFindData_Char_Ordinal(); - - [Theory] - [MemberData(nameof(TryFindData_Char_Ordinal))] - public static void TryFind_Char_Ordinal(ustring source, char searchTerm, Range? expectedForwardMatch, Range? expectedBackwardMatch) - { - if (source is null) - { - return; // don't null ref - } - - // First, search forward - - bool wasFound = source.TryFind(searchTerm, out Range actualForwardMatch); - Assert.Equal(expectedForwardMatch.HasValue, wasFound); - - if (wasFound) - { - AssertRangesEqual(source.Length, expectedForwardMatch.Value, actualForwardMatch); - } - - // Also check Contains / StartsWith / SplitOn - - Assert.Equal(wasFound, source.Contains(searchTerm)); - Assert.Equal(wasFound && source[..actualForwardMatch.Start].Length == 0, source.StartsWith(searchTerm)); - - (var before, var after) = source.SplitOn(searchTerm); - if (wasFound) - { - Assert.Equal(source[..actualForwardMatch.Start], before); - Assert.Equal(source[actualForwardMatch.End..], after); - } - else - { - Assert.Same(source, before); // check for reference equality - Assert.Null(after); - } - - // Now search backward - - wasFound = source.TryFindLast(searchTerm, out Range actualBackwardMatch); - Assert.Equal(expectedBackwardMatch.HasValue, wasFound); - - if (wasFound) - { - AssertRangesEqual(source.Length, expectedBackwardMatch.Value, actualBackwardMatch); - } - - // Also check EndsWith / SplitOnLast - - Assert.Equal(wasFound && source[actualBackwardMatch.End..].Length == 0, source.EndsWith(searchTerm)); - - (before, after) = source.SplitOnLast(searchTerm); - if (wasFound) - { - Assert.Equal(source[..actualBackwardMatch.Start], before); - Assert.Equal(source[actualBackwardMatch.End..], after); - } - else - { - Assert.Same(source, before); // check for reference equality - Assert.Null(after); - } - } - - public static IEnumerable TryFindData_Char_WithComparison() => Utf8SpanTests.TryFindData_Char_WithComparison(); - - [PlatformSpecific(TestPlatforms.Windows)] - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNlsGlobalization))] - [MemberData(nameof(TryFindData_Char_WithComparison))] - public static void TryFind_Char_WithComparison(ustring source, char searchTerm, StringComparison comparison, CultureInfo currentCulture, Range? expectedForwardMatch, Range? expectedBackwardMatch) - { - if (source is null) - { - return; // don't null ref - } - - RunOnDedicatedThread(() => - { - if (currentCulture != null) - { - CultureInfo.CurrentCulture = currentCulture; - } - - if (IsTryFindSupported(comparison)) - { - // First, search forward - - bool wasFound = source.TryFind(searchTerm, comparison, out Range actualForwardMatch); - Assert.Equal(expectedForwardMatch.HasValue, wasFound); - - if (wasFound) - { - AssertRangesEqual(source.Length, expectedForwardMatch.Value, actualForwardMatch); - } - - // Also check Contains / StartsWith / SplitOn - - Assert.Equal(wasFound, source.Contains(searchTerm, comparison)); - Assert.Equal(wasFound && source[..actualForwardMatch.Start].Length == 0, source.StartsWith(searchTerm, comparison)); - - (var before, var after) = source.SplitOn(searchTerm, comparison); - if (wasFound) - { - Assert.Equal(source[..actualForwardMatch.Start], before); - Assert.Equal(source[actualForwardMatch.End..], after); - } - else - { - Assert.Same(source, before); // check for reference equality - Assert.Null(after); - } - - // Now search backward - - wasFound = source.TryFindLast(searchTerm, comparison, out Range actualBackwardMatch); - Assert.Equal(expectedBackwardMatch.HasValue, wasFound); - - if (wasFound) - { - AssertRangesEqual(source.Length, expectedBackwardMatch.Value, actualBackwardMatch); - } - - // Also check EndsWith / SplitOnLast - - Assert.Equal(wasFound && source[actualBackwardMatch.End..].Length == 0, source.EndsWith(searchTerm, comparison)); - - (before, after) = source.SplitOnLast(searchTerm, comparison); - if (wasFound) - { - Assert.Equal(source[..actualBackwardMatch.Start], before); - Assert.Equal(source[actualBackwardMatch.End..], after); - } - else - { - Assert.Same(source, before); // check for reference equality - Assert.Null(after); - } - } - else - { - Assert.Throws(() => source.TryFind(searchTerm, comparison, out var _)); - Assert.Throws(() => source.TryFindLast(searchTerm, comparison, out var _)); - Assert.Throws(() => source.SplitOn(searchTerm, comparison)); - Assert.Throws(() => source.SplitOnLast(searchTerm, comparison)); - - Assert.Equal(expectedForwardMatch.HasValue, source.Contains(searchTerm, comparison)); - Assert.Equal(expectedForwardMatch.HasValue && source[..expectedForwardMatch.Value.Start].Length == 0, source.StartsWith(searchTerm, comparison)); - Assert.Equal(expectedBackwardMatch.HasValue && source[expectedBackwardMatch.Value.End..].Length == 0, source.EndsWith(searchTerm, comparison)); - } - }); - } - - public static IEnumerable TryFindData_Rune_Ordinal() => Utf8SpanTests.TryFindData_Rune_Ordinal(); - - [Theory] - [MemberData(nameof(TryFindData_Rune_Ordinal))] - public static void TryFind_Rune_Ordinal(ustring source, Rune searchTerm, Range? expectedForwardMatch, Range? expectedBackwardMatch) - { - if (source is null) - { - return; // don't null ref - } - - // First, search forward - - bool wasFound = source.TryFind(searchTerm, out Range actualForwardMatch); - Assert.Equal(expectedForwardMatch.HasValue, wasFound); - - if (wasFound) - { - AssertRangesEqual(source.Length, expectedForwardMatch.Value, actualForwardMatch); - } - - // Also check Contains / StartsWith / SplitOn - - Assert.Equal(wasFound, source.Contains(searchTerm)); - Assert.Equal(wasFound && source[..actualForwardMatch.Start].Length == 0, source.StartsWith(searchTerm)); - - (var before, var after) = source.SplitOn(searchTerm); - if (wasFound) - { - Assert.Equal(source[..actualForwardMatch.Start], before); - Assert.Equal(source[actualForwardMatch.End..], after); - } - else - { - Assert.Same(source, before); // check for reference equality - Assert.Null(after); - } - - // Now search backward - - wasFound = source.TryFindLast(searchTerm, out Range actualBackwardMatch); - Assert.Equal(expectedBackwardMatch.HasValue, wasFound); - - if (wasFound) - { - AssertRangesEqual(source.Length, expectedBackwardMatch.Value, actualBackwardMatch); - } - - // Also check EndsWith / SplitOnLast - - Assert.Equal(wasFound && source[actualBackwardMatch.End..].Length == 0, source.EndsWith(searchTerm)); - - (before, after) = source.SplitOnLast(searchTerm); - if (wasFound) - { - Assert.Equal(source[..actualBackwardMatch.Start], before); - Assert.Equal(source[actualBackwardMatch.End..], after); - } - else - { - Assert.Same(source, before); // check for reference equality - Assert.Null(after); - } - } - - public static IEnumerable TryFindData_Rune_WithComparison() => Utf8SpanTests.TryFindData_Rune_WithComparison(); - - [PlatformSpecific(TestPlatforms.Windows)] - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNlsGlobalization))] - [MemberData(nameof(TryFindData_Rune_WithComparison))] - public static void TryFind_Rune_WithComparison(ustring source, Rune searchTerm, StringComparison comparison, CultureInfo currentCulture, Range? expectedForwardMatch, Range? expectedBackwardMatch) - { - if (source is null) - { - return; // don't null ref - } - - RunOnDedicatedThread(() => - { - if (currentCulture != null) - { - CultureInfo.CurrentCulture = currentCulture; - } - - if (IsTryFindSupported(comparison)) - { - // First, search forward - - bool wasFound = source.TryFind(searchTerm, comparison, out Range actualForwardMatch); - Assert.Equal(expectedForwardMatch.HasValue, wasFound); - - if (wasFound) - { - AssertRangesEqual(source.Length, expectedForwardMatch.Value, actualForwardMatch); - } - - // Also check Contains / StartsWith / SplitOn - - Assert.Equal(wasFound, source.Contains(searchTerm, comparison)); - Assert.Equal(wasFound && source[..actualForwardMatch.Start].Length == 0, source.StartsWith(searchTerm, comparison)); - - (var before, var after) = source.SplitOn(searchTerm, comparison); - if (wasFound) - { - Assert.Equal(source[..actualForwardMatch.Start], before); - Assert.Equal(source[actualForwardMatch.End..], after); - } - else - { - Assert.Same(source, before); // check for reference equality - Assert.Null(after); - } - - // Now search backward - - wasFound = source.TryFindLast(searchTerm, comparison, out Range actualBackwardMatch); - Assert.Equal(expectedBackwardMatch.HasValue, wasFound); - - if (wasFound) - { - AssertRangesEqual(source.Length, expectedBackwardMatch.Value, actualBackwardMatch); - } - - // Also check EndsWith / SplitOnLast - - Assert.Equal(wasFound && source[actualBackwardMatch.End..].Length == 0, source.EndsWith(searchTerm, comparison)); - - (before, after) = source.SplitOnLast(searchTerm, comparison); - if (wasFound) - { - Assert.Equal(source[..actualBackwardMatch.Start], before); - Assert.Equal(source[actualBackwardMatch.End..], after); - } - else - { - Assert.Same(source, before); // check for reference equality - Assert.Null(after); - } - } - else - { - Assert.Throws(() =>source.TryFind(searchTerm, comparison, out var _)); - Assert.Throws(() =>source.TryFindLast(searchTerm, comparison, out var _)); - Assert.Throws(() =>source.SplitOn(searchTerm, comparison)); - Assert.Throws(() =>source.SplitOnLast(searchTerm, comparison)); - - Assert.Equal(expectedForwardMatch.HasValue, source.Contains(searchTerm, comparison)); - Assert.Equal(expectedForwardMatch.HasValue && source[..expectedForwardMatch.Value.Start].Length == 0, source.StartsWith(searchTerm, comparison)); - Assert.Equal(expectedBackwardMatch.HasValue && source[expectedBackwardMatch.Value.End..].Length == 0, source.EndsWith(searchTerm, comparison)); - } - }); - } - - public static IEnumerable TryFindData_Utf8String_Ordinal() => Utf8SpanTests.TryFindData_Utf8Span_Ordinal(); - - [Theory] - [MemberData(nameof(TryFindData_Utf8String_Ordinal))] - public static void TryFind_Utf8String_Ordinal(ustring source, ustring searchTerm, Range? expectedForwardMatch, Range? expectedBackwardMatch) - { - if (source is null) - { - return; // don't null ref - } - - // First, search forward - - bool wasFound = source.TryFind(searchTerm, out Range actualForwardMatch); - Assert.Equal(expectedForwardMatch.HasValue, wasFound); - - if (wasFound) - { - AssertRangesEqual(source.Length, expectedForwardMatch.Value, actualForwardMatch); - } - - // Also check Contains / StartsWith / SplitOn - - Assert.Equal(wasFound, source.Contains(searchTerm)); - Assert.Equal(wasFound && source[..actualForwardMatch.Start].Length == 0, source.StartsWith(searchTerm)); - - (var before, var after) = source.SplitOn(searchTerm); - if (wasFound) - { - Assert.Equal(source[..actualForwardMatch.Start], before); - Assert.Equal(source[actualForwardMatch.End..], after); - } - else - { - Assert.Same(source, before); // check for reference equality - Assert.Null(after); - } - - // Now search backward - - wasFound = source.TryFindLast(searchTerm, out Range actualBackwardMatch); - Assert.Equal(expectedBackwardMatch.HasValue, wasFound); - - if (wasFound) - { - AssertRangesEqual(source.Length, expectedBackwardMatch.Value, actualBackwardMatch); - } - - // Also check EndsWith / SplitOnLast - - Assert.Equal(wasFound && source[actualBackwardMatch.End..].Length == 0, source.EndsWith(searchTerm)); - - (before, after) = source.SplitOnLast(searchTerm); - if (wasFound) - { - Assert.Equal(source[..actualBackwardMatch.Start], before); - Assert.Equal(source[actualBackwardMatch.End..], after); - } - else - { - Assert.Same(source, before); // check for reference equality - Assert.Null(after); - } - } - - public static IEnumerable TryFindData_Utf8String_WithComparison() => Utf8SpanTests.TryFindData_Utf8Span_WithComparison(); - - [PlatformSpecific(TestPlatforms.Windows)] - [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNlsGlobalization))] - [MemberData(nameof(TryFindData_Utf8String_WithComparison))] - public static void TryFind_Utf8String_WithComparison(ustring source, ustring searchTerm, StringComparison comparison, CultureInfo currentCulture, Range? expectedForwardMatch, Range? expectedBackwardMatch) - { - if (source is null) - { - return; // don't null ref - } - - RunOnDedicatedThread(() => - { - if (currentCulture != null) - { - CultureInfo.CurrentCulture = currentCulture; - } - - if (IsTryFindSupported(comparison)) - { - // First, search forward - - bool wasFound = source.TryFind(searchTerm, comparison, out Range actualForwardMatch); - Assert.Equal(expectedForwardMatch.HasValue, wasFound); - - if (wasFound) - { - AssertRangesEqual(source.Length, expectedForwardMatch.Value, actualForwardMatch); - } - - // Also check Contains / StartsWith / SplitOn - - Assert.Equal(wasFound, source.Contains(searchTerm, comparison)); - Assert.Equal(wasFound && source[..actualForwardMatch.Start].Length == 0, source.StartsWith(searchTerm, comparison)); - - (var before, var after) = source.SplitOn(searchTerm, comparison); - if (wasFound) - { - Assert.Equal(source[..actualForwardMatch.Start], before); - Assert.Equal(source[actualForwardMatch.End..], after); - } - else - { - Assert.Same(source, before); // check for reference equality - Assert.Null(after); - } - - // Now search backward - - wasFound = source.TryFindLast(searchTerm, comparison, out Range actualBackwardMatch); - Assert.Equal(expectedBackwardMatch.HasValue, wasFound); - - if (wasFound) - { - AssertRangesEqual(source.Length, expectedBackwardMatch.Value, actualBackwardMatch); - } - - // Also check EndsWith / SplitOnLast - - Assert.Equal(wasFound && source[actualBackwardMatch.End..].Length == 0, source.EndsWith(searchTerm, comparison)); - - (before, after) = source.SplitOnLast(searchTerm, comparison); - if (wasFound) - { - Assert.Equal(source[..actualBackwardMatch.Start], before); - Assert.Equal(source[actualBackwardMatch.End..], after); - } - else - { - Assert.Same(source, before); // check for reference equality - Assert.Null(after); - } - } - else - { - Assert.Throws(() => source.TryFind(searchTerm, comparison, out var _)); - Assert.Throws(() => source.TryFindLast(searchTerm, comparison, out var _)); - Assert.Throws(() => source.SplitOn(searchTerm, comparison)); - Assert.Throws(() => source.SplitOnLast(searchTerm, comparison)); - - Assert.Equal(expectedForwardMatch.HasValue, source.Contains(searchTerm, comparison)); - Assert.Equal(expectedForwardMatch.HasValue && source[..expectedForwardMatch.Value.Start].Length == 0, source.StartsWith(searchTerm, comparison)); - Assert.Equal(expectedBackwardMatch.HasValue && source[expectedBackwardMatch.Value.End..].Length == 0, source.EndsWith(searchTerm, comparison)); - } - }); - } - - [Fact] - public static void TryFind_WithNullUtf8String_Throws() - { - static void RunTest(Action action) - { - var exception = Assert.Throws(action); - Assert.Equal("value", exception.ParamName); - } - - ustring str = u8("Hello!"); - const ustring value = null; - const StringComparison comparison = StringComparison.OrdinalIgnoreCase; - - // Run this test for a bunch of methods, not simply TryFind - - RunTest(() => str.Contains(value)); - RunTest(() => str.Contains(value, comparison)); - RunTest(() => str.EndsWith(value)); - RunTest(() => str.EndsWith(value, comparison)); - RunTest(() => str.SplitOn(value)); - RunTest(() => str.SplitOn(value, comparison)); - RunTest(() => str.SplitOnLast(value)); - RunTest(() => str.SplitOnLast(value, comparison)); - RunTest(() => str.StartsWith(value)); - RunTest(() => str.StartsWith(value, comparison)); - RunTest(() => str.TryFind(value, out _)); - RunTest(() => str.TryFind(value, comparison, out _)); - RunTest(() => str.TryFindLast(value, out _)); - RunTest(() => str.TryFindLast(value, comparison, out _)); - } - } -} diff --git a/src/libraries/System.Utf8String.Experimental/tests/System/Utf8StringTests.cs b/src/libraries/System.Utf8String.Experimental/tests/System/Utf8StringTests.cs deleted file mode 100644 index 042f9287742ec..0000000000000 --- a/src/libraries/System.Utf8String.Experimental/tests/System/Utf8StringTests.cs +++ /dev/null @@ -1,307 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Collections.Generic; -using System.Globalization; -using Xunit; - -using static System.Tests.Utf8TestUtilities; - -namespace System.Tests -{ - [SkipOnMono("The features from System.Utf8String.Experimental namespace are experimental.")] - public unsafe partial class Utf8StringTests - { - [Fact] - public static void Empty_HasLengthZero() - { - Assert.Equal(0, Utf8String.Empty.Length); - SpanAssert.Equal(ReadOnlySpan.Empty, Utf8String.Empty.AsBytes()); - } - - [Fact] - public static void Empty_ReturnsSingleton() - { - Assert.Same(Utf8String.Empty, Utf8String.Empty); - } - - [Theory] - [InlineData(null, null, true)] - [InlineData("", null, false)] - [InlineData(null, "", false)] - [InlineData("hello", null, false)] - [InlineData(null, "hello", false)] - [InlineData("hello", "hello", true)] - [InlineData("hello", "Hello", false)] - [InlineData("hello there", "hello", false)] - public static void Equality_Ordinal(string aString, string bString, bool expected) - { - Utf8String a = u8(aString); - Utf8String b = u8(bString); - - // Operators - - Assert.Equal(expected, a == b); - Assert.NotEqual(expected, a != b); - - // Static methods - - Assert.Equal(expected, Utf8String.Equals(a, b)); - Assert.Equal(expected, Utf8String.Equals(a, b, StringComparison.Ordinal)); - - // Instance methods - - if (a != null) - { - Assert.Equal(expected, a.Equals((object)b)); - Assert.Equal(expected, a.Equals(b)); - Assert.Equal(expected, a.Equals(b, StringComparison.Ordinal)); - } - } - - [Fact] - public static void GetHashCode_Ordinal() - { - // Generate 17 all-null strings and make sure they have unique hash codes. - // Assuming Marvin32 is a good PRF and has a full 32-bit output domain, we should - // expect this test to fail only once every ~30 million runs due to the birthday paradox. - // That should be good enough for inclusion as a unit test. - - HashSet seenHashCodes = new HashSet(); - - for (int i = 0; i <= 16; i++) - { - Utf8String ustr = new Utf8String(new byte[i]); - - Assert.True(seenHashCodes.Add(ustr.GetHashCode()), "This hash code was previously seen."); - } - } - - [PlatformSpecific(TestPlatforms.Windows)] - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNlsGlobalization))] - public static void GetHashCode_WithComparison() - { - // Since hash code generation is randomized, it's possible (though unlikely) that - // we might see unanticipated collisions. It's ok if this unit test fails once in - // every few million runs, but if the unit test becomes truly flaky then that would - // be indicative of a larger problem with hash code generation. - // - // These tests also make sure that the hash code is computed over the buffer rather - // than over the reference. - - // Ordinal - - { - Utf8String ustr = u8("ababaaAA"); - - Assert.Equal(ustr[0..2].GetHashCode(StringComparison.Ordinal), ustr[2..4].GetHashCode(StringComparison.Ordinal)); - Assert.NotEqual(ustr[4..6].GetHashCode(StringComparison.Ordinal), ustr[6..8].GetHashCode(StringComparison.Ordinal)); - Assert.Equal(Utf8String.Empty.GetHashCode(StringComparison.Ordinal), ustr[^0..].GetHashCode(StringComparison.Ordinal)); - } - - // OrdinalIgnoreCase - - { - Utf8String ustr = u8("ababaaAA"); - - Assert.Equal(ustr[0..2].GetHashCode(StringComparison.OrdinalIgnoreCase), ustr[2..4].GetHashCode(StringComparison.OrdinalIgnoreCase)); - Assert.Equal(ustr[4..6].GetHashCode(StringComparison.OrdinalIgnoreCase), ustr[6..8].GetHashCode(StringComparison.OrdinalIgnoreCase)); - Assert.NotEqual(ustr[0..2].GetHashCode(StringComparison.OrdinalIgnoreCase), ustr[6..8].GetHashCode(StringComparison.OrdinalIgnoreCase)); - Assert.Equal(Utf8String.Empty.GetHashCode(StringComparison.OrdinalIgnoreCase), ustr[^0..].GetHashCode(StringComparison.OrdinalIgnoreCase)); - } - - // InvariantCulture - - { - Utf8String ustr = u8("ae\u00e6AE\u00c6"); // U+00E6 = 'æ' LATIN SMALL LETTER AE, U+00E6 = 'Æ' LATIN CAPITAL LETTER AE - - Assert.Equal(ustr[0..2].GetHashCode(StringComparison.InvariantCulture), ustr[2..4].GetHashCode(StringComparison.InvariantCulture)); - Assert.NotEqual(ustr[0..2].GetHashCode(StringComparison.InvariantCulture), ustr[4..6].GetHashCode(StringComparison.InvariantCulture)); - Assert.Equal(Utf8String.Empty.GetHashCode(StringComparison.InvariantCulture), ustr[^0..].GetHashCode(StringComparison.InvariantCulture)); - } - - // InvariantCultureIgnoreCase - - { - Utf8String ustr = u8("ae\u00e6AE\u00c6EA"); - - Assert.Equal(ustr[0..2].GetHashCode(StringComparison.InvariantCultureIgnoreCase), ustr[2..4].GetHashCode(StringComparison.InvariantCultureIgnoreCase)); - Assert.Equal(ustr[0..2].GetHashCode(StringComparison.InvariantCultureIgnoreCase), ustr[6..8].GetHashCode(StringComparison.InvariantCultureIgnoreCase)); - Assert.NotEqual(ustr[0..2].GetHashCode(StringComparison.InvariantCultureIgnoreCase), ustr[8..10].GetHashCode(StringComparison.InvariantCultureIgnoreCase)); - Assert.Equal(Utf8String.Empty.GetHashCode(StringComparison.InvariantCultureIgnoreCase), ustr[^0..].GetHashCode(StringComparison.InvariantCultureIgnoreCase)); - } - - // Invariant culture should not match Turkish I case conversion - - { - Utf8String ustr = u8("i\u0130"); // U+0130 = 'İ' LATIN CAPITAL LETTER I WITH DOT ABOVE - - Assert.NotEqual(ustr[0..1].GetHashCode(StringComparison.InvariantCultureIgnoreCase), ustr[1..3].GetHashCode(StringComparison.InvariantCultureIgnoreCase)); - } - - // CurrentCulture (we'll use tr-TR) - - RunOnDedicatedThread(() => - { - Utf8String ustr = u8("i\u0131\u0130Ii\u0131\u0130I"); // U+0131 = 'ı' LATIN SMALL LETTER DOTLESS I - - CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo("tr-TR"); - - Assert.Equal(ustr[0..6].GetHashCode(StringComparison.CurrentCulture), ustr[6..12].GetHashCode(StringComparison.CurrentCulture)); - Assert.NotEqual(ustr[0..1].GetHashCode(StringComparison.CurrentCulture), ustr[1..3].GetHashCode(StringComparison.CurrentCulture)); - Assert.Equal(Utf8String.Empty.GetHashCode(StringComparison.CurrentCulture), ustr[^0..].GetHashCode(StringComparison.CurrentCulture)); - }); - - // CurrentCultureIgnoreCase (we'll use tr-TR) - - RunOnDedicatedThread(() => - { - Utf8String ustr = u8("i\u0131\u0130Ii\u0131\u0130I"); - - CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo("tr-TR"); - - Assert.Equal(ustr[0..6].GetHashCode(StringComparison.CurrentCultureIgnoreCase), ustr[6..12].GetHashCode(StringComparison.CurrentCultureIgnoreCase)); - Assert.NotEqual(ustr[0..1].GetHashCode(StringComparison.CurrentCultureIgnoreCase), ustr[1..3].GetHashCode(StringComparison.CurrentCultureIgnoreCase)); // 'i' shouldn't match 'ı' - Assert.Equal(ustr[0..1].GetHashCode(StringComparison.CurrentCultureIgnoreCase), ustr[3..5].GetHashCode(StringComparison.CurrentCultureIgnoreCase)); // 'i' should match 'İ' - Assert.NotEqual(ustr[0..1].GetHashCode(StringComparison.CurrentCultureIgnoreCase), ustr[5..6].GetHashCode(StringComparison.CurrentCultureIgnoreCase)); // 'i' shouldn't match 'I' - Assert.Equal(Utf8String.Empty.GetHashCode(StringComparison.CurrentCultureIgnoreCase), ustr[^0..].GetHashCode(StringComparison.CurrentCultureIgnoreCase)); - }); - } - - [Fact] - public static void GetPinnableReference_CalledMultipleTimes_ReturnsSameValue() - { - var utf8 = u8("Hello!"); - - fixed (byte* pA = utf8) - fixed (byte* pB = utf8) - { - Assert.True(pA == pB); - } - } - - [Fact] - public static void GetPinnableReference_Empty() - { - fixed (byte* pStr = Utf8String.Empty) - { - Assert.True(pStr != null); - Assert.Equal((byte)0, *pStr); // should point to null terminator - } - } - - [Fact] - public static void GetPinnableReference_NotEmpty() - { - fixed (byte* pStr = u8("Hello!")) - { - Assert.True(pStr != null); - - Assert.Equal((byte)'H', pStr[0]); - Assert.Equal((byte)'e', pStr[1]); - Assert.Equal((byte)'l', pStr[2]); - Assert.Equal((byte)'l', pStr[3]); - Assert.Equal((byte)'o', pStr[4]); - Assert.Equal((byte)'!', pStr[5]); - Assert.Equal((byte)'\0', pStr[6]); - } - } - - [Theory] - [InlineData(null, true)] - [InlineData("", true)] - [InlineData("\r\n", false)] - [InlineData("not empty", false)] - public static void IsNullOrEmpty(string value, bool expectedIsNullOrEmpty) - { - Assert.Equal(expectedIsNullOrEmpty, Utf8String.IsNullOrEmpty(u8(value))); - } - - [Theory] - [InlineData(null, true)] - [InlineData("", true)] - [InlineData(" \u2028\u2029\t\v", true)] - [InlineData(" x\r\n", false)] - [InlineData("\r\nhello\r\n", false)] - [InlineData("\r\n\0\r\n", false)] - [InlineData("\r\n\r\n", true)] - public static void IsNullOrWhiteSpace(string input, bool expected) - { - Assert.Equal(expected, Utf8String.IsNullOrWhiteSpace(u8(input))); - } - - [Fact] - public static void ToByteArray_Empty() - { -#if NETFRAMEWORK - // An empty Span.ToArray doesn't return Array.Empty on netfx - Assert.Equal(Array.Empty(), Utf8String.Empty.ToByteArray()); -#else - Assert.Same(Array.Empty(), Utf8String.Empty.ToByteArray()); -#endif - } - - [Fact] - public static void ToByteArray_NotEmpty() - { - Assert.Equal(new byte[] { (byte)'H', (byte)'i' }, u8("Hi").ToByteArray()); - } - - [Fact] - public static void ToCharArray_NotEmpty() - { - Assert.Equal("Hi".ToCharArray(), u8("Hi").ToCharArray()); - } - - [Fact] - public static void ToCharArray_Empty() - { - Assert.Same(Array.Empty(), Utf8String.Empty.ToCharArray()); - } - - [Theory] - [InlineData("")] - [InlineData("Hello!")] - public static void ToString_ReturnsUtf16(string value) - { - Assert.Equal(value, u8(value).ToString()); - } - - [Theory] - [InlineData("Hello", "6..")] - [InlineData("Hello", "3..7")] - [InlineData("Hello", "2..1")] - [InlineData("Hello", "^10..")] - public static void Indexer_Range_ArgOutOfRange_Throws(string strAsUtf16, string rangeAsString) - { - Utf8String utf8String = u8(strAsUtf16); - Range range = ParseRangeExpr(rangeAsString); - - Assert.Throws(() => utf8String[range]); - } - - [Fact] - public static void Indexer_Range_Success() - { - Utf8String utf8String = u8("Hello\u0800world."); - - Assert.Equal(u8("Hello"), utf8String[..5]); - Assert.Equal(u8("world."), utf8String[^6..]); - Assert.Equal(u8("o\u0800w"), utf8String[4..9]); - - Assert.Same(utf8String, utf8String[..]); // don't allocate new instance if slicing to entire string - Assert.Same(Utf8String.Empty, utf8String[1..1]); // don't allocare new zero-length string instane - Assert.Same(Utf8String.Empty, utf8String[6..6]); // ok to have a zero-length slice within a multi-byte sequence - } - - [Fact] - public static void Indexer_Range_TriesToSplitMultiByteSequence_Throws() - { - Utf8String utf8String = u8("Hello\u0800world."); - - Assert.Throws(() => utf8String[..6]); - Assert.Throws(() => utf8String[6..]); - Assert.Throws(() => utf8String[7..8]); - } - } -} diff --git a/src/libraries/System.Utf8String.Experimental/tests/System/Utf8TestUtilities.cs b/src/libraries/System.Utf8String.Experimental/tests/System/Utf8TestUtilities.cs deleted file mode 100644 index 0160d327c8c00..0000000000000 --- a/src/libraries/System.Utf8String.Experimental/tests/System/Utf8TestUtilities.cs +++ /dev/null @@ -1,208 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Globalization; -using System.IO; -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.ExceptionServices; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading; -using Xunit; - -namespace System.Tests -{ - public static class Utf8TestUtilities - { - private static readonly Lazy> _utf8StringFactory = CreateUtf8StringFactory(); - - private static Lazy> CreateUtf8StringFactory() - { - return new Lazy>(() => - { - MethodInfo fastAllocateMethod = typeof(Utf8String).GetMethod("FastAllocate", BindingFlags.NonPublic | BindingFlags.Static, null, new[] { typeof(int) }, null); - Assert.NotNull(fastAllocateMethod); - return (Func)fastAllocateMethod.CreateDelegate(typeof(Func)); - }); - } - - public unsafe static bool IsNull(this Utf8Span span) - { - return Unsafe.AreSame(ref Unsafe.AsRef(null), ref MemoryMarshal.GetReference(span.Bytes)); - } - - /// - /// Parses an expression of the form "a..b" and returns a . - /// - public static Range ParseRangeExpr(string expression) => ParseRangeExpr(expression.AsSpan()); - - /// - /// Parses an expression of the form "a..b" and returns a . - /// - public static Range ParseRangeExpr(ReadOnlySpan expression) - { - int idxOfDots = expression.IndexOf("..".AsSpan(), StringComparison.Ordinal); - if (idxOfDots < 0) - { - goto Error; - } - - ReadOnlySpan firstPart = expression[..idxOfDots].Trim(); - Index firstIndex = Index.Start; - - if (!firstPart.IsWhiteSpace()) - { - bool fromEnd = false; - - if (!firstPart.IsEmpty && firstPart[0] == '^') - { - fromEnd = true; - firstPart = firstPart[1..]; - } - - if (!int.TryParse(firstPart.ToString(), NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite, CultureInfo.InvariantCulture, out int startIndex)) - { - goto Error; - } - - firstIndex = new Index(startIndex, fromEnd); - } - - ReadOnlySpan secondPart = expression[(idxOfDots + 2)..].Trim(); - Index secondIndex = Index.End; - - if (!secondPart.IsWhiteSpace()) - { - bool fromEnd = false; - - if (!secondPart.IsEmpty && secondPart[0] == '^') - { - fromEnd = true; - secondPart = secondPart[1..]; - } - - if (!int.TryParse(secondPart.ToString(), NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite, CultureInfo.InvariantCulture, out int endIndex)) - { - goto Error; - } - - secondIndex = new Index(endIndex, fromEnd); - } - - return new Range(firstIndex, secondIndex); - - Error: - throw new ArgumentException($"Range expression '{expression.ToString()}' is invalid."); - } - - public static void AssertRangesEqual(int originalLength, Range expected, Range actual) - { - Assert.Equal(expected, actual, new RangeEqualityComparer(originalLength)); - } - - /// - /// Runs this test on its own dedicated thread; allows for setting CurrentCulture and other thread-statics. - /// - /// - public static void RunOnDedicatedThread(Action testCode) - { - Assert.NotNull(testCode); - - ExceptionDispatchInfo edi = default; - Thread newThread = new Thread(() => - { - try - { - testCode(); - } - catch (Exception ex) - { - edi = ExceptionDispatchInfo.Capture(ex); - } - }); - - newThread.Start(); - newThread.Join(); - - if (edi != null) - { - edi.Throw(); - } - } - - /// - /// Mimics returning a literal instance. - /// - public static Utf8String u8(string str) - { - if (str is null) - { - return null; - } - else if (str.Length == 0) - { - return Utf8String.Empty; - } - - // First, transcode UTF-16 to UTF-8. We use direct by-scalar transcoding here - // because we have good reference implementation tests for this and it'll help - // catch any errors we introduce to our bulk transcoding implementations. - - MemoryStream memStream = new MemoryStream(); - - byte[] utf8Bytes = new byte[4]; // 4 UTF-8 code units is the largest any scalar value can be encoded as - - int index = 0; - while (index < str.Length) - { - if (Rune.TryGetRuneAt(str, index, out Rune value) && value.TryEncodeToUtf8(utf8Bytes, out int bytesWritten)) - { - memStream.Write(utf8Bytes, 0, bytesWritten); - index += value.Utf16SequenceLength; - } - else - { - throw new ArgumentException($"String '{str}' is not a well-formed UTF-16 string."); - } - } - - Assert.True(memStream.TryGetBuffer(out ArraySegment buffer)); - - // Now allocate a UTF-8 string instance and set this as the contents. - - return Utf8String.UnsafeCreateWithoutValidation(buffer); - } - - public unsafe static Range GetRangeOfSubspan(ReadOnlySpan outerSpan, ReadOnlySpan innerSpan) - { - ulong byteOffset = (ulong)(void*)Unsafe.ByteOffset(ref MemoryMarshal.GetReference(outerSpan), ref MemoryMarshal.GetReference(innerSpan)); - ulong elementOffset = byteOffset / (uint)Unsafe.SizeOf(); - - checked - { - int elementOffsetAsInt = (int)elementOffset; - Range retVal = elementOffsetAsInt..(elementOffsetAsInt + innerSpan.Length); - - _ = outerSpan[retVal]; // call the real slice logic to make sure we're really within the outer span - return retVal; - } - } - - public static Range GetRangeOfSubspan(Utf8Span outerSpan, Utf8Span innerSpan) - { - return GetRangeOfSubspan(outerSpan.Bytes, innerSpan.Bytes); - } - - public static bool IsEmpty(this Range range, int length) - { - (_, int actualLength) = range.GetOffsetAndLength(length); - return (actualLength == 0); - } - - public static bool IsTryFindSupported(StringComparison comparison) => - !PlatformDetection.IsNetFramework || - comparison == StringComparison.Ordinal || - comparison == StringComparison.OrdinalIgnoreCase; - } -} diff --git a/src/libraries/System.Utf8String.Experimental/tests/Xunit/SpanAssert.cs b/src/libraries/System.Utf8String.Experimental/tests/Xunit/SpanAssert.cs deleted file mode 100644 index db7fe744d2532..0000000000000 --- a/src/libraries/System.Utf8String.Experimental/tests/Xunit/SpanAssert.cs +++ /dev/null @@ -1,35 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Collections.Generic; - -namespace Xunit -{ - public static class SpanAssert - { - public static void Equal(ReadOnlySpan a, ReadOnlySpan b, IEqualityComparer comparer = null) where T : IEquatable - { - if (comparer is null) - { - Assert.Equal(a.ToArray(), b.ToArray()); - } - else - { - Assert.Equal(a.ToArray(), b.ToArray(), comparer); - } - } - - public static void Equal(Span a, Span b, IEqualityComparer comparer = null) where T : IEquatable - { - if (comparer is null) - { - Assert.Equal(a.ToArray(), b.ToArray()); - } - else - { - Assert.Equal(a.ToArray(), b.ToArray(), comparer); - } - } - } -} diff --git a/src/libraries/pkg/test/packageSettings/System.Utf8String.Experimental/net/DisableVerifyClosure.targets b/src/libraries/pkg/test/packageSettings/System.Utf8String.Experimental/net/DisableVerifyClosure.targets deleted file mode 100644 index a5776c4391448..0000000000000 --- a/src/libraries/pkg/test/packageSettings/System.Utf8String.Experimental/net/DisableVerifyClosure.targets +++ /dev/null @@ -1,7 +0,0 @@ - - - - false - - \ No newline at end of file diff --git a/src/libraries/pkg/test/packageSettings/System.Utf8String.Experimental/netcoreapp/DisableVerifyClosure.targets b/src/libraries/pkg/test/packageSettings/System.Utf8String.Experimental/netcoreapp/DisableVerifyClosure.targets deleted file mode 100644 index a5776c4391448..0000000000000 --- a/src/libraries/pkg/test/packageSettings/System.Utf8String.Experimental/netcoreapp/DisableVerifyClosure.targets +++ /dev/null @@ -1,7 +0,0 @@ - - - - false - - \ No newline at end of file diff --git a/src/mono/netcore/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/mono/netcore/System.Private.CoreLib/System.Private.CoreLib.csproj index 481833215299b..8546ffcaf5f13 100644 --- a/src/mono/netcore/System.Private.CoreLib/System.Private.CoreLib.csproj +++ b/src/mono/netcore/System.Private.CoreLib/System.Private.CoreLib.csproj @@ -174,7 +174,6 @@ - @@ -250,7 +249,6 @@ - diff --git a/src/mono/netcore/System.Private.CoreLib/src/System/Text/Utf8Span.cs b/src/mono/netcore/System.Private.CoreLib/src/System/Text/Utf8Span.cs deleted file mode 100644 index b3ffff505534b..0000000000000 --- a/src/mono/netcore/System.Private.CoreLib/src/System/Text/Utf8Span.cs +++ /dev/null @@ -1,99 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.ComponentModel; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace System.Text -{ - [StructLayout(LayoutKind.Auto)] - public readonly ref partial struct Utf8Span - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Utf8Span(Utf8String? value) - { - throw new PlatformNotSupportedException(); - } - - public ReadOnlySpan Bytes { get; } - - public static Utf8Span Empty => default; - - public bool IsEmpty => throw new PlatformNotSupportedException(); - - public int Length => throw new PlatformNotSupportedException(); - - public Utf8Span this[Range range] - { - get - { - throw new PlatformNotSupportedException(); - } - } - - public bool IsEmptyOrWhiteSpace() => throw new PlatformNotSupportedException(); - - [Obsolete("Equals(object) on Utf8Span will always throw an exception. Use Equals(Utf8Span) or operator == instead.")] - [EditorBrowsable(EditorBrowsableState.Never)] -#pragma warning disable 0809 // Obsolete member 'Utf8Span.Equals(object)' overrides non-obsolete member 'object.Equals(object)' - public override bool Equals(object? obj) -#pragma warning restore 0809 - { - throw new NotSupportedException(SR.Utf8Span_CannotCallEqualsObject); - } - - public bool Equals(Utf8Span other) => throw new PlatformNotSupportedException(); - - public bool Equals(Utf8Span other, StringComparison comparison) => throw new PlatformNotSupportedException(); - - public static bool Equals(Utf8Span left, Utf8Span right) => throw new PlatformNotSupportedException(); - - public static bool Equals(Utf8Span left, Utf8Span right, StringComparison comparison) - { - throw new PlatformNotSupportedException(); - } - - public override int GetHashCode() - { - throw new PlatformNotSupportedException(); - } - - public int GetHashCode(StringComparison comparison) - { - throw new PlatformNotSupportedException(); - } - - public bool IsAscii() - { - throw new PlatformNotSupportedException(); - } - - public bool IsNormalized(NormalizationForm normalizationForm = NormalizationForm.FormC) - { - throw new PlatformNotSupportedException(); - } - - [EditorBrowsable(EditorBrowsableState.Never)] - public ref readonly byte GetPinnableReference() - { - throw new PlatformNotSupportedException(); - } - - public override string ToString() - { - throw new PlatformNotSupportedException(); - } - - public Utf8String ToUtf8String() - { - throw new PlatformNotSupportedException(); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Utf8Span UnsafeCreateWithoutValidation(ReadOnlySpan buffer) - { - throw new PlatformNotSupportedException(); - } - } -} diff --git a/src/mono/netcore/System.Private.CoreLib/src/System/Utf8String.cs b/src/mono/netcore/System.Private.CoreLib/src/System/Utf8String.cs deleted file mode 100644 index 3299ccd09eb9e..0000000000000 --- a/src/mono/netcore/System.Private.CoreLib/src/System/Utf8String.cs +++ /dev/null @@ -1,101 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.ComponentModel; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.CompilerServices; -using System.Text; - -namespace System -{ - /// - /// Represents an immutable string of UTF-8 code units. - /// - public sealed partial class Utf8String : IComparable, IEquatable - { -#pragma warning disable CS8618 - public static readonly Utf8String Empty; -#pragma warning restore CS8618 - - public static bool operator ==(Utf8String? left, Utf8String? right) => throw new PlatformNotSupportedException(); - public static bool operator !=(Utf8String? left, Utf8String? right) => throw new PlatformNotSupportedException(); - public static implicit operator Utf8Span(Utf8String? value) => throw new PlatformNotSupportedException(); - - public int Length => throw new PlatformNotSupportedException(); - public Utf8String this[Range range] - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - throw new PlatformNotSupportedException(); - } - } - - public int CompareTo(Utf8String? other) - { - throw new PlatformNotSupportedException(); - } - - public int CompareTo(Utf8String? other, StringComparison comparison) - { - throw new PlatformNotSupportedException(); - } - - public override bool Equals(object? obj) - { - throw new PlatformNotSupportedException(); - } - - public bool Equals(Utf8String? value) - { - throw new PlatformNotSupportedException(); - } - - public bool Equals(Utf8String? value, StringComparison comparison) => throw new PlatformNotSupportedException(); - - public static bool Equals(Utf8String? left, Utf8String? right) - { - throw new PlatformNotSupportedException(); - } - - public static bool Equals(Utf8String? a, Utf8String? b, StringComparison comparison) - { - throw new PlatformNotSupportedException(); - } - - public override int GetHashCode() - { - throw new PlatformNotSupportedException(); - } - - public int GetHashCode(StringComparison comparison) - { - throw new PlatformNotSupportedException(); - } - - [EditorBrowsable(EditorBrowsableState.Never)] // for compiler use only - public ref readonly byte GetPinnableReference() => throw new PlatformNotSupportedException(); - - public bool IsAscii() - { - throw new PlatformNotSupportedException(); - } - - public static bool IsNullOrEmpty([NotNullWhen(false)] Utf8String? value) - { - throw new PlatformNotSupportedException(); - } - - public static bool IsNullOrWhiteSpace([NotNullWhen(false)] Utf8String? value) - { - throw new PlatformNotSupportedException(); - } - - public byte[] ToByteArray() => throw new PlatformNotSupportedException(); - - public override string ToString() - { - throw new PlatformNotSupportedException(); - } - } -}