//
// Created by Eugeny Grishul
//
// See license at http://bamelg.com/license.txt
//
using System.Runtime;
using System.Text;
namespace System {
public sealed partial class Utf32String {
public const Utf32String Empty = "";
public readonly uint Length;
public readonly uint Hash;
public uint ByteLength { get { return Length * sizeof( this[0] ); } }
public bool IsNullOrEmpty { get { return this == null || Length == 0; } }
private Utf32String() {
}
private Utf32String( uint length ) {
extra {
return sizeof( uint ) * ( length + 1 );
}
body {
Length = length;
}
}
public Utf32String( uint source, uint length ) {
extra {
return sizeof( uint ) * ( length + 1 );
}
body {
var chars = GetChars();
Length = length;
Memory.Fill32( chars, source, length );
chars[Length] = '\0';
UpdateHash();
}
}
public Utf32String( Utf32String source ) {
extra {
return sizeof( uint ) * ( source.Length + 1 );
}
body {
var chars = GetChars();
Length = source.Length;
Hash = source.Hash;
Memory.Copy( chars, source.GetChars(), ByteLength + sizeof( GetChars()[0] ) ); // copy with '\0'
}
}
public static Utf32String Concat( vararg TypedReference values ) {
using( var builder = StringBuilder.CachedBuilders.PopScoped() ) {
builder.Value.Concat( vararg( values, values.Length ) );
return builder.Value.ToUtf32String();
}
}
public static Utf32String operator +( Utf32String left, TypedReference right ) { return Concat( left, right ); }
public static Utf32String operator +( TypedReference left, Utf32String right ) { return Concat( left, right ); }
private void UpdateHash() { *cast<uint*>( bitcast<byte*>( this ) + memberinfo( Hash ).ByteOffset ) = CUtf32String.ComputeHashCode( GetChars(), Length ); }
public override uint GetHashCode() { return Hash; }
internal uint* GetChars() { return this != null ? ( uint* )( bitcast<byte*>( this ) + sizeof( thistype ) ) : null; }
public uint this[int index] { get { System.Diagnostics.Debug.Assert( ( uint ) index < Length ); return GetChars()[index]; } }
public uint this[uint index] { get { System.Diagnostics.Debug.Assert( index < Length ); return GetChars()[index]; } }
public static bool operator ==( Utf32String left, Utf32String right ) {
if( cast<RuntimeObjectBase>( left ) == cast<RuntimeObjectBase>( right ) ) return true;
if( ( left == null ) | ( right == null ) ) return false;
if( left.Hash != right.Hash ) return false;
if( left.Length != right.Length ) return false;
return Memory.Compare( left.GetChars(), right.GetChars(), ( int ) left.ByteLength );
}
public static bool operator !=( Utf32String left, Utf32String right ) {
return !( left == right );
}
public static Utf32String operator +( Utf32String left, Utf32String right ) {
if( left == null ) return right;
if( right == null ) return left;
var resultLength = left.Length + right.Length;
var result = new Utf32String( resultLength );
var chars = result.GetChars();
Memory.Copy( chars, left.GetChars(), left.ByteLength );
Memory.Copy( chars + left.Length, right.GetChars(), right.ByteLength + sizeof( right.GetChars()[0] ) );
result.UpdateHash();
return result;
}
public static Utf32String Format( [VerifyFormatString] Utf16String format, vararg TypedReference parameters ) {
using( var builder = StringBuilder.CachedBuilders.PopScoped() ) {
builder.Value.AppendFormat( format, vararg( parameters, parameters.Length ) );
return builder.Value.ToUtf32String();
}
}
/// @ Conversion from SBCS
public static explicit operator Utf32String( SbcsString value ) { return FromSBCS( value ); }
public static explicit operator Utf32String( CString value ) { return FromSBCS( value ); }
public static explicit operator Utf32String( CStringSpan value ) { return FromSBCS( value ); }
public static Utf32String FromSBCS( CString value ) { return FromSBCS( Environment.DefaultCodePage, value ); }
public static Utf32String FromSBCS( CodePageID codePage, CString value ) { return FromSBCS( codePage, value.GetChars(), 0 ); }
public static Utf32String FromSBCS( CStringSpan value ) { return FromSBCS( Environment.DefaultCodePage, value ); }
public static Utf32String FromSBCS( CodePageID codePage, CStringSpan value ) { return FromSBCS( codePage, value.GetChars(), value.Length ); }
public static Utf32String FromSBCS( SbcsString value ) {
if( value == null ) return null;
if( value.Length == 0 ) return "";
return FromSBCS( value.CodePage, value.GetChars(), value.Length );
}
public static Utf32String FromSBCS( CodePageID codePage, byte* memory, uint limitBytes = 0 ) {
if( memory == null ) return null;
if( memory[0] == 0 & limitBytes == 0 ) return "";
if( limitBytes == 0 )
limitBytes = CString.ComputeLength( memory );
var result = new Utf32String( limitBytes );
var chars = result.GetChars();
var table = Encoding.GetConversionTable( codePage );
for( var i = 0U; i < limitBytes; ++i )
chars[i] = table[memory[i]];
result.UpdateHash();
return result;
}
/// @}
/// @ Conversion from UTF8
public static explicit operator Utf32String( Utf8String value ) { return FromUtf8( value ); }
public static explicit operator Utf32String( CUtf8String value ) { return FromUtf8( value ); }
public static explicit operator Utf32String( CUtf8StringSpan value ) { return FromUtf8( value ); }
public static Utf32String FromUtf8( CUtf8String value ) { return FromUtf8( value.GetChars(), 0 ); }
public static Utf32String FromUtf8( CUtf8StringSpan value ) { return FromUtf8( value.GetChars(), value.ByteLength ); }
public static Utf32String FromUtf8( Utf8String value ) {
if( value == null ) return null;
if( value.Length == 0 ) return "";
return FromUtf8( value.GetChars(), value.ByteLength );
}
public static Utf32String FromUtf8( byte* memory, uint limitBytes = 0 ) {
if( memory == null ) return null;
if( memory[0] == 0 & limitBytes == 0 ) return "";
uint charsCount;
Unicode.GetUtf8ByteCountInUtf32( memory, limitBytes, charsCount );
var result = new Utf32String( charsCount );
var chars = result.GetChars();
Unicode.ConvertUtf8CharactersToUtf32( chars, memory, limitBytes );
chars[charsCount] = '\0';
result.UpdateHash();
return result;
}
/// @}
/// @ Conversion from UTF16
public static explicit operator Utf32String( Utf16String value ) { return FromUtf16( value ); }
public static explicit operator Utf32String( CUtf16String value ) { return FromUtf16( value ); }
public static explicit operator Utf32String( CUtf16StringSpan value ) { return FromUtf16( value ); }
public static Utf32String FromUtf16( CUtf16String value ) { return FromUtf16( value.GetChars(), 0 ); }
public static Utf32String FromUtf16( CUtf16StringSpan value ) { return FromUtf16( value.GetChars(), value.Length ); }
public static Utf32String FromUtf16( Utf16String value ) {
if( value == null ) return null;
if( value.Length == 0 ) return "";
return FromUtf16( value.GetChars(), value.Length );
}
public static Utf32String FromUtf16( char* memory, uint limitChars ) {
if( memory == null ) return null;
if( memory[0] == '\0' & limitChars == 0 ) return "";
uint charsCount;
Unicode.GetUtf16ByteCountInUtf32( memory, limitChars, charsCount );
var result = new Utf32String( charsCount );
var chars = result.GetChars();
Unicode.ConvertUtf16CharactersToUtf32( chars, memory, limitChars );
chars[charsCount] = '\0';
result.UpdateHash();
return result;
}
/// @}
/// @ Conversion from UTF32
public static explicit operator Utf32String( CUtf32String value ) { return FromUtf32( value ); }
public static explicit operator Utf32String( CUtf32StringSpan value ) { return FromUtf32( value ); }
public static Utf32String FromUtf32( CUtf32String value ) { return FromUtf32( value.GetChars(), 0 ); }
public static Utf32String FromUtf32( CUtf32StringSpan value ) { return FromUtf32( value.GetChars(), value.Length ); }
public static Utf32String FromUtf32( uint* memory, uint limitChars = 0 ) {
if( memory == null ) return null;
if( memory[0] == 0 & limitChars == 0 ) return "";
if( limitChars == 0 )
limitChars = CUtf32String.ComputeLength( memory );
var result = new Utf32String( limitChars );
var resultChars = result.GetChars();
Memory.Copy( resultChars, memory, limitChars * sizeof( uint ) );
resultChars[limitChars] = '\0';
result.UpdateHash();
return result;
}
/// @}
public thistype ToUpper() {
if( IsNullOrEmpty ) return this;
using( var builder = StringBuilder.CachedBuilders.PopScoped() ) {
builder.Value.Append( this );
builder.Value.ToUpper();
return builder.Value.ToUtf32String();
}
}
public thistype ToLower() {
if( IsNullOrEmpty ) return this;
using( var builder = StringBuilder.CachedBuilders.PopScoped() ) {
builder.Value.Append( this );
builder.Value.ToLower();
return builder.Value.ToUtf32String();
}
}
public override string ToString() { return ( string ) this; }
public uint[] ToCharArray() {
var result = new[Length] uint;
Memory.Copy( &result[0], GetChars(), ByteLength );
return result;
}
public int IndexOf( thistype value ) {
return IndexOf( value, 0 );
}
public int IndexOf( thistype value, int startIndex ) {
if( !Assert.IsFalse( startIndex < 0 || ( uint ) startIndex >= Length || value == "" ) )
return -1;
for( var i = ( uint ) startIndex; i + value.Length < Length + 1; ++i ) {
if( this[i] == value[0] ) {
uint j;
for( j = 1; j < value.Length; ++j )
if( this[i + j] != value[j] )
break;
if( j == value.Length ) return ( int ) i;
}
}
return -1;
}
}
[PrimitiveType( Size = sizeof( uintptr ) )]
public partial struct CUtf32String {
public const thistype Null = bitcast<thistype>( ( uintptr ) 0 );
public bool IsNullOrEmpty { get { return GetChars() == null || GetChars()[0] == 0; } }
public CUtf32String( uint* location ) {
this = bitcast<thistype>( location );
}
public uint Length {
get { return ComputeLength( GetChars() ); }
}
public uint ByteLength {
get { return Length * 4; }
}
public uint Hash {
get { return GetHashCode(); }
}
public uint GetHashCode() { return GetHashAndByteLength( GetChars(), 0U ); }
public static bool operator ==( CUtf32String left, CUtf32String right ) { return AreEqual( left, right ); }
public static bool operator !=( CUtf32String left, CUtf32String right ) { return !AreEqual( left, right ); }
public static void Concatenate( CUtf32String destinationString, CUtf32String sourceString ) {
var destination = destinationString.GetChars();
var source = sourceString.GetChars();
var length = destinationString.Length;
var length2 = sourceString.Length;
for( var i = 0U; i <= length2; ++i )
destination[i + length] = source[i];
}
public static bool AreEqual( CUtf32String leftString, CUtf32String rightString ) {
var left = leftString.GetChars();
var right = rightString.GetChars();
if( ( left == null ) & ( right == null ) ) return true;
if( ( left == null ) | ( right == null ) ) return false;
while( *left != '\0' && ( *left == *right ) ) {
++left;
++right;
}
return ( *left - *right ) == 0;
}
public static bool AreEqual( CUtf32String leftString, CUtf32String rightString, int length ) {
var left = leftString.GetChars();
var right = rightString.GetChars();
if( ( left == null ) & ( right == null ) ) return true;
if( ( left == null ) | ( right == null ) ) return false;
int n = length;
while( --n >= 0 && *left == *right++ )
if( *left++ == '\0' )
return true;
return n < 0 ? true : *left - *--right == 0;
}
public bool StartsWith( CUtf32String prefix ) {
var left = GetChars();
var right = prefix.GetChars();
if( ( left == null ) | ( right == null ) ) return false;
while( *left != '\0' && ( *left == *right ) ) {
++left;
++right;
}
return *right == 0;
}
static void Copy( CUtf32String leftString, CUtf32String rightString ) {
var left = leftString.GetChars();
var right = rightString.GetChars();
while( ( *left++ = *right++ ) != 0 )
continue;
}
static void Copy( CUtf32String leftString, CUtf32String rightString, int length ) {
var left = leftString.GetChars();
var right = rightString.GetChars();
while( length != 0 && ( *left++ = *right++ ) != 0 )
--length;
if( length == 0 ) *--left = ( char ) 0;
}
/// Dangerous operator. Result will correct while 'value' is alive.
public static implicit operator CUtf32String( Utf32String value ) { return new CUtf32String( value.GetChars() ); }
public uint* GetChars() { return bitcast<uint*>( this ); }
public uint this[int index] { get { return GetChars()[index]; } }
public uint this[uint index] { get { return GetChars()[index]; } }
public static uint ComputeLength( uint* chars ) {
if( chars == null ) return 0U;
var result = 0U;
while( *chars++ != 0 )
++result;
return result;
}
public static uint ComputeLength( uint* chars, uint limitLength ) {
if( chars == null ) return 0U;
var result = 0U;
while( *chars++ != 0 ) {
++result;
if( result >= limitLength ) break;
}
return result;
}
public static uint ComputeHashCode( uint* chars, uint length ) {
if( chars == null ) return 0U;
var result = 0U;
for( var i = 0U; i < length; ++i )
result = result * 41 + chars[i];
return result;
}
public static uint GetHashAndByteLength( uint* chars, uint& resultLength ) {
if( chars == null ) { resultLength = 0; return 0U; }
var result = 0U;
var length = 0U;
for( int i = 0; chars[i] != '\0'; ++i, ++length )
result = result * 41 + chars[i];
resultLength = length * sizeof( uint );
return result;
}
}
public partial struct CUtf32StringSpan {
public static readonly CUtf32StringSpan Null;
public bool IsNullOrEmpty { get { return Location == null || Length == 0; } }
public uint* Location;
public uint Length;
public uint ByteLength { get { return Length * sizeof( uint ); } }
public CUtf32StringSpan( uint* location, uint length ) { Location = location; Length = length; }
public uint GetHashCode() { return CUtf32String.ComputeHashCode( Location, Length ); }
public uint* GetChars() { return Location; }
public static bool AreEqual( CUtf32StringSpan& leftString, CUtf32StringSpan& rightString ) {
var left = leftString.Location;
var right = rightString.Location;
if( left == right && leftString.Length == rightString.Length ) return true;
if( ( left == null ) | ( right == null ) ) return false;
return Memory.Compare( left, right, ( int ) leftString.ByteLength );
}
public static bool operator ==( CUtf32StringSpan& left, CUtf32StringSpan& right ) { return AreEqual( left, right ); }
public static bool operator !=( CUtf32StringSpan& left, CUtf32StringSpan& right ) { return !AreEqual( left, right ); }
public static bool operator ==( Utf32String left, CUtf32StringSpan& right ) { return AreEqual( left, right ); }
public static bool operator !=( Utf32String left, CUtf32StringSpan& right ) { return !AreEqual( left, right ); }
public static bool operator ==( CUtf32StringSpan& left, Utf32String right ) { return AreEqual( left, right ); }
public static bool operator !=( CUtf32StringSpan& left, Utf32String right ) { return !AreEqual( left, right ); }
/// Dangerous operator. Result will correct while 'value' is alive.
public static implicit operator CUtf32StringSpan( Utf32String value ) { return value != null ? new CUtf32StringSpan( value.GetChars(), value.Length ) : CUtf32StringSpan.Null; }
public static implicit operator CUtf32StringSpan( CUtf32String value ) { return new CUtf32StringSpan( value.GetChars(), value.Length ); }
public bool StartsWith( CUtf32StringSpan value ) {
if( value == null || value.Length == 0 ) return false;
if( Length < value.Length ) return false;
return Memory.Compare( GetChars(), value.GetChars(), ( int ) value.ByteLength );
}
public bool EndsWith( CUtf32StringSpan value ) {
if( value == null || value.Length == 0 ) return false;
if( Length < value.Length ) return false;
return Memory.Compare( GetChars() + ( Length - value.Length ), value.GetChars(), ( int ) value.ByteLength );
}
public bool StartsWith( Utf32String value ) {
if( value == null || value.Length == 0 ) return false;
if( Length < value.Length ) return false;
return Memory.Compare( GetChars(), value.GetChars(), ( int ) value.ByteLength );
}
public bool EndsWith( Utf32String value ) {
if( value == null || value.Length == 0 ) return false;
if( Length < value.Length ) return false;
return Memory.Compare( GetChars() + ( Length - value.Length ), value.GetChars(), ( int ) value.ByteLength );
}
}
}