From 8879e98229f8384159c142e54c0bbbcb46a70d1b Mon Sep 17 00:00:00 2001 From: Marc Hernandez Date: Tue, 30 Apr 2024 12:18:33 -0700 Subject: [PATCH] Whitespace changes --- Helpers.cs | 54 +- Id.cs | 1232 ++++++++-------- Token.cs | 108 +- Utilities.Interop.cs | 46 +- Utilities.cs | 1700 ++++++++++----------- ar/AdaptiveArithmeticCompress.cs | 146 +- ar/AdaptiveArithmeticDecompress.cs | 134 +- ar/ArithmeticCoderBase.cs | 370 ++--- ar/ArithmeticCompress.cs | 254 ++-- ar/ArithmeticDecoder.cs | 304 ++-- ar/ArithmeticDecompress.cs | 198 +-- ar/ArithmeticEncoder.cs | 236 +-- ar/Arrays.cs | 80 +- ar/BitInputStream.cs | 240 +-- ar/BitOutputStream.cs | 190 +-- ar/CheckedFrequencyTable.cs | 256 ++-- ar/FlatFrequencyTable.cs | 290 ++-- ar/FrequencyTable.cs | 152 +- ar/PpmCompress.cs | 258 ++-- ar/PpmDecompress.cs | 244 ++-- ar/PpmModel.cs | 226 +-- ar/SimpleFrequencyTable.cs | 520 +++---- att/CanBeNullAttribute.cs | 12 +- att/NotNullAttribute.cs | 8 +- db/Act.cs | 192 +-- db/DB.cs | 442 +++--- db/Processor.cs | 244 ++-- db/System.cs | 616 ++++---- math/AngleSingle.cs | 868 +++++------ math/Pos.cs | 92 +- math/fn.cs | 208 +-- mod/Modules.cs | 4 +- net/Conn.cs | 390 ++--- net/NetMsg.cs | 206 +-- scr/Script.cs | 698 ++++----- ser/SerializableDictionary.cs | 332 ++--- ser/VersionFormatter.cs | 1354 ++++++++--------- ser/XmlFormatter.cs | 2188 ++++++++++++++-------------- time/Clock.cs | 104 +- time/Timer.cs | 754 +++++----- 40 files changed, 7975 insertions(+), 7975 deletions(-) diff --git a/Helpers.cs b/Helpers.cs index 3c5ee7b..7ed5537 100644 --- a/Helpers.cs +++ b/Helpers.cs @@ -1,8 +1,8 @@ - + /* * TODO: Need to verify types are correct when deserializing. -*/ - +*/ + using System; using System.Collections.Generic; using System.Linq; @@ -22,10 +22,10 @@ namespace lib { FileStream fs = new FileStream( filename, FileMode.Create, FileAccess.Write ); - XmlSerializer xs = new XmlSerializer( obj.GetType() ); - //MemoryStream memoryStream = new MemoryStream( StringToUTF8ByteArray( pXmlizedString ) ); - //XmlTextReader reader = new XmlTextReader( fs, Encoding.UTF8 ); - + XmlSerializer xs = new XmlSerializer( obj.GetType() ); + //MemoryStream memoryStream = new MemoryStream( StringToUTF8ByteArray( pXmlizedString ) ); + //XmlTextReader reader = new XmlTextReader( fs, Encoding.UTF8 ); + xs.Serialize( fs, obj ); } @@ -33,10 +33,10 @@ namespace lib { FileStream fs = new FileStream( filename, FileMode.Open, FileAccess.Read ); - XmlSerializer xs = new XmlSerializer( typeof( TType ) ); - //MemoryStream memoryStream = new MemoryStream( StringToUTF8ByteArray( pXmlizedString ) ); - //XmlTextReader reader = new XmlTextReader( fs, Encoding.UTF8 ); - + XmlSerializer xs = new XmlSerializer( typeof( TType ) ); + //MemoryStream memoryStream = new MemoryStream( StringToUTF8ByteArray( pXmlizedString ) ); + //XmlTextReader reader = new XmlTextReader( fs, Encoding.UTF8 ); + return xs.Deserialize( fs ); } @@ -72,10 +72,10 @@ namespace lib { XmlTextWriter xmlWriter = new XmlTextWriter( filename, null ); - xmlWriter.Formatting = Formatting.Indented; - - //xmlWriter.WriteStartDocument(); - + xmlWriter.Formatting = Formatting.Indented; + + //xmlWriter.WriteStartDocument(); + xmlWriter.WriteStartElement( "dictionary" ); Type[] types = dict.GetType().GetGenericArguments(); @@ -93,10 +93,10 @@ namespace lib xmlWriter.WriteEndElement(); } - xmlWriter.WriteEndElement(); - - //xmlWriter.WriteEndDocument(); - + xmlWriter.WriteEndElement(); + + //xmlWriter.WriteEndDocument(); + xmlWriter.Close(); } @@ -106,10 +106,10 @@ namespace lib XmlDocument doc = new XmlDocument(); - doc.Load( fs ); - - //CreateTypeFor() - + doc.Load( fs ); + + //CreateTypeFor() + XmlElement docElem = doc.DocumentElement; if( docElem.Name == "dictionary" ) @@ -125,10 +125,10 @@ namespace lib { XmlNodeList nodeList = docElem.ChildNodes; - object[] args = new object[ 1 ]; - - //fi.SetValue( newObj, obj ); - + object[] args = new object[ 1 ]; + + //fi.SetValue( newObj, obj ); + foreach( XmlElement node in nodeList ) { if( node.Name == "kvp" ) diff --git a/Id.cs b/Id.cs index 2172cdf..dd9495f 100644 --- a/Id.cs +++ b/Id.cs @@ -1,616 +1,616 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Runtime.InteropServices; -using System.Security; -using System.Text; -using System.Threading.Tasks; - -//using System.MemoryExtensions; - -namespace lib -{ - - - public struct Id: IComparable, IFormattable, IConvertible, IComparable, IEquatable - { - public const ulong Min = 0uL; - public const ulong Max = 18446744073709551615uL; - - static Random s_rand = new Random(); - - - // TODO PERF Make span versions of all these functions - - unsafe public static Id Generate() - { - var buf = new byte[8]; - - s_rand.NextBytes( buf ); - - var newId = BitConverter.ToUInt64(buf, 0); - - return new Id { m_value = newId }; - } - - ulong m_value; - - - public int CompareTo( object value ) - { - if( value == null ) - { - return 1; - } - if( value is ulong ) - { - ulong num = (ulong)value; - if( m_value < num ) - { - return -1; - } - if( m_value > num ) - { - return 1; - } - return 0; - } - throw new ArgumentException( "" ); - } - - public int CompareTo( ulong value ) - { - if( m_value < value ) - { - return -1; - } - if( m_value > value ) - { - return 1; - } - return 0; - } - - public override bool Equals( object obj ) - { - if( !( obj is ulong ) ) - { - return false; - } - return m_value == (ulong)obj; - } - - public bool Equals( ulong obj ) - { - return m_value == obj; - } - - public override int GetHashCode() - { - return (int)m_value ^ (int)( m_value >> 32 ); - } - - #region ToString - // - // Summary: - // Converts the numeric value of m_value instance to its equivalent string representation. - // - // Returns: - // The string representation of the value of m_value instance, consisting of a sequence - // of digits ranging from 0 to 9, without a sign or leading zeroes. - [SecuritySafeCritical] - - public override string ToString() - { - return m_value.ToString( null, NumberFormatInfo.CurrentInfo ); - } - - // - // Summary: - // Converts the numeric value of m_value instance to its equivalent string representation - // using the specified culture-specific format information. - // - // Parameters: - // provider: - // An object that supplies culture-specific formatting information. - // - // Returns: - // The string representation of the value of m_value instance as specified by provider. - [SecuritySafeCritical] - - public string ToString( IFormatProvider provider ) - { - return m_value.ToString( null, NumberFormatInfo.GetInstance( provider ) ); - } - - // - // Summary: - // Converts the numeric value of m_value instance to its equivalent string representation - // using the specified format. - // - // Parameters: - // format: - // A numeric format string. - // - // Returns: - // The string representation of the value of m_value instance as specified by format. - // - // Exceptions: - // T:System.FormatException: - // The format parameter is invalid. - [SecuritySafeCritical] - - public string ToString( string format ) - { - return m_value.ToString( format, NumberFormatInfo.CurrentInfo ); - } - - // - // Summary: - // Converts the numeric value of m_value instance to its equivalent string representation - // using the specified format and culture-specific format information. - // - // Parameters: - // format: - // A numeric format string. - // - // provider: - // An object that supplies culture-specific formatting information about m_value instance. - // - // Returns: - // The string representation of the value of m_value instance as specified by format - // and provider. - // - // Exceptions: - // T:System.FormatException: - // The format parameter is invalid. - [SecuritySafeCritical] - - public string ToString( string format, IFormatProvider provider ) - { - return m_value.ToString( format, NumberFormatInfo.GetInstance( provider ) ); - } - - #endregion - - #region Parse - // - // Summary: - // Converts the string representation of a number to its 64-bit unsigned integer - // equivalent. - // - // Parameters: - // s: - // A string that represents the number to convert. - // - // Returns: - // A 64-bit unsigned integer equivalent to the number contained in s. - // - // Exceptions: - // T:System.ArgumentNullException: - // The s parameter is null. - // - // T:System.FormatException: - // The s parameter is not in the correct format. - // - // T:System.OverflowException: - // The s parameter represents a number less than System.UInt64.MinValue or greater - // than System.UInt64.MaxValue. - - - public static ulong Parse( string s ) - { - - return ulong.Parse( s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo ); - } - - // - // Summary: - // Converts the string representation of a number in a specified style to its 64-bit - // unsigned integer equivalent. - // - // Parameters: - // s: - // A string that represents the number to convert. The string is interpreted by - // using the style specified by the style parameter. - // - // style: - // A bitwise combination of the enumeration values that specifies the permitted - // format of s. A typical value to specify is System.Globalization.NumberStyles.Integer. - // - // Returns: - // A 64-bit unsigned integer equivalent to the number specified in s. - // - // Exceptions: - // T:System.ArgumentNullException: - // The s parameter is null. - // - // T:System.ArgumentException: - // /// style is not a System.Globalization.NumberStyles value. -or-style is not - // a combination of System.Globalization.NumberStyles.AllowHexSpecifier and System.Globalization.NumberStyles.HexNumber - // values. - // - // T:System.FormatException: - // The s parameter is not in a format compliant with style. - // - // T:System.OverflowException: - // The s parameter represents a number less than System.UInt64.MinValue or greater - // than System.UInt64.MaxValue. -or-s includes non-zero, fractional digits. - - - public static ulong Parse( string s, NumberStyles style ) - { - return ulong.Parse( s, style, NumberFormatInfo.CurrentInfo ); - } - - // - // Summary: - // Converts the string representation of a number in a specified culture-specific - // format to its 64-bit unsigned integer equivalent. - // - // Parameters: - // s: - // A string that represents the number to convert. - // - // provider: - // An object that supplies culture-specific formatting information about s. - // - // Returns: - // A 64-bit unsigned integer equivalent to the number specified in s. - // - // Exceptions: - // T:System.ArgumentNullException: - // The s parameter is null. - // - // T:System.FormatException: - // The s parameter is not in the correct style. - // - // T:System.OverflowException: - // The s parameter represents a number less than System.UInt64.MinValue or greater - // than System.UInt64.MaxValue. - - - public static ulong Parse( string s, IFormatProvider provider ) - { - return ulong.Parse( s, NumberStyles.Integer, NumberFormatInfo.GetInstance( provider ) ); - } - - // - // Summary: - // Converts the string representation of a number in a specified style and culture-specific - // format to its 64-bit unsigned integer equivalent. - // - // Parameters: - // s: - // A string that represents the number to convert. The string is interpreted by - // using the style specified by the style parameter. - // - // style: - // A bitwise combination of enumeration values that indicates the style elements - // that can be present in s. A typical value to specify is System.Globalization.NumberStyles.Integer. - // - // provider: - // An object that supplies culture-specific formatting information about s. - // - // Returns: - // A 64-bit unsigned integer equivalent to the number specified in s. - // - // Exceptions: - // T:System.ArgumentNullException: - // The s parameter is null. - // - // T:System.ArgumentException: - // /// style is not a System.Globalization.NumberStyles value. -or-style is not - // a combination of System.Globalization.NumberStyles.AllowHexSpecifier and System.Globalization.NumberStyles.HexNumber - // values. - // - // T:System.FormatException: - // The s parameter is not in a format compliant with style. - // - // T:System.OverflowException: - // The s parameter represents a number less than System.UInt64.MinValue or greater - // than System.UInt64.MaxValue. -or-s includes non-zero, fractional digits. - - - public static ulong Parse( string s, NumberStyles style, IFormatProvider provider ) - { - return ulong.Parse( s, style, NumberFormatInfo.GetInstance( provider ) ); - } - - // - // Summary: - // Tries to convert the string representation of a number to its 64-bit unsigned - // integer equivalent. A return value indicates whether the conversion succeeded - // or failed. - // - // Parameters: - // s: - // A string that represents the number to convert. - // - // result: - // When m_value method returns, contains the 64-bit unsigned integer value that is - // equivalent to the number contained in s, if the conversion succeeded, or zero - // if the conversion failed. The conversion fails if the s parameter is null, is - // not of the correct format, or represents a number less than System.UInt64.MinValue - // or greater than System.UInt64.MaxValue. m_value parameter is passed uninitialized. - // - // Returns: - // true if s was converted successfully; otherwise, false. - - - public static bool TryParse( string s, out ulong result ) - { - return ulong.TryParse( s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result ); - } - - // - // Summary: - // Tries to convert the string representation of a number in a specified style and - // culture-specific format to its 64-bit unsigned integer equivalent. A return value - // indicates whether the conversion succeeded or failed. - // - // Parameters: - // s: - // A string that represents the number to convert. The string is interpreted by - // using the style specified by the style parameter. - // - // style: - // A bitwise combination of enumeration values that indicates the permitted format - // of s. A typical value to specify is System.Globalization.NumberStyles.Integer. - // - // provider: - // An object that supplies culture-specific formatting information about s. - // - // result: - // When m_value method returns, contains the 64-bit unsigned integer value equivalent - // to the number contained in s, if the conversion succeeded, or zero if the conversion - // failed. The conversion fails if the s parameter is null, is not in a format compliant - // with style, or represents a number less than System.UInt64.MinValue or greater - // than System.UInt64.MaxValue. m_value parameter is passed uninitialized. - // - // Returns: - // true if s was converted successfully; otherwise, false. - // - // Exceptions: - // T:System.ArgumentException: - // /// style is not a System.Globalization.NumberStyles value. -or-style is not - // a combination of System.Globalization.NumberStyles.AllowHexSpecifier and System.Globalization.NumberStyles.HexNumber - // values. - - - public static bool TryParse( string s, NumberStyles style, IFormatProvider provider, out ulong result ) - { - return ulong.TryParse( s, style, NumberFormatInfo.GetInstance( provider ), out result ); - } - - #endregion - - - // - // Summary: - // Returns the System.TypeCode for value type System.UInt64. - // - // Returns: - // The enumerated constant, System.TypeCode.UInt64. - public TypeCode GetTypeCode() - { - return TypeCode.UInt64; - } - - #region Converters - // - // Summary: - // For a description of m_value member, see System.IConvertible.ToBoolean(System.IFormatProvider). - // - // Parameters: - // provider: - // m_value parameter is ignored. - // - // Returns: - // true if the value of the current instance is not zero; otherwise, false. - - bool IConvertible.ToBoolean( IFormatProvider provider ) - { - return Convert.ToBoolean( m_value ); - } - - // - // Summary: - // For a description of m_value member, see System.IConvertible.ToChar(System.IFormatProvider). - // - // Parameters: - // provider: - // m_value parameter is ignored. - // - // Returns: - // The value of the current instance, converted to a System.Char. - - char IConvertible.ToChar( IFormatProvider provider ) - { - return Convert.ToChar( m_value ); - } - - // - // Summary: - // For a description of m_value member, see System.IConvertible.ToSByte(System.IFormatProvider). - // - // Parameters: - // provider: - // m_value parameter is ignored. - // - // Returns: - // The value of the current instance, converted to an System.SByte. - - sbyte IConvertible.ToSByte( IFormatProvider provider ) - { - return Convert.ToSByte( m_value ); - } - - // - // Summary: - // For a description of m_value member, see System.IConvertible.ToByte(System.IFormatProvider). - // - // Parameters: - // provider: - // m_value parameter is ignored. - // - // Returns: - // The value of the current instance, converted to a System.Byte. - - byte IConvertible.ToByte( IFormatProvider provider ) - { - return Convert.ToByte( m_value ); - } - - // - // Summary: - // For a description of m_value member, see System.IConvertible.ToInt16(System.IFormatProvider). - // - // Parameters: - // provider: - // m_value parameter is ignored. - // - // Returns: - // The value of the current instance, converted to an System.Int16. - - short IConvertible.ToInt16( IFormatProvider provider ) - { - return Convert.ToInt16( m_value ); - } - - // - // Summary: - // For a description of m_value member, see System.IConvertible.ToUInt16(System.IFormatProvider). - // - // Parameters: - // provider: - // m_value parameter is ignored. - // - // Returns: - // The value of the current instance, converted to a System.UInt16. - - ushort IConvertible.ToUInt16( IFormatProvider provider ) - { - return Convert.ToUInt16( m_value ); - } - - // - // Summary: - // For a description of m_value member, see System.IConvertible.ToInt32(System.IFormatProvider). - // - // Parameters: - // provider: - // m_value parameter is ignored. - // - // Returns: - // The value of the current instance, converted to an System.Int32. - - int IConvertible.ToInt32( IFormatProvider provider ) - { - return Convert.ToInt32( m_value ); - } - - // - // Summary: - // For a description of m_value member, see System.IConvertible.ToUInt32(System.IFormatProvider). - // - // Parameters: - // provider: - // m_value parameter is ignored. - // - // Returns: - // The value of the current instance, converted to a System.UInt32. - - uint IConvertible.ToUInt32( IFormatProvider provider ) - { - return Convert.ToUInt32( m_value ); - } - - // - // Summary: - // For a description of m_value member, see System.IConvertible.ToInt64(System.IFormatProvider). - // - // Parameters: - // provider: - // m_value parameter is ignored. - // - // Returns: - // The value of the current instance, converted to an System.Int64. - - long IConvertible.ToInt64( IFormatProvider provider ) - { - return Convert.ToInt64( m_value ); - } - - // - // Summary: - // For a description of m_value member, see System.IConvertible.ToUInt64(System.IFormatProvider). - // - // Parameters: - // provider: - // m_value parameter is ignored. - // - // Returns: - // The value of the current instance, unchanged. - - ulong IConvertible.ToUInt64( IFormatProvider provider ) - { - return m_value; - } - - // - // Summary: - // For a description of m_value member, see System.IConvertible.ToSingle(System.IFormatProvider). - // - // Parameters: - // provider: - // m_value parameter is ignored. - // - // Returns: - // The value of the current instance, converted to a System.Single. - - float IConvertible.ToSingle( IFormatProvider provider ) - { - return Convert.ToSingle( m_value ); - } - - // - // Summary: - // For a description of m_value member, see System.IConvertible.ToDouble(System.IFormatProvider). - // - // Parameters: - // provider: - // m_value parameter is ignored. - // - // Returns: - // The value of the current instance, converted to a System.Double. - - double IConvertible.ToDouble( IFormatProvider provider ) - { - return Convert.ToDouble( m_value ); - } - - decimal IConvertible.ToDecimal( IFormatProvider provider ) - { - return Convert.ToDecimal( m_value ); - } - - DateTime IConvertible.ToDateTime( IFormatProvider provider ) - { - throw new InvalidCastException( $"InvalidCast_FromTo UInt64 DateTime" ); - } - - public object ToType( Type conversionType, IFormatProvider provider ) - { - return Convert.ChangeType( m_value, conversionType, provider ); - } - - #endregion - - } - - - - -} +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Runtime.InteropServices; +using System.Security; +using System.Text; +using System.Threading.Tasks; + +//using System.MemoryExtensions; + +namespace lib +{ + + + public struct Id: IComparable, IFormattable, IConvertible, IComparable, IEquatable + { + public const ulong Min = 0uL; + public const ulong Max = 18446744073709551615uL; + + static Random s_rand = new Random(); + + + // TODO PERF Make span versions of all these functions + + unsafe public static Id Generate() + { + var buf = new byte[8]; + + s_rand.NextBytes( buf ); + + var newId = BitConverter.ToUInt64(buf, 0); + + return new Id { m_value = newId }; + } + + ulong m_value; + + + public int CompareTo( object value ) + { + if( value == null ) + { + return 1; + } + if( value is ulong ) + { + ulong num = (ulong)value; + if( m_value < num ) + { + return -1; + } + if( m_value > num ) + { + return 1; + } + return 0; + } + throw new ArgumentException( "" ); + } + + public int CompareTo( ulong value ) + { + if( m_value < value ) + { + return -1; + } + if( m_value > value ) + { + return 1; + } + return 0; + } + + public override bool Equals( object obj ) + { + if( !( obj is ulong ) ) + { + return false; + } + return m_value == (ulong)obj; + } + + public bool Equals( ulong obj ) + { + return m_value == obj; + } + + public override int GetHashCode() + { + return (int)m_value ^ (int)( m_value >> 32 ); + } + + #region ToString + // + // Summary: + // Converts the numeric value of m_value instance to its equivalent string representation. + // + // Returns: + // The string representation of the value of m_value instance, consisting of a sequence + // of digits ranging from 0 to 9, without a sign or leading zeroes. + [SecuritySafeCritical] + + public override string ToString() + { + return m_value.ToString( null, NumberFormatInfo.CurrentInfo ); + } + + // + // Summary: + // Converts the numeric value of m_value instance to its equivalent string representation + // using the specified culture-specific format information. + // + // Parameters: + // provider: + // An object that supplies culture-specific formatting information. + // + // Returns: + // The string representation of the value of m_value instance as specified by provider. + [SecuritySafeCritical] + + public string ToString( IFormatProvider provider ) + { + return m_value.ToString( null, NumberFormatInfo.GetInstance( provider ) ); + } + + // + // Summary: + // Converts the numeric value of m_value instance to its equivalent string representation + // using the specified format. + // + // Parameters: + // format: + // A numeric format string. + // + // Returns: + // The string representation of the value of m_value instance as specified by format. + // + // Exceptions: + // T:System.FormatException: + // The format parameter is invalid. + [SecuritySafeCritical] + + public string ToString( string format ) + { + return m_value.ToString( format, NumberFormatInfo.CurrentInfo ); + } + + // + // Summary: + // Converts the numeric value of m_value instance to its equivalent string representation + // using the specified format and culture-specific format information. + // + // Parameters: + // format: + // A numeric format string. + // + // provider: + // An object that supplies culture-specific formatting information about m_value instance. + // + // Returns: + // The string representation of the value of m_value instance as specified by format + // and provider. + // + // Exceptions: + // T:System.FormatException: + // The format parameter is invalid. + [SecuritySafeCritical] + + public string ToString( string format, IFormatProvider provider ) + { + return m_value.ToString( format, NumberFormatInfo.GetInstance( provider ) ); + } + + #endregion + + #region Parse + // + // Summary: + // Converts the string representation of a number to its 64-bit unsigned integer + // equivalent. + // + // Parameters: + // s: + // A string that represents the number to convert. + // + // Returns: + // A 64-bit unsigned integer equivalent to the number contained in s. + // + // Exceptions: + // T:System.ArgumentNullException: + // The s parameter is null. + // + // T:System.FormatException: + // The s parameter is not in the correct format. + // + // T:System.OverflowException: + // The s parameter represents a number less than System.UInt64.MinValue or greater + // than System.UInt64.MaxValue. + + + public static ulong Parse( string s ) + { + + return ulong.Parse( s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo ); + } + + // + // Summary: + // Converts the string representation of a number in a specified style to its 64-bit + // unsigned integer equivalent. + // + // Parameters: + // s: + // A string that represents the number to convert. The string is interpreted by + // using the style specified by the style parameter. + // + // style: + // A bitwise combination of the enumeration values that specifies the permitted + // format of s. A typical value to specify is System.Globalization.NumberStyles.Integer. + // + // Returns: + // A 64-bit unsigned integer equivalent to the number specified in s. + // + // Exceptions: + // T:System.ArgumentNullException: + // The s parameter is null. + // + // T:System.ArgumentException: + // /// style is not a System.Globalization.NumberStyles value. -or-style is not + // a combination of System.Globalization.NumberStyles.AllowHexSpecifier and System.Globalization.NumberStyles.HexNumber + // values. + // + // T:System.FormatException: + // The s parameter is not in a format compliant with style. + // + // T:System.OverflowException: + // The s parameter represents a number less than System.UInt64.MinValue or greater + // than System.UInt64.MaxValue. -or-s includes non-zero, fractional digits. + + + public static ulong Parse( string s, NumberStyles style ) + { + return ulong.Parse( s, style, NumberFormatInfo.CurrentInfo ); + } + + // + // Summary: + // Converts the string representation of a number in a specified culture-specific + // format to its 64-bit unsigned integer equivalent. + // + // Parameters: + // s: + // A string that represents the number to convert. + // + // provider: + // An object that supplies culture-specific formatting information about s. + // + // Returns: + // A 64-bit unsigned integer equivalent to the number specified in s. + // + // Exceptions: + // T:System.ArgumentNullException: + // The s parameter is null. + // + // T:System.FormatException: + // The s parameter is not in the correct style. + // + // T:System.OverflowException: + // The s parameter represents a number less than System.UInt64.MinValue or greater + // than System.UInt64.MaxValue. + + + public static ulong Parse( string s, IFormatProvider provider ) + { + return ulong.Parse( s, NumberStyles.Integer, NumberFormatInfo.GetInstance( provider ) ); + } + + // + // Summary: + // Converts the string representation of a number in a specified style and culture-specific + // format to its 64-bit unsigned integer equivalent. + // + // Parameters: + // s: + // A string that represents the number to convert. The string is interpreted by + // using the style specified by the style parameter. + // + // style: + // A bitwise combination of enumeration values that indicates the style elements + // that can be present in s. A typical value to specify is System.Globalization.NumberStyles.Integer. + // + // provider: + // An object that supplies culture-specific formatting information about s. + // + // Returns: + // A 64-bit unsigned integer equivalent to the number specified in s. + // + // Exceptions: + // T:System.ArgumentNullException: + // The s parameter is null. + // + // T:System.ArgumentException: + // /// style is not a System.Globalization.NumberStyles value. -or-style is not + // a combination of System.Globalization.NumberStyles.AllowHexSpecifier and System.Globalization.NumberStyles.HexNumber + // values. + // + // T:System.FormatException: + // The s parameter is not in a format compliant with style. + // + // T:System.OverflowException: + // The s parameter represents a number less than System.UInt64.MinValue or greater + // than System.UInt64.MaxValue. -or-s includes non-zero, fractional digits. + + + public static ulong Parse( string s, NumberStyles style, IFormatProvider provider ) + { + return ulong.Parse( s, style, NumberFormatInfo.GetInstance( provider ) ); + } + + // + // Summary: + // Tries to convert the string representation of a number to its 64-bit unsigned + // integer equivalent. A return value indicates whether the conversion succeeded + // or failed. + // + // Parameters: + // s: + // A string that represents the number to convert. + // + // result: + // When m_value method returns, contains the 64-bit unsigned integer value that is + // equivalent to the number contained in s, if the conversion succeeded, or zero + // if the conversion failed. The conversion fails if the s parameter is null, is + // not of the correct format, or represents a number less than System.UInt64.MinValue + // or greater than System.UInt64.MaxValue. m_value parameter is passed uninitialized. + // + // Returns: + // true if s was converted successfully; otherwise, false. + + + public static bool TryParse( string s, out ulong result ) + { + return ulong.TryParse( s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo, out result ); + } + + // + // Summary: + // Tries to convert the string representation of a number in a specified style and + // culture-specific format to its 64-bit unsigned integer equivalent. A return value + // indicates whether the conversion succeeded or failed. + // + // Parameters: + // s: + // A string that represents the number to convert. The string is interpreted by + // using the style specified by the style parameter. + // + // style: + // A bitwise combination of enumeration values that indicates the permitted format + // of s. A typical value to specify is System.Globalization.NumberStyles.Integer. + // + // provider: + // An object that supplies culture-specific formatting information about s. + // + // result: + // When m_value method returns, contains the 64-bit unsigned integer value equivalent + // to the number contained in s, if the conversion succeeded, or zero if the conversion + // failed. The conversion fails if the s parameter is null, is not in a format compliant + // with style, or represents a number less than System.UInt64.MinValue or greater + // than System.UInt64.MaxValue. m_value parameter is passed uninitialized. + // + // Returns: + // true if s was converted successfully; otherwise, false. + // + // Exceptions: + // T:System.ArgumentException: + // /// style is not a System.Globalization.NumberStyles value. -or-style is not + // a combination of System.Globalization.NumberStyles.AllowHexSpecifier and System.Globalization.NumberStyles.HexNumber + // values. + + + public static bool TryParse( string s, NumberStyles style, IFormatProvider provider, out ulong result ) + { + return ulong.TryParse( s, style, NumberFormatInfo.GetInstance( provider ), out result ); + } + + #endregion + + + // + // Summary: + // Returns the System.TypeCode for value type System.UInt64. + // + // Returns: + // The enumerated constant, System.TypeCode.UInt64. + public TypeCode GetTypeCode() + { + return TypeCode.UInt64; + } + + #region Converters + // + // Summary: + // For a description of m_value member, see System.IConvertible.ToBoolean(System.IFormatProvider). + // + // Parameters: + // provider: + // m_value parameter is ignored. + // + // Returns: + // true if the value of the current instance is not zero; otherwise, false. + + bool IConvertible.ToBoolean( IFormatProvider provider ) + { + return Convert.ToBoolean( m_value ); + } + + // + // Summary: + // For a description of m_value member, see System.IConvertible.ToChar(System.IFormatProvider). + // + // Parameters: + // provider: + // m_value parameter is ignored. + // + // Returns: + // The value of the current instance, converted to a System.Char. + + char IConvertible.ToChar( IFormatProvider provider ) + { + return Convert.ToChar( m_value ); + } + + // + // Summary: + // For a description of m_value member, see System.IConvertible.ToSByte(System.IFormatProvider). + // + // Parameters: + // provider: + // m_value parameter is ignored. + // + // Returns: + // The value of the current instance, converted to an System.SByte. + + sbyte IConvertible.ToSByte( IFormatProvider provider ) + { + return Convert.ToSByte( m_value ); + } + + // + // Summary: + // For a description of m_value member, see System.IConvertible.ToByte(System.IFormatProvider). + // + // Parameters: + // provider: + // m_value parameter is ignored. + // + // Returns: + // The value of the current instance, converted to a System.Byte. + + byte IConvertible.ToByte( IFormatProvider provider ) + { + return Convert.ToByte( m_value ); + } + + // + // Summary: + // For a description of m_value member, see System.IConvertible.ToInt16(System.IFormatProvider). + // + // Parameters: + // provider: + // m_value parameter is ignored. + // + // Returns: + // The value of the current instance, converted to an System.Int16. + + short IConvertible.ToInt16( IFormatProvider provider ) + { + return Convert.ToInt16( m_value ); + } + + // + // Summary: + // For a description of m_value member, see System.IConvertible.ToUInt16(System.IFormatProvider). + // + // Parameters: + // provider: + // m_value parameter is ignored. + // + // Returns: + // The value of the current instance, converted to a System.UInt16. + + ushort IConvertible.ToUInt16( IFormatProvider provider ) + { + return Convert.ToUInt16( m_value ); + } + + // + // Summary: + // For a description of m_value member, see System.IConvertible.ToInt32(System.IFormatProvider). + // + // Parameters: + // provider: + // m_value parameter is ignored. + // + // Returns: + // The value of the current instance, converted to an System.Int32. + + int IConvertible.ToInt32( IFormatProvider provider ) + { + return Convert.ToInt32( m_value ); + } + + // + // Summary: + // For a description of m_value member, see System.IConvertible.ToUInt32(System.IFormatProvider). + // + // Parameters: + // provider: + // m_value parameter is ignored. + // + // Returns: + // The value of the current instance, converted to a System.UInt32. + + uint IConvertible.ToUInt32( IFormatProvider provider ) + { + return Convert.ToUInt32( m_value ); + } + + // + // Summary: + // For a description of m_value member, see System.IConvertible.ToInt64(System.IFormatProvider). + // + // Parameters: + // provider: + // m_value parameter is ignored. + // + // Returns: + // The value of the current instance, converted to an System.Int64. + + long IConvertible.ToInt64( IFormatProvider provider ) + { + return Convert.ToInt64( m_value ); + } + + // + // Summary: + // For a description of m_value member, see System.IConvertible.ToUInt64(System.IFormatProvider). + // + // Parameters: + // provider: + // m_value parameter is ignored. + // + // Returns: + // The value of the current instance, unchanged. + + ulong IConvertible.ToUInt64( IFormatProvider provider ) + { + return m_value; + } + + // + // Summary: + // For a description of m_value member, see System.IConvertible.ToSingle(System.IFormatProvider). + // + // Parameters: + // provider: + // m_value parameter is ignored. + // + // Returns: + // The value of the current instance, converted to a System.Single. + + float IConvertible.ToSingle( IFormatProvider provider ) + { + return Convert.ToSingle( m_value ); + } + + // + // Summary: + // For a description of m_value member, see System.IConvertible.ToDouble(System.IFormatProvider). + // + // Parameters: + // provider: + // m_value parameter is ignored. + // + // Returns: + // The value of the current instance, converted to a System.Double. + + double IConvertible.ToDouble( IFormatProvider provider ) + { + return Convert.ToDouble( m_value ); + } + + decimal IConvertible.ToDecimal( IFormatProvider provider ) + { + return Convert.ToDecimal( m_value ); + } + + DateTime IConvertible.ToDateTime( IFormatProvider provider ) + { + throw new InvalidCastException( $"InvalidCast_FromTo UInt64 DateTime" ); + } + + public object ToType( Type conversionType, IFormatProvider provider ) + { + return Convert.ChangeType( m_value, conversionType, provider ); + } + + #endregion + + } + + + + +} diff --git a/Token.cs b/Token.cs index 206ece6..c2eb566 100644 --- a/Token.cs +++ b/Token.cs @@ -1,54 +1,54 @@ -using System; -using System.Diagnostics; - -namespace lib -{ - - //TODO PERF fix this and make it fast. - - [Serializable] - public struct Token - { - public string str { get { return m_str; } } - - public Token( String str ) - { - m_str = str; - m_hash = m_str.GetHashCode(); - } - - public override bool Equals( object obj ) - { - if( !( obj is Token ) ) - return false; - - //This doesnt use as because Token is a struct - var otherId = (Token)obj; - - if( m_hash != otherId.m_hash ) - return false; - - return m_str == otherId.m_str; - } - - - public bool Equals_fast( Token other ) - { - return m_hash == other.m_hash && m_str == other.m_str; - } - - public override int GetHashCode() - { - return m_hash; - } - - public override string ToString() - { - return m_str; - } - - int m_hash; - String m_str; - } - -} +using System; +using System.Diagnostics; + +namespace lib +{ + + //TODO PERF fix this and make it fast. + + [Serializable] + public struct Token + { + public string str { get { return m_str; } } + + public Token( String str ) + { + m_str = str; + m_hash = m_str.GetHashCode(); + } + + public override bool Equals( object obj ) + { + if( !( obj is Token ) ) + return false; + + //This doesnt use as because Token is a struct + var otherId = (Token)obj; + + if( m_hash != otherId.m_hash ) + return false; + + return m_str == otherId.m_str; + } + + + public bool Equals_fast( Token other ) + { + return m_hash == other.m_hash && m_str == other.m_str; + } + + public override int GetHashCode() + { + return m_hash; + } + + public override string ToString() + { + return m_str; + } + + int m_hash; + String m_str; + } + +} diff --git a/Utilities.Interop.cs b/Utilities.Interop.cs index 2c88928..a1d5f68 100644 --- a/Utilities.Interop.cs +++ b/Utilities.Interop.cs @@ -1,32 +1,32 @@ -// Copyright (c) Xenko contributors (https://xenko.com) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) -// Distributed under the MIT license. See the LICENSE.md file in the project root for more information. -// -// Copyright (c) 2010-2012 SharpDX - Alexandre Mutel -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +// Copyright (c) Xenko contributors (https://xenko.com) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) +// Distributed under the MIT license. See the LICENSE.md file in the project root for more information. +// +// Copyright (c) 2010-2012 SharpDX - Alexandre Mutel +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. #pragma warning disable SA1300 // Element must begin with upper-case letter #pragma warning disable SA1649 // File name must match first type name using System; using System.Runtime.CompilerServices; namespace lib -{ +{ /// /// Utility class. /// diff --git a/Utilities.cs b/Utilities.cs index bde0e72..7f9cefd 100644 --- a/Utilities.cs +++ b/Utilities.cs @@ -1,850 +1,850 @@ -// Copyright (c) Xenko contributors (https://xenko.com) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) -// Distributed under the MIT license. See the LICENSE.md file in the project root for more information. -// -// Copyright (c) 2010-2012 SharpDX - Alexandre Mutel -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -#pragma warning disable SA1405 // Debug.Assert must provide message text -using att; - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Security; -using System.Text; -using System.Threading; - -namespace lib -{ - /// - /// Utility class. - /// - public static class Util - { - - /* - #if XENKO_PLATFORM_UWP - public static unsafe void CopyMemory(IntPtr dest, IntPtr src, int sizeInBytesToCopy) - { - Interop.memcpy((void*)dest, (void*)src, sizeInBytesToCopy); - } - #else - #if XENKO_PLATFORM_WINDOWS_DESKTOP - private const string MemcpyDll = "msvcrt.dll"; - #elif XENKO_PLATFORM_ANDROID - private const string MemcpyDll = "libc.so"; - #elif XENKO_PLATFORM_UNIX - // We do not specifiy the .so extension as libc.so on Linux - // is actually not a .so files but a script. Using just libc - // will automatically find the corresponding .so. - private const string MemcpyDll = "libc"; - #elif XENKO_PLATFORM_IOS - private const string MemcpyDll = ObjCRuntime.Constants.SystemLibrary; - #else - # error Unsupported platform - #endif - [DllImport(MemcpyDll, EntryPoint = "memcpy", CallingConvention = CallingConvention.Cdecl, SetLastError = false)] - #if !XENKO_RUNTIME_CORECLR - [SuppressUnmanagedCodeSecurity] - #endif - private static extern IntPtr CopyMemory(IntPtr dest, IntPtr src, ulong sizeInBytesToCopy); - - /// - /// Copy memory. - /// - /// The destination memory location - /// The source memory location. - /// The count. - public static void CopyMemory(IntPtr dest, IntPtr src, int sizeInBytesToCopy) - { - CopyMemory(dest, src, (ulong)sizeInBytesToCopy); - } - #endif - */ - - - - public static void checkAndAddDirectory( string path ) - { - if( !Directory.Exists( path ) ) - { - log.info( $"Creating directory {path}" ); - Directory.CreateDirectory( path ); - } - else - { - log.debug( $"{path} already exists." ); - } - - } - - - /// - /// Compares two block of memory. - /// - /// The pointer to compare from. - /// The pointer to compare against. - /// The size in bytes to compare. - /// True if the buffers are equivalent, false otherwise. - public static unsafe bool CompareMemory( IntPtr from, IntPtr against, int sizeToCompare ) - { - var pSrc = (byte*)from; - var pDst = (byte*)against; - - // Compare 8 bytes. - var numberOf = sizeToCompare >> 3; - while( numberOf > 0 ) - { - if( *(long*)pSrc != *(long*)pDst ) - return false; - pSrc += 8; - pDst += 8; - numberOf--; - } - - // Compare remaining bytes. - numberOf = sizeToCompare & 7; - while( numberOf > 0 ) - { - if( *pSrc != *pDst ) - return false; - pSrc++; - pDst++; - numberOf--; - } - - return true; - } - - /// - /// Clears the memory. - /// - /// The dest. - /// The value. - /// The size in bytes to clear. - public static void ClearMemory( IntPtr dest, byte value, int sizeInBytesToClear ) - { - unsafe - { - Interop.memset( (void*)dest, value, sizeInBytesToClear ); - } - } - - /// - /// Return the sizeof a struct from a CLR. Equivalent to sizeof operator but works on generics too. - /// - /// a struct to evaluate - /// sizeof this struct - public static int SizeOf() where T : struct - { - return Interop.SizeOf(); - } - - /// - /// Return the sizeof an array of struct. Equivalent to sizeof operator but works on generics too. - /// - /// a struct - /// The array of struct to evaluate. - /// sizeof in bytes of this array of struct - public static int SizeOf( T[] array ) where T : struct - { - return array == null ? 0 : array.Length * Interop.SizeOf(); - } - - /// - /// Pins the specified source and call an action with the pinned pointer. - /// - /// The type of the structure to pin - /// The source. - /// The pin action to perform on the pinned pointer. - public static void Pin( ref T source, Action pinAction ) where T : struct - { - unsafe - { - pinAction( (IntPtr)Interop.Fixed( ref source ) ); - } - } - - /// - /// Pins the specified source and call an action with the pinned pointer. - /// - /// The type of the structure to pin - /// The source array. - /// The pin action to perform on the pinned pointer. - public static void Pin( T[] source, [NotNull] Action pinAction ) where T : struct - { - unsafe - { - pinAction( source == null ? IntPtr.Zero : (IntPtr)Interop.Fixed( source ) ); - } - } - - /// - /// Covnerts a structured array to an equivalent byte array. - /// - /// The source. - /// The byte array. - public static byte[] ToByteArray( T[] source ) where T : struct - { - if( source == null ) - return null; - - var buffer = new byte[SizeOf() * source.Length]; - - if( source.Length == 0 ) - return buffer; - - unsafe - { - fixed( void* pBuffer = buffer ) - Interop.Write( pBuffer, source, 0, source.Length ); - } - return buffer; - } - - /// - /// Reads the specified T data from a memory location. - /// - /// Type of a data to read - /// Memory location to read from. - /// The data read from the memory location - public static T Read( IntPtr source ) where T : struct - { - unsafe - { - return Interop.ReadInline( (void*)source ); - } - } - - /// - /// Reads the specified T data from a memory location. - /// - /// Type of a data to read - /// Memory location to read from. - /// The data write to. - [MethodImpl( MethodImplOptions.AggressiveInlining )] - public static void Read( IntPtr source, ref T data ) where T : struct - { - unsafe - { - Interop.CopyInline( ref data, (void*)source ); - } - } - - /// - /// Reads the specified T data from a memory location. - /// - /// Type of a data to read - /// Memory location to read from. - /// The data write to. - public static void ReadOut( IntPtr source, out T data ) where T : struct - { - unsafe - { - Interop.CopyInlineOut( out data, (void*)source ); - } - } - - /// - /// Reads the specified T data from a memory location. - /// - /// Type of a data to read - /// Memory location to read from. - /// The data write to. - /// source pointer + sizeof(T) - public static IntPtr ReadAndPosition( IntPtr source, ref T data ) where T : struct - { - unsafe - { - return (IntPtr)Interop.Read( (void*)source, ref data ); - } - } - - /// - /// Reads the specified array T[] data from a memory location. - /// - /// Type of a data to read - /// Memory location to read from. - /// The data write to. - /// The offset in the array to write to. - /// The number of T element to read from the memory location - /// source pointer + sizeof(T) * count - public static IntPtr Read( IntPtr source, T[] data, int offset, int count ) where T : struct - { - unsafe - { - return (IntPtr)Interop.Read( (void*)source, data, offset, count ); - } - } - - /// - /// Writes the specified T data to a memory location. - /// - /// Type of a data to write - /// Memory location to write to. - /// The data to write. - [MethodImpl( MethodImplOptions.AggressiveInlining )] - public static void Write( IntPtr destination, ref T data ) where T : struct - { - unsafe - { - Interop.CopyInline( (void*)destination, ref data ); - } - } - - /// - /// Writes the specified T data to a memory location. - /// - /// Type of a data to write - /// Memory location to write to. - /// The data to write. - /// destination pointer + sizeof(T) - public static IntPtr WriteAndPosition( IntPtr destination, ref T data ) where T : struct - { - unsafe - { - return (IntPtr)Interop.Write( (void*)destination, ref data ); - } - } - - /// - /// Writes the specified array T[] data to a memory location. - /// - /// Type of a data to write - /// Memory location to write to. - /// The array of T data to write. - /// The offset in the array to read from. - /// The number of T element to write to the memory location - public static void Write( byte[] destination, T[] data, int offset, int count ) where T : struct - { - unsafe - { - fixed( void* pDest = destination ) - { - Write( (IntPtr)pDest, data, offset, count ); - } - } - } - - /// - /// Writes the specified array T[] data to a memory location. - /// - /// Type of a data to write - /// Memory location to write to. - /// The array of T data to write. - /// The offset in the array to read from. - /// The number of T element to write to the memory location - /// destination pointer + sizeof(T) * count - public static IntPtr Write( IntPtr destination, T[] data, int offset, int count ) where T : struct - { - unsafe - { - return (IntPtr)Interop.Write( (void*)destination, data, offset, count ); - } - } - - /// - /// Allocate an aligned memory buffer. - /// - /// Size of the buffer to allocate. - /// Alignment, a positive value which is a power of 2. 16 bytes by default. - /// A pointer to a buffer aligned. - /// - /// To free this buffer, call - /// - public static unsafe IntPtr AllocateMemory( int sizeInBytes, int align = 16 ) - { - var mask = align - 1; - if( ( align & mask ) != 0 ) - { - throw new ArgumentException( "Alignment is not power of 2", nameof( align ) ); - } - var memPtr = Marshal.AllocHGlobal(sizeInBytes + mask + sizeof(void*)); - var ptr = (byte*)((ulong)(memPtr.ToInt32() + sizeof(void*) + mask) & ~(ulong)mask); - ( (IntPtr*)ptr )[-1] = memPtr; - return new IntPtr( ptr ); - } - - /// - /// Allocate an aligned memory buffer and clear it with a specified value (0 by defaault). - /// - /// Size of the buffer to allocate. - /// Default value used to clear the buffer. - /// Alignment, 16 bytes by default. - /// A pointer to a buffer aligned. - /// - /// To free this buffer, call - /// - public static IntPtr AllocateClearedMemory( int sizeInBytes, byte clearValue = 0, int align = 16 ) - { - var ptr = AllocateMemory(sizeInBytes, align); - ClearMemory( ptr, clearValue, sizeInBytes ); - return ptr; - } - - /// - /// Determines whether the specified memory pointer is aligned in memory. - /// - /// The memory pointer. - /// The align. - /// true if the specified memory pointer is aligned in memory; otherwise, false. - public static bool IsMemoryAligned( IntPtr memoryPtr, int align = 16 ) - { - return ( memoryPtr.ToInt64() & ( align - 1 ) ) == 0; - } - - /// - /// Allocate an aligned memory buffer. - /// - /// - /// The buffer must have been allocated with - /// - public static unsafe void FreeMemory( IntPtr alignedBuffer ) - { - Marshal.FreeHGlobal( ( (IntPtr*)alignedBuffer )[-1] ); - } - - /// - /// If non-null, disposes the specified object and set it to null, otherwise do nothing. - /// - /// The disposable. - public static void Dispose( ref T disposable ) where T : class, IDisposable - { - if( disposable != null ) - { - disposable.Dispose(); - disposable = null; - } - } - - /// - /// String helper join method to display an array of object as a single string. - /// - /// The separator. - /// The array. - /// a string with array elements serparated by the seperator - [NotNull] - public static string Join( string separator, T[] array ) - { - var text = new StringBuilder(); - if( array != null ) - { - for( var i = 0; i < array.Length; i++ ) - { - if( i > 0 ) - text.Append( separator ); - text.Append( array[i] ); - } - } - return text.ToString(); - } - - /// - /// String helper join method to display an enumrable of object as a single string. - /// - /// The separator. - /// The enumerable. - /// a string with array elements serparated by the seperator - [NotNull] - public static string Join( string separator, [NotNull] IEnumerable elements ) - { - var elementList = new List(); - foreach( var element in elements ) - elementList.Add( element.ToString() ); - - var text = new StringBuilder(); - for( var i = 0; i < elementList.Count; i++ ) - { - var element = elementList[i]; - if( i > 0 ) - text.Append( separator ); - text.Append( element ); - } - return text.ToString(); - } - - /// - /// String helper join method to display an enumrable of object as a single string. - /// - /// The separator. - /// The enumerable. - /// a string with array elements serparated by the seperator - [NotNull] - public static string Join( string separator, [NotNull] IEnumerator elements ) - { - var elementList = new List(); - while( elements.MoveNext() ) - elementList.Add( elements.Current.ToString() ); - - var text = new StringBuilder(); - for( var i = 0; i < elementList.Count; i++ ) - { - var element = elementList[i]; - if( i > 0 ) - text.Append( separator ); - text.Append( element ); - } - return text.ToString(); - } - - /// - /// Read stream to a byte[] buffer - /// - /// input stream - /// a byte[] buffer - [NotNull] - public static byte[] ReadStream( [NotNull] Stream stream ) - { - var readLength = 0; - return ReadStream( stream, ref readLength ); - } - - /// - /// Read stream to a byte[] buffer - /// - /// input stream - /// length to read - /// a byte[] buffer - [NotNull] - public static byte[] ReadStream( [NotNull] Stream stream, ref int readLength ) - { - System.Diagnostics.Debug.Assert( stream != null ); - System.Diagnostics.Debug.Assert( stream.CanRead ); - var num = readLength; - System.Diagnostics.Debug.Assert( num <= ( stream.Length - stream.Position ) ); - if( num == 0 ) - readLength = (int)( stream.Length - stream.Position ); - num = readLength; - - System.Diagnostics.Debug.Assert( num >= 0 ); - if( num == 0 ) - return new byte[0]; - - var buffer = new byte[num]; - var bytesRead = 0; - if( num > 0 ) - { - do - { - bytesRead += stream.Read( buffer, bytesRead, readLength - bytesRead ); - } while( bytesRead < readLength ); - } - return buffer; - } - - /// - /// Computes a hashcode for a dictionary. - /// - /// Hashcode for the list. - public static int GetHashCode( IDictionary dict ) - { - if( dict == null ) - return 0; - - var hashCode = 0; - foreach( DictionaryEntry keyValue in dict ) - { - hashCode = ( hashCode * 397 ) ^ keyValue.Key.GetHashCode(); - hashCode = ( hashCode * 397 ) ^ ( keyValue.Value?.GetHashCode() ?? 0 ); - } - return hashCode; - } - - /// - /// Computes a hashcode for an enumeration - /// - /// An enumerator. - /// Hashcode for the list. - public static int GetHashCode( IEnumerable it ) - { - if( it == null ) - return 0; - - var hashCode = 0; - foreach( var current in it ) - { - hashCode = ( hashCode * 397 ) ^ ( current?.GetHashCode() ?? 0 ); - } - return hashCode; - } - - /// - /// Computes a hashcode for an enumeration - /// - /// An enumerator. - /// Hashcode for the list. - public static int GetHashCode( IEnumerator it ) - { - if( it == null ) - return 0; - - var hashCode = 0; - while( it.MoveNext() ) - { - var current = it.Current; - hashCode = ( hashCode * 397 ) ^ ( current?.GetHashCode() ?? 0 ); - } - return hashCode; - } - - /// - /// Compares two collection, element by elements. - /// - /// A "from" enumerator. - /// A "to" enumerator. - /// True if lists are identical. False otherwise. - public static bool Compare( IEnumerable left, IEnumerable right ) - { - if( ReferenceEquals( left, right ) ) - return true; - if( ReferenceEquals( left, null ) || ReferenceEquals( right, null ) ) - return false; - - return Compare( left.GetEnumerator(), right.GetEnumerator() ); - } - - /// - /// Compares two collection, element by elements. - /// - /// A "from" enumerator. - /// A "to" enumerator. - /// True if lists are identical. False otherwise. - public static bool Compare( IEnumerator leftIt, IEnumerator rightIt ) - { - if( ReferenceEquals( leftIt, rightIt ) ) - return true; - if( ReferenceEquals( leftIt, null ) || ReferenceEquals( rightIt, null ) ) - return false; - - bool hasLeftNext; - bool hasRightNext; - while( true ) - { - hasLeftNext = leftIt.MoveNext(); - hasRightNext = rightIt.MoveNext(); - if( !hasLeftNext || !hasRightNext ) - break; - - if( !Equals( leftIt.Current, rightIt.Current ) ) - return false; - } - - // If there is any left element - if( hasLeftNext != hasRightNext ) - return false; - - return true; - } - - /// - /// Compares two collection, element by elements. - /// - /// The collection to compare from. - /// The colllection to compare to. - /// True if lists are identical (but no necessarely of the same time). False otherwise. - public static bool Compare( IDictionary first, IDictionary second ) - { - if( ReferenceEquals( first, second ) ) - return true; - if( ReferenceEquals( first, null ) || ReferenceEquals( second, null ) ) - return false; - if( first.Count != second.Count ) - return false; - - var comparer = EqualityComparer.Default; - - foreach( var keyValue in first ) - { - TValue secondValue; - if( !second.TryGetValue( keyValue.Key, out secondValue ) ) - return false; - if( !comparer.Equals( keyValue.Value, secondValue ) ) - return false; - } - - // Check that all keys in second are in first - return second.Keys.All( first.ContainsKey ); - } - - public static bool Compare( T[] left, T[] right ) - { - if( ReferenceEquals( left, right ) ) - return true; - if( ReferenceEquals( left, null ) || ReferenceEquals( right, null ) ) - return false; - - if( left.Length != right.Length ) - return false; - - var comparer = EqualityComparer.Default; - for( var i = 0; i < left.Length; ++i ) - { - if( !comparer.Equals( left[i], right[i] ) ) - return false; - } - - return true; - } - - /// - /// Compares two collection, element by elements. - /// - /// The collection to compare from. - /// The colllection to compare to. - /// True if lists are identical (but no necessarely of the same time). False otherwise. - public static bool Compare( ICollection left, ICollection right ) - { - if( ReferenceEquals( left, right ) ) - return true; - if( ReferenceEquals( left, null ) || ReferenceEquals( right, null ) ) - return false; - - if( left.Count != right.Count ) - return false; - - var count = 0; - var leftIt = left.GetEnumerator(); - var rightIt = right.GetEnumerator(); - var comparer = EqualityComparer.Default; - while( leftIt.MoveNext() && rightIt.MoveNext() ) - { - if( !comparer.Equals( leftIt.Current, rightIt.Current ) ) - return false; - count++; - } - - // Just double check to make sure that the iterator actually returns - // the exact number of elements - if( count != left.Count ) - return false; - - return true; - } - - /// - /// Swaps the value between two references. - /// - /// Type of a data to swap. - /// The left value. - /// The right value. - public static void Swap( ref T left, ref T right ) - { - var temp = left; - left = right; - right = temp; - } - - /// - /// Suspends current thread for a . - /// - /// The duration of sleep. - public static void Sleep( TimeSpan sleepTime ) - { - var ms = (long)sleepTime.TotalMilliseconds; - if( ms < 0 || ms > int.MaxValue ) - { - throw new ArgumentOutOfRangeException( nameof( sleepTime ), "Sleep time must be a duration less than '2^31 - 1' milliseconds." ); - } - // MH PORTED NativeInvoke.Sleep((int)ms); - Thread.Sleep( (int)ms ); - } - - /// - /// Suspends current thread for a . - /// - /// The duration of sleep in milliseconds. - public static void Sleep( int sleepTimeInMillis ) - { - // MH PORTED NativeInvoke.Sleep(sleepTimeInMillis); - Thread.Sleep( sleepTimeInMillis ); - } - - /// - /// Writes the specified T data to a memory location. - /// - /// Type of a data to write - /// Memory location to write to. - /// The data to write. - internal static void UnsafeWrite( IntPtr destination, ref T data ) - { - unsafe - { - Interop.CopyInline( (void*)destination, ref data ); - } - } - - /// - /// Reads the specified T data from a memory location. - /// - /// Type of a data to read - /// Memory location to read from. - /// The data write to. - internal static void UnsafeReadOut( IntPtr source, out T data ) - { - unsafe - { - Interop.CopyInlineOut( out data, (void*)source ); - } - } - - /// - /// Return the sizeof a struct from a CLR. Equivalent to sizeof operator but works on generics too. - /// - /// a struct to evaluate - /// sizeof this struct - internal static int UnsafeSizeOf() - { - return Interop.SizeOf(); - } - - /// - /// Linq assisted full tree iteration and collection in a single line. - /// Warning, could be slow. - /// - /// The type to iterate. - /// The root item - /// The function to retrieve a child - public static IEnumerable IterateTree( T root, Func> childrenF ) - { - var q = new List { root }; - while( q.Any() ) - { - var c = q[0]; - q.RemoveAt( 0 ); - q.AddRange( childrenF( c ) ?? Enumerable.Empty() ); - yield return c; - } - } - - /// - /// Converts a raw time to a . - /// - /// The delta. - /// The . - public static TimeSpan ConvertRawToTimestamp( long delta ) - { - return new TimeSpan( delta == 0 ? 0 : ( delta * TimeSpan.TicksPerSecond ) / Stopwatch.Frequency ); - } - } -} +// Copyright (c) Xenko contributors (https://xenko.com) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) +// Distributed under the MIT license. See the LICENSE.md file in the project root for more information. +// +// Copyright (c) 2010-2012 SharpDX - Alexandre Mutel +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +#pragma warning disable SA1405 // Debug.Assert must provide message text +using att; + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Security; +using System.Text; +using System.Threading; + +namespace lib +{ + /// + /// Utility class. + /// + public static class Util + { + + /* + #if XENKO_PLATFORM_UWP + public static unsafe void CopyMemory(IntPtr dest, IntPtr src, int sizeInBytesToCopy) + { + Interop.memcpy((void*)dest, (void*)src, sizeInBytesToCopy); + } + #else + #if XENKO_PLATFORM_WINDOWS_DESKTOP + private const string MemcpyDll = "msvcrt.dll"; + #elif XENKO_PLATFORM_ANDROID + private const string MemcpyDll = "libc.so"; + #elif XENKO_PLATFORM_UNIX + // We do not specifiy the .so extension as libc.so on Linux + // is actually not a .so files but a script. Using just libc + // will automatically find the corresponding .so. + private const string MemcpyDll = "libc"; + #elif XENKO_PLATFORM_IOS + private const string MemcpyDll = ObjCRuntime.Constants.SystemLibrary; + #else + # error Unsupported platform + #endif + [DllImport(MemcpyDll, EntryPoint = "memcpy", CallingConvention = CallingConvention.Cdecl, SetLastError = false)] + #if !XENKO_RUNTIME_CORECLR + [SuppressUnmanagedCodeSecurity] + #endif + private static extern IntPtr CopyMemory(IntPtr dest, IntPtr src, ulong sizeInBytesToCopy); + + /// + /// Copy memory. + /// + /// The destination memory location + /// The source memory location. + /// The count. + public static void CopyMemory(IntPtr dest, IntPtr src, int sizeInBytesToCopy) + { + CopyMemory(dest, src, (ulong)sizeInBytesToCopy); + } + #endif + */ + + + + public static void checkAndAddDirectory( string path ) + { + if( !Directory.Exists( path ) ) + { + log.info( $"Creating directory {path}" ); + Directory.CreateDirectory( path ); + } + else + { + log.debug( $"{path} already exists." ); + } + + } + + + /// + /// Compares two block of memory. + /// + /// The pointer to compare from. + /// The pointer to compare against. + /// The size in bytes to compare. + /// True if the buffers are equivalent, false otherwise. + public static unsafe bool CompareMemory( IntPtr from, IntPtr against, int sizeToCompare ) + { + var pSrc = (byte*)from; + var pDst = (byte*)against; + + // Compare 8 bytes. + var numberOf = sizeToCompare >> 3; + while( numberOf > 0 ) + { + if( *(long*)pSrc != *(long*)pDst ) + return false; + pSrc += 8; + pDst += 8; + numberOf--; + } + + // Compare remaining bytes. + numberOf = sizeToCompare & 7; + while( numberOf > 0 ) + { + if( *pSrc != *pDst ) + return false; + pSrc++; + pDst++; + numberOf--; + } + + return true; + } + + /// + /// Clears the memory. + /// + /// The dest. + /// The value. + /// The size in bytes to clear. + public static void ClearMemory( IntPtr dest, byte value, int sizeInBytesToClear ) + { + unsafe + { + Interop.memset( (void*)dest, value, sizeInBytesToClear ); + } + } + + /// + /// Return the sizeof a struct from a CLR. Equivalent to sizeof operator but works on generics too. + /// + /// a struct to evaluate + /// sizeof this struct + public static int SizeOf() where T : struct + { + return Interop.SizeOf(); + } + + /// + /// Return the sizeof an array of struct. Equivalent to sizeof operator but works on generics too. + /// + /// a struct + /// The array of struct to evaluate. + /// sizeof in bytes of this array of struct + public static int SizeOf( T[] array ) where T : struct + { + return array == null ? 0 : array.Length * Interop.SizeOf(); + } + + /// + /// Pins the specified source and call an action with the pinned pointer. + /// + /// The type of the structure to pin + /// The source. + /// The pin action to perform on the pinned pointer. + public static void Pin( ref T source, Action pinAction ) where T : struct + { + unsafe + { + pinAction( (IntPtr)Interop.Fixed( ref source ) ); + } + } + + /// + /// Pins the specified source and call an action with the pinned pointer. + /// + /// The type of the structure to pin + /// The source array. + /// The pin action to perform on the pinned pointer. + public static void Pin( T[] source, [NotNull] Action pinAction ) where T : struct + { + unsafe + { + pinAction( source == null ? IntPtr.Zero : (IntPtr)Interop.Fixed( source ) ); + } + } + + /// + /// Covnerts a structured array to an equivalent byte array. + /// + /// The source. + /// The byte array. + public static byte[] ToByteArray( T[] source ) where T : struct + { + if( source == null ) + return null; + + var buffer = new byte[SizeOf() * source.Length]; + + if( source.Length == 0 ) + return buffer; + + unsafe + { + fixed( void* pBuffer = buffer ) + Interop.Write( pBuffer, source, 0, source.Length ); + } + return buffer; + } + + /// + /// Reads the specified T data from a memory location. + /// + /// Type of a data to read + /// Memory location to read from. + /// The data read from the memory location + public static T Read( IntPtr source ) where T : struct + { + unsafe + { + return Interop.ReadInline( (void*)source ); + } + } + + /// + /// Reads the specified T data from a memory location. + /// + /// Type of a data to read + /// Memory location to read from. + /// The data write to. + [MethodImpl( MethodImplOptions.AggressiveInlining )] + public static void Read( IntPtr source, ref T data ) where T : struct + { + unsafe + { + Interop.CopyInline( ref data, (void*)source ); + } + } + + /// + /// Reads the specified T data from a memory location. + /// + /// Type of a data to read + /// Memory location to read from. + /// The data write to. + public static void ReadOut( IntPtr source, out T data ) where T : struct + { + unsafe + { + Interop.CopyInlineOut( out data, (void*)source ); + } + } + + /// + /// Reads the specified T data from a memory location. + /// + /// Type of a data to read + /// Memory location to read from. + /// The data write to. + /// source pointer + sizeof(T) + public static IntPtr ReadAndPosition( IntPtr source, ref T data ) where T : struct + { + unsafe + { + return (IntPtr)Interop.Read( (void*)source, ref data ); + } + } + + /// + /// Reads the specified array T[] data from a memory location. + /// + /// Type of a data to read + /// Memory location to read from. + /// The data write to. + /// The offset in the array to write to. + /// The number of T element to read from the memory location + /// source pointer + sizeof(T) * count + public static IntPtr Read( IntPtr source, T[] data, int offset, int count ) where T : struct + { + unsafe + { + return (IntPtr)Interop.Read( (void*)source, data, offset, count ); + } + } + + /// + /// Writes the specified T data to a memory location. + /// + /// Type of a data to write + /// Memory location to write to. + /// The data to write. + [MethodImpl( MethodImplOptions.AggressiveInlining )] + public static void Write( IntPtr destination, ref T data ) where T : struct + { + unsafe + { + Interop.CopyInline( (void*)destination, ref data ); + } + } + + /// + /// Writes the specified T data to a memory location. + /// + /// Type of a data to write + /// Memory location to write to. + /// The data to write. + /// destination pointer + sizeof(T) + public static IntPtr WriteAndPosition( IntPtr destination, ref T data ) where T : struct + { + unsafe + { + return (IntPtr)Interop.Write( (void*)destination, ref data ); + } + } + + /// + /// Writes the specified array T[] data to a memory location. + /// + /// Type of a data to write + /// Memory location to write to. + /// The array of T data to write. + /// The offset in the array to read from. + /// The number of T element to write to the memory location + public static void Write( byte[] destination, T[] data, int offset, int count ) where T : struct + { + unsafe + { + fixed( void* pDest = destination ) + { + Write( (IntPtr)pDest, data, offset, count ); + } + } + } + + /// + /// Writes the specified array T[] data to a memory location. + /// + /// Type of a data to write + /// Memory location to write to. + /// The array of T data to write. + /// The offset in the array to read from. + /// The number of T element to write to the memory location + /// destination pointer + sizeof(T) * count + public static IntPtr Write( IntPtr destination, T[] data, int offset, int count ) where T : struct + { + unsafe + { + return (IntPtr)Interop.Write( (void*)destination, data, offset, count ); + } + } + + /// + /// Allocate an aligned memory buffer. + /// + /// Size of the buffer to allocate. + /// Alignment, a positive value which is a power of 2. 16 bytes by default. + /// A pointer to a buffer aligned. + /// + /// To free this buffer, call + /// + public static unsafe IntPtr AllocateMemory( int sizeInBytes, int align = 16 ) + { + var mask = align - 1; + if( ( align & mask ) != 0 ) + { + throw new ArgumentException( "Alignment is not power of 2", nameof( align ) ); + } + var memPtr = Marshal.AllocHGlobal(sizeInBytes + mask + sizeof(void*)); + var ptr = (byte*)((ulong)(memPtr.ToInt32() + sizeof(void*) + mask) & ~(ulong)mask); + ( (IntPtr*)ptr )[-1] = memPtr; + return new IntPtr( ptr ); + } + + /// + /// Allocate an aligned memory buffer and clear it with a specified value (0 by defaault). + /// + /// Size of the buffer to allocate. + /// Default value used to clear the buffer. + /// Alignment, 16 bytes by default. + /// A pointer to a buffer aligned. + /// + /// To free this buffer, call + /// + public static IntPtr AllocateClearedMemory( int sizeInBytes, byte clearValue = 0, int align = 16 ) + { + var ptr = AllocateMemory(sizeInBytes, align); + ClearMemory( ptr, clearValue, sizeInBytes ); + return ptr; + } + + /// + /// Determines whether the specified memory pointer is aligned in memory. + /// + /// The memory pointer. + /// The align. + /// true if the specified memory pointer is aligned in memory; otherwise, false. + public static bool IsMemoryAligned( IntPtr memoryPtr, int align = 16 ) + { + return ( memoryPtr.ToInt64() & ( align - 1 ) ) == 0; + } + + /// + /// Allocate an aligned memory buffer. + /// + /// + /// The buffer must have been allocated with + /// + public static unsafe void FreeMemory( IntPtr alignedBuffer ) + { + Marshal.FreeHGlobal( ( (IntPtr*)alignedBuffer )[-1] ); + } + + /// + /// If non-null, disposes the specified object and set it to null, otherwise do nothing. + /// + /// The disposable. + public static void Dispose( ref T disposable ) where T : class, IDisposable + { + if( disposable != null ) + { + disposable.Dispose(); + disposable = null; + } + } + + /// + /// String helper join method to display an array of object as a single string. + /// + /// The separator. + /// The array. + /// a string with array elements serparated by the seperator + [NotNull] + public static string Join( string separator, T[] array ) + { + var text = new StringBuilder(); + if( array != null ) + { + for( var i = 0; i < array.Length; i++ ) + { + if( i > 0 ) + text.Append( separator ); + text.Append( array[i] ); + } + } + return text.ToString(); + } + + /// + /// String helper join method to display an enumrable of object as a single string. + /// + /// The separator. + /// The enumerable. + /// a string with array elements serparated by the seperator + [NotNull] + public static string Join( string separator, [NotNull] IEnumerable elements ) + { + var elementList = new List(); + foreach( var element in elements ) + elementList.Add( element.ToString() ); + + var text = new StringBuilder(); + for( var i = 0; i < elementList.Count; i++ ) + { + var element = elementList[i]; + if( i > 0 ) + text.Append( separator ); + text.Append( element ); + } + return text.ToString(); + } + + /// + /// String helper join method to display an enumrable of object as a single string. + /// + /// The separator. + /// The enumerable. + /// a string with array elements serparated by the seperator + [NotNull] + public static string Join( string separator, [NotNull] IEnumerator elements ) + { + var elementList = new List(); + while( elements.MoveNext() ) + elementList.Add( elements.Current.ToString() ); + + var text = new StringBuilder(); + for( var i = 0; i < elementList.Count; i++ ) + { + var element = elementList[i]; + if( i > 0 ) + text.Append( separator ); + text.Append( element ); + } + return text.ToString(); + } + + /// + /// Read stream to a byte[] buffer + /// + /// input stream + /// a byte[] buffer + [NotNull] + public static byte[] ReadStream( [NotNull] Stream stream ) + { + var readLength = 0; + return ReadStream( stream, ref readLength ); + } + + /// + /// Read stream to a byte[] buffer + /// + /// input stream + /// length to read + /// a byte[] buffer + [NotNull] + public static byte[] ReadStream( [NotNull] Stream stream, ref int readLength ) + { + System.Diagnostics.Debug.Assert( stream != null ); + System.Diagnostics.Debug.Assert( stream.CanRead ); + var num = readLength; + System.Diagnostics.Debug.Assert( num <= ( stream.Length - stream.Position ) ); + if( num == 0 ) + readLength = (int)( stream.Length - stream.Position ); + num = readLength; + + System.Diagnostics.Debug.Assert( num >= 0 ); + if( num == 0 ) + return new byte[0]; + + var buffer = new byte[num]; + var bytesRead = 0; + if( num > 0 ) + { + do + { + bytesRead += stream.Read( buffer, bytesRead, readLength - bytesRead ); + } while( bytesRead < readLength ); + } + return buffer; + } + + /// + /// Computes a hashcode for a dictionary. + /// + /// Hashcode for the list. + public static int GetHashCode( IDictionary dict ) + { + if( dict == null ) + return 0; + + var hashCode = 0; + foreach( DictionaryEntry keyValue in dict ) + { + hashCode = ( hashCode * 397 ) ^ keyValue.Key.GetHashCode(); + hashCode = ( hashCode * 397 ) ^ ( keyValue.Value?.GetHashCode() ?? 0 ); + } + return hashCode; + } + + /// + /// Computes a hashcode for an enumeration + /// + /// An enumerator. + /// Hashcode for the list. + public static int GetHashCode( IEnumerable it ) + { + if( it == null ) + return 0; + + var hashCode = 0; + foreach( var current in it ) + { + hashCode = ( hashCode * 397 ) ^ ( current?.GetHashCode() ?? 0 ); + } + return hashCode; + } + + /// + /// Computes a hashcode for an enumeration + /// + /// An enumerator. + /// Hashcode for the list. + public static int GetHashCode( IEnumerator it ) + { + if( it == null ) + return 0; + + var hashCode = 0; + while( it.MoveNext() ) + { + var current = it.Current; + hashCode = ( hashCode * 397 ) ^ ( current?.GetHashCode() ?? 0 ); + } + return hashCode; + } + + /// + /// Compares two collection, element by elements. + /// + /// A "from" enumerator. + /// A "to" enumerator. + /// True if lists are identical. False otherwise. + public static bool Compare( IEnumerable left, IEnumerable right ) + { + if( ReferenceEquals( left, right ) ) + return true; + if( ReferenceEquals( left, null ) || ReferenceEquals( right, null ) ) + return false; + + return Compare( left.GetEnumerator(), right.GetEnumerator() ); + } + + /// + /// Compares two collection, element by elements. + /// + /// A "from" enumerator. + /// A "to" enumerator. + /// True if lists are identical. False otherwise. + public static bool Compare( IEnumerator leftIt, IEnumerator rightIt ) + { + if( ReferenceEquals( leftIt, rightIt ) ) + return true; + if( ReferenceEquals( leftIt, null ) || ReferenceEquals( rightIt, null ) ) + return false; + + bool hasLeftNext; + bool hasRightNext; + while( true ) + { + hasLeftNext = leftIt.MoveNext(); + hasRightNext = rightIt.MoveNext(); + if( !hasLeftNext || !hasRightNext ) + break; + + if( !Equals( leftIt.Current, rightIt.Current ) ) + return false; + } + + // If there is any left element + if( hasLeftNext != hasRightNext ) + return false; + + return true; + } + + /// + /// Compares two collection, element by elements. + /// + /// The collection to compare from. + /// The colllection to compare to. + /// True if lists are identical (but no necessarely of the same time). False otherwise. + public static bool Compare( IDictionary first, IDictionary second ) + { + if( ReferenceEquals( first, second ) ) + return true; + if( ReferenceEquals( first, null ) || ReferenceEquals( second, null ) ) + return false; + if( first.Count != second.Count ) + return false; + + var comparer = EqualityComparer.Default; + + foreach( var keyValue in first ) + { + TValue secondValue; + if( !second.TryGetValue( keyValue.Key, out secondValue ) ) + return false; + if( !comparer.Equals( keyValue.Value, secondValue ) ) + return false; + } + + // Check that all keys in second are in first + return second.Keys.All( first.ContainsKey ); + } + + public static bool Compare( T[] left, T[] right ) + { + if( ReferenceEquals( left, right ) ) + return true; + if( ReferenceEquals( left, null ) || ReferenceEquals( right, null ) ) + return false; + + if( left.Length != right.Length ) + return false; + + var comparer = EqualityComparer.Default; + for( var i = 0; i < left.Length; ++i ) + { + if( !comparer.Equals( left[i], right[i] ) ) + return false; + } + + return true; + } + + /// + /// Compares two collection, element by elements. + /// + /// The collection to compare from. + /// The colllection to compare to. + /// True if lists are identical (but no necessarely of the same time). False otherwise. + public static bool Compare( ICollection left, ICollection right ) + { + if( ReferenceEquals( left, right ) ) + return true; + if( ReferenceEquals( left, null ) || ReferenceEquals( right, null ) ) + return false; + + if( left.Count != right.Count ) + return false; + + var count = 0; + var leftIt = left.GetEnumerator(); + var rightIt = right.GetEnumerator(); + var comparer = EqualityComparer.Default; + while( leftIt.MoveNext() && rightIt.MoveNext() ) + { + if( !comparer.Equals( leftIt.Current, rightIt.Current ) ) + return false; + count++; + } + + // Just double check to make sure that the iterator actually returns + // the exact number of elements + if( count != left.Count ) + return false; + + return true; + } + + /// + /// Swaps the value between two references. + /// + /// Type of a data to swap. + /// The left value. + /// The right value. + public static void Swap( ref T left, ref T right ) + { + var temp = left; + left = right; + right = temp; + } + + /// + /// Suspends current thread for a . + /// + /// The duration of sleep. + public static void Sleep( TimeSpan sleepTime ) + { + var ms = (long)sleepTime.TotalMilliseconds; + if( ms < 0 || ms > int.MaxValue ) + { + throw new ArgumentOutOfRangeException( nameof( sleepTime ), "Sleep time must be a duration less than '2^31 - 1' milliseconds." ); + } + // MH PORTED NativeInvoke.Sleep((int)ms); + Thread.Sleep( (int)ms ); + } + + /// + /// Suspends current thread for a . + /// + /// The duration of sleep in milliseconds. + public static void Sleep( int sleepTimeInMillis ) + { + // MH PORTED NativeInvoke.Sleep(sleepTimeInMillis); + Thread.Sleep( sleepTimeInMillis ); + } + + /// + /// Writes the specified T data to a memory location. + /// + /// Type of a data to write + /// Memory location to write to. + /// The data to write. + internal static void UnsafeWrite( IntPtr destination, ref T data ) + { + unsafe + { + Interop.CopyInline( (void*)destination, ref data ); + } + } + + /// + /// Reads the specified T data from a memory location. + /// + /// Type of a data to read + /// Memory location to read from. + /// The data write to. + internal static void UnsafeReadOut( IntPtr source, out T data ) + { + unsafe + { + Interop.CopyInlineOut( out data, (void*)source ); + } + } + + /// + /// Return the sizeof a struct from a CLR. Equivalent to sizeof operator but works on generics too. + /// + /// a struct to evaluate + /// sizeof this struct + internal static int UnsafeSizeOf() + { + return Interop.SizeOf(); + } + + /// + /// Linq assisted full tree iteration and collection in a single line. + /// Warning, could be slow. + /// + /// The type to iterate. + /// The root item + /// The function to retrieve a child + public static IEnumerable IterateTree( T root, Func> childrenF ) + { + var q = new List { root }; + while( q.Any() ) + { + var c = q[0]; + q.RemoveAt( 0 ); + q.AddRange( childrenF( c ) ?? Enumerable.Empty() ); + yield return c; + } + } + + /// + /// Converts a raw time to a . + /// + /// The delta. + /// The . + public static TimeSpan ConvertRawToTimestamp( long delta ) + { + return new TimeSpan( delta == 0 ? 0 : ( delta * TimeSpan.TicksPerSecond ) / Stopwatch.Frequency ); + } + } +} diff --git a/ar/AdaptiveArithmeticCompress.cs b/ar/AdaptiveArithmeticCompress.cs index 337fe8e..dbc9013 100644 --- a/ar/AdaptiveArithmeticCompress.cs +++ b/ar/AdaptiveArithmeticCompress.cs @@ -1,73 +1,73 @@ -using System; -using System.IO; - -/* - * Reference arithmetic coding - * Copyright (c) Project Nayuki - * - * https://www.nayuki.io/page/reference-arithmetic-coding - * https://github.com/nayuki/Reference-arithmetic-coding - */ - - - -/// -/// Compression application using adaptive arithmetic coding. -/// Usage: java AdaptiveArithmeticCompress InputFile OutputFile -/// Then use the corresponding "AdaptiveArithmeticDecompress" application to recreate the original input file. -/// Note that the application starts with a flat frequency table of 257 symbols (all set to a frequency of 1), -/// and updates it after each byte encoded. The corresponding decompressor program also starts with a flat -/// frequency table and updates it after each byte decoded. It is by design that the compressor and -/// decompressor have synchronized states, so that the data can be decompressed properly. -/// -public class AdaptiveArithmeticCompress -{ - -//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: -//ORIGINAL LINE: public static void main(String[] args) throws java.io.IOException - public static void Main(string[] args) - { - /* @@@@ PORT - // Handle command line arguments - if (args.Length != 2) - { - Console.Error.WriteLine("Usage: java AdaptiveArithmeticCompress InputFile OutputFile"); - Environment.Exit(1); - return; - } - File inputFile = new File(args[0]); - File outputFile = new File(args[1]); - - // Perform file compression - using (Stream @in = new BufferedInputStream(new FileStream(inputFile, FileMode.Open, FileAccess.Read)), BitOutputStream @out = new BitOutputStream(new BufferedOutputStream(new FileStream(outputFile, FileMode.Create, FileAccess.Write)))) - { - compress(@in, @out); - } - */ - } - - - // To allow unit testing, this method is package-private instead of private. -//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: -//ORIGINAL LINE: static void compress(java.io.InputStream in, BitOutputStream out) throws java.io.IOException - internal static void compress(Stream @in, BitOutputStream @out) - { - FlatFrequencyTable initFreqs = new FlatFrequencyTable(257); - FrequencyTable freqs = new SimpleFrequencyTable(initFreqs); - ArithmeticEncoder enc = new ArithmeticEncoder(32, @out); - while (true) - { - // Read and encode one byte - int symbol = @in.ReadByte(); - if (symbol == -1) - { - break; - } - enc.write(freqs, symbol); - freqs.increment(symbol); - } - enc.write(freqs, 256); // EOF - enc.finish(); // Flush remaining code bits - } - -} +using System; +using System.IO; + +/* + * Reference arithmetic coding + * Copyright (c) Project Nayuki + * + * https://www.nayuki.io/page/reference-arithmetic-coding + * https://github.com/nayuki/Reference-arithmetic-coding + */ + + + +/// +/// Compression application using adaptive arithmetic coding. +/// Usage: java AdaptiveArithmeticCompress InputFile OutputFile +/// Then use the corresponding "AdaptiveArithmeticDecompress" application to recreate the original input file. +/// Note that the application starts with a flat frequency table of 257 symbols (all set to a frequency of 1), +/// and updates it after each byte encoded. The corresponding decompressor program also starts with a flat +/// frequency table and updates it after each byte decoded. It is by design that the compressor and +/// decompressor have synchronized states, so that the data can be decompressed properly. +/// +public class AdaptiveArithmeticCompress +{ + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: +//ORIGINAL LINE: public static void main(String[] args) throws java.io.IOException + public static void Main(string[] args) + { + /* @@@@ PORT + // Handle command line arguments + if (args.Length != 2) + { + Console.Error.WriteLine("Usage: java AdaptiveArithmeticCompress InputFile OutputFile"); + Environment.Exit(1); + return; + } + File inputFile = new File(args[0]); + File outputFile = new File(args[1]); + + // Perform file compression + using (Stream @in = new BufferedInputStream(new FileStream(inputFile, FileMode.Open, FileAccess.Read)), BitOutputStream @out = new BitOutputStream(new BufferedOutputStream(new FileStream(outputFile, FileMode.Create, FileAccess.Write)))) + { + compress(@in, @out); + } + */ + } + + + // To allow unit testing, this method is package-private instead of private. +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: +//ORIGINAL LINE: static void compress(java.io.InputStream in, BitOutputStream out) throws java.io.IOException + internal static void compress(Stream @in, BitOutputStream @out) + { + FlatFrequencyTable initFreqs = new FlatFrequencyTable(257); + FrequencyTable freqs = new SimpleFrequencyTable(initFreqs); + ArithmeticEncoder enc = new ArithmeticEncoder(32, @out); + while (true) + { + // Read and encode one byte + int symbol = @in.ReadByte(); + if (symbol == -1) + { + break; + } + enc.write(freqs, symbol); + freqs.increment(symbol); + } + enc.write(freqs, 256); // EOF + enc.finish(); // Flush remaining code bits + } + +} diff --git a/ar/AdaptiveArithmeticDecompress.cs b/ar/AdaptiveArithmeticDecompress.cs index 3bb4208..2959e77 100644 --- a/ar/AdaptiveArithmeticDecompress.cs +++ b/ar/AdaptiveArithmeticDecompress.cs @@ -1,67 +1,67 @@ -using System; -using System.IO; - -/* - * Reference arithmetic coding - * Copyright (c) Project Nayuki - * - * https://www.nayuki.io/page/reference-arithmetic-coding - * https://github.com/nayuki/Reference-arithmetic-coding - */ - - - -/// -/// Decompression application using adaptive arithmetic coding. -/// Usage: java AdaptiveArithmeticDecompress InputFile OutputFile -/// This decompresses files generated by the "AdaptiveArithmeticCompress" application. -/// -public class AdaptiveArithmeticDecompress -{ - -//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: -//ORIGINAL LINE: public static void main(String[] args) throws java.io.IOException - public static void Main(string[] args) - { - /* @@@@ PORT - // Handle command line arguments - if (args.Length != 2) - { - Console.Error.WriteLine("Usage: java AdaptiveArithmeticDecompress InputFile OutputFile"); - Environment.Exit(1); - return; - } - File inputFile = new File(args[0]); - File outputFile = new File(args[1]); - - // Perform file decompression - using (BitInputStream @in = new BitInputStream(new BufferedInputStream(new FileStream(inputFile, FileMode.Open, FileAccess.Read))), Stream @out = new BufferedOutputStream(new FileStream(outputFile, FileMode.Create, FileAccess.Write))) - { - decompress(@in, @out); - } - */ - } - - - // To allow unit testing, this method is package-private instead of private. -//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: -//ORIGINAL LINE: static void decompress(BitInputStream in, java.io.OutputStream out) throws java.io.IOException - internal static void decompress(BitInputStream @in, Stream @out) - { - FlatFrequencyTable initFreqs = new FlatFrequencyTable(257); - FrequencyTable freqs = new SimpleFrequencyTable(initFreqs); - ArithmeticDecoder dec = new ArithmeticDecoder(32, @in); - while (true) - { - // Decode and write one byte - int symbol = dec.read(freqs); - if (symbol == 256) // EOF symbol - { - break; - } - @out.WriteByte((byte)symbol); - freqs.increment(symbol); - } - } - -} +using System; +using System.IO; + +/* + * Reference arithmetic coding + * Copyright (c) Project Nayuki + * + * https://www.nayuki.io/page/reference-arithmetic-coding + * https://github.com/nayuki/Reference-arithmetic-coding + */ + + + +/// +/// Decompression application using adaptive arithmetic coding. +/// Usage: java AdaptiveArithmeticDecompress InputFile OutputFile +/// This decompresses files generated by the "AdaptiveArithmeticCompress" application. +/// +public class AdaptiveArithmeticDecompress +{ + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: +//ORIGINAL LINE: public static void main(String[] args) throws java.io.IOException + public static void Main(string[] args) + { + /* @@@@ PORT + // Handle command line arguments + if (args.Length != 2) + { + Console.Error.WriteLine("Usage: java AdaptiveArithmeticDecompress InputFile OutputFile"); + Environment.Exit(1); + return; + } + File inputFile = new File(args[0]); + File outputFile = new File(args[1]); + + // Perform file decompression + using (BitInputStream @in = new BitInputStream(new BufferedInputStream(new FileStream(inputFile, FileMode.Open, FileAccess.Read))), Stream @out = new BufferedOutputStream(new FileStream(outputFile, FileMode.Create, FileAccess.Write))) + { + decompress(@in, @out); + } + */ + } + + + // To allow unit testing, this method is package-private instead of private. +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: +//ORIGINAL LINE: static void decompress(BitInputStream in, java.io.OutputStream out) throws java.io.IOException + internal static void decompress(BitInputStream @in, Stream @out) + { + FlatFrequencyTable initFreqs = new FlatFrequencyTable(257); + FrequencyTable freqs = new SimpleFrequencyTable(initFreqs); + ArithmeticDecoder dec = new ArithmeticDecoder(32, @in); + while (true) + { + // Decode and write one byte + int symbol = dec.read(freqs); + if (symbol == 256) // EOF symbol + { + break; + } + @out.WriteByte((byte)symbol); + freqs.increment(symbol); + } + } + +} diff --git a/ar/ArithmeticCoderBase.cs b/ar/ArithmeticCoderBase.cs index 4c30f35..9761cd6 100644 --- a/ar/ArithmeticCoderBase.cs +++ b/ar/ArithmeticCoderBase.cs @@ -1,185 +1,185 @@ -using System; -using System.Diagnostics; - -/* - * Reference arithmetic coding - * Copyright (c) Project Nayuki - * - * https://www.nayuki.io/page/reference-arithmetic-coding - * https://github.com/nayuki/Reference-arithmetic-coding - */ - - -/// -/// Provides the state and behaviors that arithmetic coding encoders and decoders share. -/// -/// -public abstract class ArithmeticCoderBase -{ - - /*---- Configuration fields ----*/ - - /// - /// Number of bits for the 'low' and 'high' state variables. Must be in the range [1, 62]. - ///
    - ///
  • For state sizes less than the midpoint of around 32, larger values are generally better - - /// they allow a larger maximum frequency total (maximumTotal), and they reduce the approximation - /// error inherent in adapting fractions to integers; both effects reduce the data encoding loss - /// and asymptotically approach the efficiency of arithmetic coding using exact fractions.
  • - ///
  • But for state sizes greater than the midpoint, because intermediate computations are limited - /// to the long integer type's 63-bit unsigned precision, larger state sizes will decrease the - /// maximum frequency total, which might constrain the user-supplied probability model.
  • - ///
  • Therefore numStateBits=32 is recommended as the most versatile setting - /// because it maximizes maximumTotal (which ends up being slightly over 2^30).
  • - ///
  • Note that numStateBits=62 is legal but useless because it implies maximumTotal=1, - /// which means a frequency table can only support one symbol with non-zero frequency.
  • - ///
- ///
- protected internal readonly int numStateBits; - - /// - /// Maximum range (high+1-low) during coding (trivial), which is 2^numStateBits = 1000...000. - protected internal readonly long fullRange; - - /// - /// The top bit at width numStateBits, which is 0100...000. - protected internal readonly long halfRange; - - /// - /// The second highest bit at width numStateBits, which is 0010...000. This is zero when numStateBits=1. - protected internal readonly long quarterRange; - - /// - /// Minimum range (high+1-low) during coding (non-trivial), which is 0010...010. - protected internal readonly long minimumRange; - - /// - /// Maximum allowed total from a frequency table at all times during coding. - protected internal readonly long maximumTotal; - - /// - /// Bit mask of numStateBits ones, which is 0111...111. - protected internal readonly long stateMask; - - - - /*---- State fields ----*/ - - /// - /// Low end of this arithmetic coder's current range. Conceptually has an infinite number of trailing 0s. - /// - protected internal long low; - - /// - /// High end of this arithmetic coder's current range. Conceptually has an infinite number of trailing 1s. - /// - protected internal long high; - - - - /*---- Constructor ----*/ - - /// - /// Constructs an arithmetic coder, which initializes the code range. - /// the number of bits for the arithmetic coding range - /// if stateSize is outside the range [1, 62] - public ArithmeticCoderBase(int numBits) - { - if (numBits < 1 || numBits > 62) - { - throw new System.ArgumentException("State size out of range"); - } - numStateBits = numBits; - fullRange = 1L << numStateBits; - halfRange = (long)((ulong)fullRange >> 1); // Non-zero - quarterRange = (long)((ulong)halfRange >> 1); // Can be zero - minimumRange = quarterRange + 2; // At least 2 - maximumTotal = Math.Min(long.MaxValue / fullRange, minimumRange); - stateMask = fullRange - 1; - - low = 0; - high = stateMask; - } - - - - /*---- Methods ----*/ - - /// - /// Updates the code range (low and high) of this arithmetic coder as a result - /// of processing the specified symbol with the specified frequency table. - /// Invariants that are true before and after encoding/decoding each symbol - /// (letting fullRange = 2numStateBits): - ///
    - ///
  • 0 ≤ low ≤ code ≤ high < fullRange. ('code' exists only in the decoder.) - /// Therefore these variables are unsigned integers of numStateBits bits.
  • - ///
  • low < 1/2 × fullRange ≤ high. - /// In other words, they are in different halves of the full range.
  • - ///
  • (low < 1/4 × fullRange) || (high ≥ 3/4 × fullRange). - /// In other words, they are not both in the middle two quarters.
  • - ///
  • Let range = high − low + 1, then fullRange/4 < minimumRange ≤ range ≤ - /// fullRange. These invariants for 'range' essentially dictate the maximum total that the - /// incoming frequency table can have, such that intermediate calculations don't overflow.
  • - ///
- /// the frequency table to use - /// the symbol that was processed - /// if the symbol has zero frequency or the frequency table's total is too large -//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: -//ORIGINAL LINE: protected void update(CheckedFrequencyTable freqs, int symbol) throws java.io.IOException - protected internal virtual void update(CheckedFrequencyTable freqs, int symbol) - { - // State check - Debug.Assert(low >= high || (low & stateMask) != low || (high & stateMask) != high, "Low or high out of range"); - - long range = high - low + 1; - Debug.Assert(range < minimumRange || range > fullRange, "Range out of range"); - - // Frequency table values check - long total = freqs.Total; - long symLow = freqs.getLow(symbol); - long symHigh = freqs.getHigh(symbol); - Debug.Assert( symLow == symHigh, "Symbol has zero frequency"); - - Debug.Assert( total > maximumTotal, "Cannot code symbol because total is too large"); - - // Update range - long newLow = low + symLow * range / total; - long newHigh = low + symHigh * range / total - 1; - low = newLow; - high = newHigh; - - // While low and high have the same top bit value, shift them out - while (((low ^ high) & halfRange) == 0) - { - shift(); - low = ((low << 1) & stateMask); - high = ((high << 1) & stateMask) | 1; - } - // Now low's top bit must be 0 and high's top bit must be 1 - - // While low's top two bits are 01 and high's are 10, delete the second highest bit of both - while ((low & ~high & quarterRange) != 0) - { - underflow(); - low = (low << 1) ^ halfRange; - high = ((high ^ halfRange) << 1) | halfRange | 1; - } - } - - - /// - /// Called to handle the situation when the top bit of {@code low} and {@code high} are equal. - /// if an I/O exception occurred -//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: -//ORIGINAL LINE: protected abstract void shift() throws java.io.IOException; - protected internal abstract void shift(); - - - /// - /// Called to handle the situation when low=01(...) and high=10(...). - /// if an I/O exception occurred -//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: -//ORIGINAL LINE: protected abstract void underflow() throws java.io.IOException; - protected internal abstract void underflow(); - -} +using System; +using System.Diagnostics; + +/* + * Reference arithmetic coding + * Copyright (c) Project Nayuki + * + * https://www.nayuki.io/page/reference-arithmetic-coding + * https://github.com/nayuki/Reference-arithmetic-coding + */ + + +/// +/// Provides the state and behaviors that arithmetic coding encoders and decoders share. +/// +/// +public abstract class ArithmeticCoderBase +{ + + /*---- Configuration fields ----*/ + + /// + /// Number of bits for the 'low' and 'high' state variables. Must be in the range [1, 62]. + ///
    + ///
  • For state sizes less than the midpoint of around 32, larger values are generally better - + /// they allow a larger maximum frequency total (maximumTotal), and they reduce the approximation + /// error inherent in adapting fractions to integers; both effects reduce the data encoding loss + /// and asymptotically approach the efficiency of arithmetic coding using exact fractions.
  • + ///
  • But for state sizes greater than the midpoint, because intermediate computations are limited + /// to the long integer type's 63-bit unsigned precision, larger state sizes will decrease the + /// maximum frequency total, which might constrain the user-supplied probability model.
  • + ///
  • Therefore numStateBits=32 is recommended as the most versatile setting + /// because it maximizes maximumTotal (which ends up being slightly over 2^30).
  • + ///
  • Note that numStateBits=62 is legal but useless because it implies maximumTotal=1, + /// which means a frequency table can only support one symbol with non-zero frequency.
  • + ///
+ ///
+ protected internal readonly int numStateBits; + + /// + /// Maximum range (high+1-low) during coding (trivial), which is 2^numStateBits = 1000...000. + protected internal readonly long fullRange; + + /// + /// The top bit at width numStateBits, which is 0100...000. + protected internal readonly long halfRange; + + /// + /// The second highest bit at width numStateBits, which is 0010...000. This is zero when numStateBits=1. + protected internal readonly long quarterRange; + + /// + /// Minimum range (high+1-low) during coding (non-trivial), which is 0010...010. + protected internal readonly long minimumRange; + + /// + /// Maximum allowed total from a frequency table at all times during coding. + protected internal readonly long maximumTotal; + + /// + /// Bit mask of numStateBits ones, which is 0111...111. + protected internal readonly long stateMask; + + + + /*---- State fields ----*/ + + /// + /// Low end of this arithmetic coder's current range. Conceptually has an infinite number of trailing 0s. + /// + protected internal long low; + + /// + /// High end of this arithmetic coder's current range. Conceptually has an infinite number of trailing 1s. + /// + protected internal long high; + + + + /*---- Constructor ----*/ + + /// + /// Constructs an arithmetic coder, which initializes the code range. + /// the number of bits for the arithmetic coding range + /// if stateSize is outside the range [1, 62] + public ArithmeticCoderBase(int numBits) + { + if (numBits < 1 || numBits > 62) + { + throw new System.ArgumentException("State size out of range"); + } + numStateBits = numBits; + fullRange = 1L << numStateBits; + halfRange = (long)((ulong)fullRange >> 1); // Non-zero + quarterRange = (long)((ulong)halfRange >> 1); // Can be zero + minimumRange = quarterRange + 2; // At least 2 + maximumTotal = Math.Min(long.MaxValue / fullRange, minimumRange); + stateMask = fullRange - 1; + + low = 0; + high = stateMask; + } + + + + /*---- Methods ----*/ + + /// + /// Updates the code range (low and high) of this arithmetic coder as a result + /// of processing the specified symbol with the specified frequency table. + /// Invariants that are true before and after encoding/decoding each symbol + /// (letting fullRange = 2numStateBits): + ///
    + ///
  • 0 ≤ low ≤ code ≤ high < fullRange. ('code' exists only in the decoder.) + /// Therefore these variables are unsigned integers of numStateBits bits.
  • + ///
  • low < 1/2 × fullRange ≤ high. + /// In other words, they are in different halves of the full range.
  • + ///
  • (low < 1/4 × fullRange) || (high ≥ 3/4 × fullRange). + /// In other words, they are not both in the middle two quarters.
  • + ///
  • Let range = high − low + 1, then fullRange/4 < minimumRange ≤ range ≤ + /// fullRange. These invariants for 'range' essentially dictate the maximum total that the + /// incoming frequency table can have, such that intermediate calculations don't overflow.
  • + ///
+ /// the frequency table to use + /// the symbol that was processed + /// if the symbol has zero frequency or the frequency table's total is too large +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: +//ORIGINAL LINE: protected void update(CheckedFrequencyTable freqs, int symbol) throws java.io.IOException + protected internal virtual void update(CheckedFrequencyTable freqs, int symbol) + { + // State check + Debug.Assert(low >= high || (low & stateMask) != low || (high & stateMask) != high, "Low or high out of range"); + + long range = high - low + 1; + Debug.Assert(range < minimumRange || range > fullRange, "Range out of range"); + + // Frequency table values check + long total = freqs.Total; + long symLow = freqs.getLow(symbol); + long symHigh = freqs.getHigh(symbol); + Debug.Assert( symLow == symHigh, "Symbol has zero frequency"); + + Debug.Assert( total > maximumTotal, "Cannot code symbol because total is too large"); + + // Update range + long newLow = low + symLow * range / total; + long newHigh = low + symHigh * range / total - 1; + low = newLow; + high = newHigh; + + // While low and high have the same top bit value, shift them out + while (((low ^ high) & halfRange) == 0) + { + shift(); + low = ((low << 1) & stateMask); + high = ((high << 1) & stateMask) | 1; + } + // Now low's top bit must be 0 and high's top bit must be 1 + + // While low's top two bits are 01 and high's are 10, delete the second highest bit of both + while ((low & ~high & quarterRange) != 0) + { + underflow(); + low = (low << 1) ^ halfRange; + high = ((high ^ halfRange) << 1) | halfRange | 1; + } + } + + + /// + /// Called to handle the situation when the top bit of {@code low} and {@code high} are equal. + /// if an I/O exception occurred +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: +//ORIGINAL LINE: protected abstract void shift() throws java.io.IOException; + protected internal abstract void shift(); + + + /// + /// Called to handle the situation when low=01(...) and high=10(...). + /// if an I/O exception occurred +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: +//ORIGINAL LINE: protected abstract void underflow() throws java.io.IOException; + protected internal abstract void underflow(); + +} diff --git a/ar/ArithmeticCompress.cs b/ar/ArithmeticCompress.cs index 34c81d6..c839063 100644 --- a/ar/ArithmeticCompress.cs +++ b/ar/ArithmeticCompress.cs @@ -1,127 +1,127 @@ -using System; -using System.IO; - -/* - * Reference arithmetic coding - * Copyright (c) Project Nayuki - * - * https://www.nayuki.io/page/reference-arithmetic-coding - * https://github.com/nayuki/Reference-arithmetic-coding - */ - - - -/// -/// Compression application using static arithmetic coding. -/// Usage: java ArithmeticCompress InputFile OutputFile -/// Then use the corresponding "ArithmeticDecompress" application to recreate the original input file. -/// Note that the application uses an alphabet of 257 symbols - 256 symbols for the byte -/// values and 1 symbol for the EOF marker. The compressed file format starts with a list -/// of 256 symbol frequencies, and then followed by the arithmetic-coded data. -/// -public class ArithmeticCompress -{ - -//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: -//ORIGINAL LINE: public static void main(String[] args) throws java.io.IOException - public static void Main(string[] args) - { - /* @@ PORT - // Handle command line arguments - if (args.Length != 2) - { - Console.Error.WriteLine("Usage: java ArithmeticCompress InputFile OutputFile"); - Environment.Exit(1); - return; - } - File inputFile = new File(args[0]); - File outputFile = new File(args[1]); - - // Read input file once to compute symbol frequencies - FrequencyTable freqs = getFrequencies(inputFile); - freqs.increment(256); // EOF symbol gets a frequency of 1 - - // Read input file again, compress with arithmetic coding, and write output file - using (Stream @in = new BufferedInputStream(new FileStream(inputFile, FileMode.Open, FileAccess.Read)), BitOutputStream @out = new BitOutputStream(new BufferedOutputStream(new FileStream(outputFile, FileMode.Create, FileAccess.Write)))) - { - writeFrequencies(@out, freqs); - compress(freqs, @in, @out); - } - */ - } - - - // Returns a frequency table based on the bytes in the given file. - // Also contains an extra entry for symbol 256, whose frequency is set to 0. -//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: -//ORIGINAL LINE: private static FrequencyTable getFrequencies(java.io.File file) throws java.io.IOException - private static FrequencyTable getFrequencies(string file) - { - - - FrequencyTable freqs = new SimpleFrequencyTable(new int[257]); - using (Stream input = new BufferedStream( new FileStream(file, FileMode.Open, FileAccess.Read))) - { - while (true) - { - int b = input.ReadByte(); - if (b == -1) - { - break; - } - freqs.increment(b); - } - } - return freqs; - } - - - // To allow unit testing, this method is package-private instead of private. -//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: -//ORIGINAL LINE: static void writeFrequencies(BitOutputStream out, FrequencyTable freqs) throws java.io.IOException - internal static void writeFrequencies(BitOutputStream @out, FrequencyTable freqs) - { - for (int i = 0; i < 256; i++) - { - writeInt(@out, 32, freqs.get(i)); - } - } - - - // To allow unit testing, this method is package-private instead of private. -//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: -//ORIGINAL LINE: static void compress(FrequencyTable freqs, java.io.InputStream in, BitOutputStream out) throws java.io.IOException - internal static void compress(FrequencyTable freqs, Stream @in, BitOutputStream @out) - { - ArithmeticEncoder enc = new ArithmeticEncoder(32, @out); - while (true) - { - int symbol = @in.ReadByte(); - if (symbol == -1) - { - break; - } - enc.write(freqs, symbol); - } - enc.write(freqs, 256); // EOF - enc.finish(); // Flush remaining code bits - } - - - // Writes an unsigned integer of the given bit width to the given stream. -//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: -//ORIGINAL LINE: private static void writeInt(BitOutputStream out, int numBits, int value) throws java.io.IOException - private static void writeInt(BitOutputStream @out, int numBits, int value) - { - if (numBits < 0 || numBits > 32) - { - throw new System.ArgumentException(); - } - - for (int i = numBits - 1; i >= 0; i--) - { - @out.write(((int)((uint)value >> i)) & 1); // Big endian - } - } - -} +using System; +using System.IO; + +/* + * Reference arithmetic coding + * Copyright (c) Project Nayuki + * + * https://www.nayuki.io/page/reference-arithmetic-coding + * https://github.com/nayuki/Reference-arithmetic-coding + */ + + + +/// +/// Compression application using static arithmetic coding. +/// Usage: java ArithmeticCompress InputFile OutputFile +/// Then use the corresponding "ArithmeticDecompress" application to recreate the original input file. +/// Note that the application uses an alphabet of 257 symbols - 256 symbols for the byte +/// values and 1 symbol for the EOF marker. The compressed file format starts with a list +/// of 256 symbol frequencies, and then followed by the arithmetic-coded data. +/// +public class ArithmeticCompress +{ + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: +//ORIGINAL LINE: public static void main(String[] args) throws java.io.IOException + public static void Main(string[] args) + { + /* @@ PORT + // Handle command line arguments + if (args.Length != 2) + { + Console.Error.WriteLine("Usage: java ArithmeticCompress InputFile OutputFile"); + Environment.Exit(1); + return; + } + File inputFile = new File(args[0]); + File outputFile = new File(args[1]); + + // Read input file once to compute symbol frequencies + FrequencyTable freqs = getFrequencies(inputFile); + freqs.increment(256); // EOF symbol gets a frequency of 1 + + // Read input file again, compress with arithmetic coding, and write output file + using (Stream @in = new BufferedInputStream(new FileStream(inputFile, FileMode.Open, FileAccess.Read)), BitOutputStream @out = new BitOutputStream(new BufferedOutputStream(new FileStream(outputFile, FileMode.Create, FileAccess.Write)))) + { + writeFrequencies(@out, freqs); + compress(freqs, @in, @out); + } + */ + } + + + // Returns a frequency table based on the bytes in the given file. + // Also contains an extra entry for symbol 256, whose frequency is set to 0. +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: +//ORIGINAL LINE: private static FrequencyTable getFrequencies(java.io.File file) throws java.io.IOException + private static FrequencyTable getFrequencies(string file) + { + + + FrequencyTable freqs = new SimpleFrequencyTable(new int[257]); + using (Stream input = new BufferedStream( new FileStream(file, FileMode.Open, FileAccess.Read))) + { + while (true) + { + int b = input.ReadByte(); + if (b == -1) + { + break; + } + freqs.increment(b); + } + } + return freqs; + } + + + // To allow unit testing, this method is package-private instead of private. +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: +//ORIGINAL LINE: static void writeFrequencies(BitOutputStream out, FrequencyTable freqs) throws java.io.IOException + internal static void writeFrequencies(BitOutputStream @out, FrequencyTable freqs) + { + for (int i = 0; i < 256; i++) + { + writeInt(@out, 32, freqs.get(i)); + } + } + + + // To allow unit testing, this method is package-private instead of private. +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: +//ORIGINAL LINE: static void compress(FrequencyTable freqs, java.io.InputStream in, BitOutputStream out) throws java.io.IOException + internal static void compress(FrequencyTable freqs, Stream @in, BitOutputStream @out) + { + ArithmeticEncoder enc = new ArithmeticEncoder(32, @out); + while (true) + { + int symbol = @in.ReadByte(); + if (symbol == -1) + { + break; + } + enc.write(freqs, symbol); + } + enc.write(freqs, 256); // EOF + enc.finish(); // Flush remaining code bits + } + + + // Writes an unsigned integer of the given bit width to the given stream. +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: +//ORIGINAL LINE: private static void writeInt(BitOutputStream out, int numBits, int value) throws java.io.IOException + private static void writeInt(BitOutputStream @out, int numBits, int value) + { + if (numBits < 0 || numBits > 32) + { + throw new System.ArgumentException(); + } + + for (int i = numBits - 1; i >= 0; i--) + { + @out.write(((int)((uint)value >> i)) & 1); // Big endian + } + } + +} diff --git a/ar/ArithmeticDecoder.cs b/ar/ArithmeticDecoder.cs index 506e4f6..8506b02 100644 --- a/ar/ArithmeticDecoder.cs +++ b/ar/ArithmeticDecoder.cs @@ -1,152 +1,152 @@ -/* - * Reference arithmetic coding - * Copyright (c) Project Nayuki - * - * https://www.nayuki.io/page/reference-arithmetic-coding - * https://github.com/nayuki/Reference-arithmetic-coding - */ - - - -using System.Diagnostics; -/// -/// Reads from an arithmetic-coded bit stream and decodes symbols. Not thread-safe. -/// -public sealed class ArithmeticDecoder : ArithmeticCoderBase -{ - - /*---- Fields ----*/ - - // The underlying bit input stream (not null). - private BitInputStream input; - - // The current raw code bits being buffered, which is always in the range [low, high]. - private long code; - - - - /*---- Constructor ----*/ - - /// - /// Constructs an arithmetic coding decoder based on the - /// specified bit input stream, and fills the code bits. - /// the number of bits for the arithmetic coding range - /// the bit input stream to read from - /// if the input steam is {@code null} - /// if stateSize is outside the range [1, 62] - /// if an I/O exception occurred -//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: -//ORIGINAL LINE: public ArithmeticDecoder(int numBits, BitInputStream in) throws java.io.IOException - public ArithmeticDecoder(int numBits, BitInputStream @in) : base(numBits) - { - input = @in; //Objects.requireNonNull(@in); - code = 0; - for (int i = 0; i < numStateBits; i++) - { - code = code << 1 | readCodeBit(); - } - } - - - - /*---- Methods ----*/ - - /// - /// Decodes the next symbol based on the specified frequency table and returns it. - /// Also updates this arithmetic coder's state and may read in some bits. - /// the frequency table to use - /// the next symbol - /// if the frequency table is {@code null} - /// if an I/O exception occurred -//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: -//ORIGINAL LINE: public int read(FrequencyTable freqs) throws java.io.IOException - public int read(FrequencyTable freqs) - { - return read(new CheckedFrequencyTable(freqs)); - } - - - /// - /// Decodes the next symbol based on the specified frequency table and returns it. - /// Also updates this arithmetic coder's state and may read in some bits. - /// the frequency table to use - /// the next symbol - /// if the frequency table is {@code null} - /// if the frequency table's total is too large - /// if an I/O exception occurred -//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: -//ORIGINAL LINE: public int read(CheckedFrequencyTable freqs) throws java.io.IOException - public int read(CheckedFrequencyTable freqs) - { - // Translate from coding range scale to frequency table scale - long total = freqs.Total; - if (total > maximumTotal) - { - throw new System.ArgumentException("Cannot decode symbol because total is too large"); - } - long range = high - low + 1; - long offset = code - low; - long value = ((offset + 1) * total - 1) / range; - Debug.Assert(value * range / total > offset); - - Debug.Assert(value < 0 || value >= total); - - // A kind of binary search. Find highest symbol such that freqs.getLow(symbol) <= value. - int start = 0; - int end = freqs.SymbolLimit; - while (end - start > 1) - { - int middle = (int)((uint)(start + end) >> 1); - if (freqs.getLow(middle) > value) - { - end = middle; - } - else - { - start = middle; - } - } - Debug.Assert( start + 1 != end); - - - int symbol = start; - Debug.Assert(offset < freqs.getLow(symbol) * range / total || freqs.getHigh(symbol) * range / total <= offset); - - update(freqs, symbol); - Debug.Assert(code < low || code > high); - - return symbol; - } - - -//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: -//ORIGINAL LINE: protected void shift() throws java.io.IOException - protected internal override void shift() - { - code = ((code << 1) & stateMask) | readCodeBit(); - } - - -//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: -//ORIGINAL LINE: protected void underflow() throws java.io.IOException - protected internal override void underflow() - { - code = (code & halfRange) | ((code << 1) & ((long)((ulong)stateMask >> 1))) | readCodeBit(); - } - - - // Returns the next bit (0 or 1) from the input stream. The end - // of stream is treated as an infinite number of trailing zeros. -//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: -//ORIGINAL LINE: private int readCodeBit() throws java.io.IOException - private int readCodeBit() - { - int temp = input.read(); - if (temp == -1) - { - temp = 0; - } - return temp; - } - -} +/* + * Reference arithmetic coding + * Copyright (c) Project Nayuki + * + * https://www.nayuki.io/page/reference-arithmetic-coding + * https://github.com/nayuki/Reference-arithmetic-coding + */ + + + +using System.Diagnostics; +/// +/// Reads from an arithmetic-coded bit stream and decodes symbols. Not thread-safe. +/// +public sealed class ArithmeticDecoder : ArithmeticCoderBase +{ + + /*---- Fields ----*/ + + // The underlying bit input stream (not null). + private BitInputStream input; + + // The current raw code bits being buffered, which is always in the range [low, high]. + private long code; + + + + /*---- Constructor ----*/ + + /// + /// Constructs an arithmetic coding decoder based on the + /// specified bit input stream, and fills the code bits. + /// the number of bits for the arithmetic coding range + /// the bit input stream to read from + /// if the input steam is {@code null} + /// if stateSize is outside the range [1, 62] + /// if an I/O exception occurred +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: +//ORIGINAL LINE: public ArithmeticDecoder(int numBits, BitInputStream in) throws java.io.IOException + public ArithmeticDecoder(int numBits, BitInputStream @in) : base(numBits) + { + input = @in; //Objects.requireNonNull(@in); + code = 0; + for (int i = 0; i < numStateBits; i++) + { + code = code << 1 | readCodeBit(); + } + } + + + + /*---- Methods ----*/ + + /// + /// Decodes the next symbol based on the specified frequency table and returns it. + /// Also updates this arithmetic coder's state and may read in some bits. + /// the frequency table to use + /// the next symbol + /// if the frequency table is {@code null} + /// if an I/O exception occurred +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: +//ORIGINAL LINE: public int read(FrequencyTable freqs) throws java.io.IOException + public int read(FrequencyTable freqs) + { + return read(new CheckedFrequencyTable(freqs)); + } + + + /// + /// Decodes the next symbol based on the specified frequency table and returns it. + /// Also updates this arithmetic coder's state and may read in some bits. + /// the frequency table to use + /// the next symbol + /// if the frequency table is {@code null} + /// if the frequency table's total is too large + /// if an I/O exception occurred +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: +//ORIGINAL LINE: public int read(CheckedFrequencyTable freqs) throws java.io.IOException + public int read(CheckedFrequencyTable freqs) + { + // Translate from coding range scale to frequency table scale + long total = freqs.Total; + if (total > maximumTotal) + { + throw new System.ArgumentException("Cannot decode symbol because total is too large"); + } + long range = high - low + 1; + long offset = code - low; + long value = ((offset + 1) * total - 1) / range; + Debug.Assert(value * range / total > offset); + + Debug.Assert(value < 0 || value >= total); + + // A kind of binary search. Find highest symbol such that freqs.getLow(symbol) <= value. + int start = 0; + int end = freqs.SymbolLimit; + while (end - start > 1) + { + int middle = (int)((uint)(start + end) >> 1); + if (freqs.getLow(middle) > value) + { + end = middle; + } + else + { + start = middle; + } + } + Debug.Assert( start + 1 != end); + + + int symbol = start; + Debug.Assert(offset < freqs.getLow(symbol) * range / total || freqs.getHigh(symbol) * range / total <= offset); + + update(freqs, symbol); + Debug.Assert(code < low || code > high); + + return symbol; + } + + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: +//ORIGINAL LINE: protected void shift() throws java.io.IOException + protected internal override void shift() + { + code = ((code << 1) & stateMask) | readCodeBit(); + } + + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: +//ORIGINAL LINE: protected void underflow() throws java.io.IOException + protected internal override void underflow() + { + code = (code & halfRange) | ((code << 1) & ((long)((ulong)stateMask >> 1))) | readCodeBit(); + } + + + // Returns the next bit (0 or 1) from the input stream. The end + // of stream is treated as an infinite number of trailing zeros. +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: +//ORIGINAL LINE: private int readCodeBit() throws java.io.IOException + private int readCodeBit() + { + int temp = input.read(); + if (temp == -1) + { + temp = 0; + } + return temp; + } + +} diff --git a/ar/ArithmeticDecompress.cs b/ar/ArithmeticDecompress.cs index f8e45a4..7f603ec 100644 --- a/ar/ArithmeticDecompress.cs +++ b/ar/ArithmeticDecompress.cs @@ -1,99 +1,99 @@ -using System; -using System.IO; - -/* - * Reference arithmetic coding - * Copyright (c) Project Nayuki - * - * https://www.nayuki.io/page/reference-arithmetic-coding - * https://github.com/nayuki/Reference-arithmetic-coding - */ - - - -/// -/// Decompression application using static arithmetic coding. -/// Usage: java ArithmeticDecompress InputFile OutputFile -/// This decompresses files generated by the "ArithmeticCompress" application. -/// -public class ArithmeticDecompress -{ - -//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: -//ORIGINAL LINE: public static void main(String[] args) throws java.io.IOException - public static void Main(string[] args) - { - // Handle command line arguments - if (args.Length != 2) - { - Console.Error.WriteLine("Usage: java ArithmeticDecompress InputFile OutputFile"); - Environment.Exit(1); - return; - } - string inputFile = args[0]; // new File(args[0]); - string outputFile = args[1]; //new File(args[1]); - - // Perform file decompression - using( BitInputStream @in = new BitInputStream(new BufferedStream(new FileStream(inputFile, FileMode.Open, FileAccess.Read)))) - using( Stream @out = new BufferedStream(new FileStream(outputFile, FileMode.Create, FileAccess.Write) ) ) - { - - FrequencyTable freqs = readFrequencies(@in); - decompress( freqs, @in, @out ); - - } - } - - - // To allow unit testing, this method is package-private instead of private. -//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: -//ORIGINAL LINE: static FrequencyTable readFrequencies(BitInputStream in) throws java.io.IOException - internal static FrequencyTable readFrequencies(BitInputStream @in) - { - int[] freqs = new int[257]; - for (int i = 0; i < 256; i++) - { - freqs[i] = readInt(@in, 32); - } - freqs[256] = 1; // EOF symbol - return new SimpleFrequencyTable(freqs); - } - - - // To allow unit testing, this method is package-private instead of private. -//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: -//ORIGINAL LINE: static void decompress(FrequencyTable freqs, BitInputStream in, java.io.OutputStream out) throws java.io.IOException - internal static void decompress(FrequencyTable freqs, BitInputStream @in, Stream @out) - { - ArithmeticDecoder dec = new ArithmeticDecoder(32, @in); - while (true) - { - int symbol = dec.read(freqs); - if (symbol == 256) // EOF symbol - { - break; - } - @out.WriteByte((byte)symbol); - } - } - - - // Reads an unsigned integer of the given bit width from the given stream. -//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: -//ORIGINAL LINE: private static int readInt(BitInputStream in, int numBits) throws java.io.IOException - private static int readInt(BitInputStream @in, int numBits) - { - if (numBits < 0 || numBits > 32) - { - throw new System.ArgumentException(); - } - - int result = 0; - for (int i = 0; i < numBits; i++) - { - result = (result << 1) | @in.readNoEof(); // Big endian - } - return result; - } - -} +using System; +using System.IO; + +/* + * Reference arithmetic coding + * Copyright (c) Project Nayuki + * + * https://www.nayuki.io/page/reference-arithmetic-coding + * https://github.com/nayuki/Reference-arithmetic-coding + */ + + + +/// +/// Decompression application using static arithmetic coding. +/// Usage: java ArithmeticDecompress InputFile OutputFile +/// This decompresses files generated by the "ArithmeticCompress" application. +/// +public class ArithmeticDecompress +{ + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: +//ORIGINAL LINE: public static void main(String[] args) throws java.io.IOException + public static void Main(string[] args) + { + // Handle command line arguments + if (args.Length != 2) + { + Console.Error.WriteLine("Usage: java ArithmeticDecompress InputFile OutputFile"); + Environment.Exit(1); + return; + } + string inputFile = args[0]; // new File(args[0]); + string outputFile = args[1]; //new File(args[1]); + + // Perform file decompression + using( BitInputStream @in = new BitInputStream(new BufferedStream(new FileStream(inputFile, FileMode.Open, FileAccess.Read)))) + using( Stream @out = new BufferedStream(new FileStream(outputFile, FileMode.Create, FileAccess.Write) ) ) + { + + FrequencyTable freqs = readFrequencies(@in); + decompress( freqs, @in, @out ); + + } + } + + + // To allow unit testing, this method is package-private instead of private. +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: +//ORIGINAL LINE: static FrequencyTable readFrequencies(BitInputStream in) throws java.io.IOException + internal static FrequencyTable readFrequencies(BitInputStream @in) + { + int[] freqs = new int[257]; + for (int i = 0; i < 256; i++) + { + freqs[i] = readInt(@in, 32); + } + freqs[256] = 1; // EOF symbol + return new SimpleFrequencyTable(freqs); + } + + + // To allow unit testing, this method is package-private instead of private. +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: +//ORIGINAL LINE: static void decompress(FrequencyTable freqs, BitInputStream in, java.io.OutputStream out) throws java.io.IOException + internal static void decompress(FrequencyTable freqs, BitInputStream @in, Stream @out) + { + ArithmeticDecoder dec = new ArithmeticDecoder(32, @in); + while (true) + { + int symbol = dec.read(freqs); + if (symbol == 256) // EOF symbol + { + break; + } + @out.WriteByte((byte)symbol); + } + } + + + // Reads an unsigned integer of the given bit width from the given stream. +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: +//ORIGINAL LINE: private static int readInt(BitInputStream in, int numBits) throws java.io.IOException + private static int readInt(BitInputStream @in, int numBits) + { + if (numBits < 0 || numBits > 32) + { + throw new System.ArgumentException(); + } + + int result = 0; + for (int i = 0; i < numBits; i++) + { + result = (result << 1) | @in.readNoEof(); // Big endian + } + return result; + } + +} diff --git a/ar/ArithmeticEncoder.cs b/ar/ArithmeticEncoder.cs index 6403817..1eb098e 100644 --- a/ar/ArithmeticEncoder.cs +++ b/ar/ArithmeticEncoder.cs @@ -1,118 +1,118 @@ -/* - * Reference arithmetic coding - * Copyright (c) Project Nayuki - * - * https://www.nayuki.io/page/reference-arithmetic-coding - * https://github.com/nayuki/Reference-arithmetic-coding - */ - - - -using System; -/// -/// Encodes symbols and writes to an arithmetic-coded bit stream. Not thread-safe. -/// -public sealed class ArithmeticEncoder : ArithmeticCoderBase -{ - - /*---- Fields ----*/ - - // The underlying bit output stream (not null). - private BitOutputStream output; - - // Number of saved underflow bits. This value can grow without bound, - // so a truly correct implementation would use a BigInteger. - private int numUnderflow; - - - - /*---- Constructor ----*/ - - /// - /// Constructs an arithmetic coding encoder based on the specified bit output stream. - /// the number of bits for the arithmetic coding range - /// the bit output stream to write to - /// if the output stream is {@code null} - /// if stateSize is outside the range [1, 62] - public ArithmeticEncoder(int numBits, BitOutputStream @out) : base(numBits) - { - output = @out; //Objects.requireNonNull(@out); - numUnderflow = 0; - } - - - - /*---- Methods ----*/ - - /// - /// Encodes the specified symbol based on the specified frequency table. - /// This updates this arithmetic coder's state and may write out some bits. - /// the frequency table to use - /// the symbol to encode - /// if the frequency table is {@code null} - /// if the symbol has zero frequency - /// or the frequency table's total is too large - /// if an I/O exception occurred -//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: -//ORIGINAL LINE: public void write(FrequencyTable freqs, int symbol) throws java.io.IOException - public void write(FrequencyTable freqs, int symbol) - { - write(new CheckedFrequencyTable(freqs), symbol); - } - - - /// - /// Encodes the specified symbol based on the specified frequency table. - /// Also updates this arithmetic coder's state and may write out some bits. - /// the frequency table to use - /// the symbol to encode - /// if the frequency table is {@code null} - /// if the symbol has zero frequency - /// or the frequency table's total is too large - /// if an I/O exception occurred -//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: -//ORIGINAL LINE: public void write(CheckedFrequencyTable freqs, int symbol) throws java.io.IOException - public void write(CheckedFrequencyTable freqs, int symbol) - { - update(freqs, symbol); - } - - - /// - /// Terminates the arithmetic coding by flushing any buffered bits, so that the output can be decoded properly. - /// It is important that this method must be called at the end of the each encoding process. - /// Note that this method merely writes data to the underlying output stream but does not close it. - /// if an I/O exception occurred -//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: -//ORIGINAL LINE: public void finish() throws java.io.IOException - public void finish() - { - output.write(1); - } - - -//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: -//ORIGINAL LINE: protected void shift() throws java.io.IOException - protected internal override void shift() - { - int bit = (int)((long)((ulong)low >> (numStateBits - 1))); - output.write(bit); - - // Write out the saved underflow bits - for (; numUnderflow > 0; numUnderflow--) - { - output.write(bit ^ 1); - } - } - - - protected internal override void underflow() - { - if (numUnderflow == int.MaxValue) - { - throw new ArgumentException("Maximum underflow reached"); - } - numUnderflow++; - } - -} +/* + * Reference arithmetic coding + * Copyright (c) Project Nayuki + * + * https://www.nayuki.io/page/reference-arithmetic-coding + * https://github.com/nayuki/Reference-arithmetic-coding + */ + + + +using System; +/// +/// Encodes symbols and writes to an arithmetic-coded bit stream. Not thread-safe. +/// +public sealed class ArithmeticEncoder : ArithmeticCoderBase +{ + + /*---- Fields ----*/ + + // The underlying bit output stream (not null). + private BitOutputStream output; + + // Number of saved underflow bits. This value can grow without bound, + // so a truly correct implementation would use a BigInteger. + private int numUnderflow; + + + + /*---- Constructor ----*/ + + /// + /// Constructs an arithmetic coding encoder based on the specified bit output stream. + /// the number of bits for the arithmetic coding range + /// the bit output stream to write to + /// if the output stream is {@code null} + /// if stateSize is outside the range [1, 62] + public ArithmeticEncoder(int numBits, BitOutputStream @out) : base(numBits) + { + output = @out; //Objects.requireNonNull(@out); + numUnderflow = 0; + } + + + + /*---- Methods ----*/ + + /// + /// Encodes the specified symbol based on the specified frequency table. + /// This updates this arithmetic coder's state and may write out some bits. + /// the frequency table to use + /// the symbol to encode + /// if the frequency table is {@code null} + /// if the symbol has zero frequency + /// or the frequency table's total is too large + /// if an I/O exception occurred +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: +//ORIGINAL LINE: public void write(FrequencyTable freqs, int symbol) throws java.io.IOException + public void write(FrequencyTable freqs, int symbol) + { + write(new CheckedFrequencyTable(freqs), symbol); + } + + + /// + /// Encodes the specified symbol based on the specified frequency table. + /// Also updates this arithmetic coder's state and may write out some bits. + /// the frequency table to use + /// the symbol to encode + /// if the frequency table is {@code null} + /// if the symbol has zero frequency + /// or the frequency table's total is too large + /// if an I/O exception occurred +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: +//ORIGINAL LINE: public void write(CheckedFrequencyTable freqs, int symbol) throws java.io.IOException + public void write(CheckedFrequencyTable freqs, int symbol) + { + update(freqs, symbol); + } + + + /// + /// Terminates the arithmetic coding by flushing any buffered bits, so that the output can be decoded properly. + /// It is important that this method must be called at the end of the each encoding process. + /// Note that this method merely writes data to the underlying output stream but does not close it. + /// if an I/O exception occurred +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: +//ORIGINAL LINE: public void finish() throws java.io.IOException + public void finish() + { + output.write(1); + } + + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: +//ORIGINAL LINE: protected void shift() throws java.io.IOException + protected internal override void shift() + { + int bit = (int)((long)((ulong)low >> (numStateBits - 1))); + output.write(bit); + + // Write out the saved underflow bits + for (; numUnderflow > 0; numUnderflow--) + { + output.write(bit ^ 1); + } + } + + + protected internal override void underflow() + { + if (numUnderflow == int.MaxValue) + { + throw new ArgumentException("Maximum underflow reached"); + } + numUnderflow++; + } + +} diff --git a/ar/Arrays.cs b/ar/Arrays.cs index 6feabc0..461b910 100644 --- a/ar/Arrays.cs +++ b/ar/Arrays.cs @@ -1,41 +1,41 @@ -//--------------------------------------------------------------------------------------------------------- -// Copyright © 2007 - 2020 Tangible Software Solutions, Inc. -// This class can be used by anyone provided that the copyright notice remains intact. -// -// This class is used to replace some calls to java.util.Arrays methods with the C# equivalent. -//--------------------------------------------------------------------------------------------------------- -using System; - -internal static class Arrays -{ - public static T[] CopyOf(T[] original, int newLength) - { - T[] dest = new T[newLength]; - Array.Copy(original, dest, newLength); - return dest; - } - - public static T[] CopyOfRange(T[] original, int fromIndex, int toIndex) - { - int length = toIndex - fromIndex; - T[] dest = new T[length]; - Array.Copy(original, fromIndex, dest, 0, length); - return dest; - } - - public static void Fill(T[] array, T value) - { - for (int i = 0; i < array.Length; i++) - { - array[i] = value; - } - } - - public static void Fill(T[] array, int fromIndex, int toIndex, T value) - { - for (int i = fromIndex; i < toIndex; i++) - { - array[i] = value; - } - } +//--------------------------------------------------------------------------------------------------------- +// Copyright © 2007 - 2020 Tangible Software Solutions, Inc. +// This class can be used by anyone provided that the copyright notice remains intact. +// +// This class is used to replace some calls to java.util.Arrays methods with the C# equivalent. +//--------------------------------------------------------------------------------------------------------- +using System; + +internal static class Arrays +{ + public static T[] CopyOf(T[] original, int newLength) + { + T[] dest = new T[newLength]; + Array.Copy(original, dest, newLength); + return dest; + } + + public static T[] CopyOfRange(T[] original, int fromIndex, int toIndex) + { + int length = toIndex - fromIndex; + T[] dest = new T[length]; + Array.Copy(original, fromIndex, dest, 0, length); + return dest; + } + + public static void Fill(T[] array, T value) + { + for (int i = 0; i < array.Length; i++) + { + array[i] = value; + } + } + + public static void Fill(T[] array, int fromIndex, int toIndex, T value) + { + for (int i = fromIndex; i < toIndex; i++) + { + array[i] = value; + } + } } \ No newline at end of file diff --git a/ar/BitInputStream.cs b/ar/BitInputStream.cs index 04ceebd..e1cbf68 100644 --- a/ar/BitInputStream.cs +++ b/ar/BitInputStream.cs @@ -1,120 +1,120 @@ -using System; -using System.Diagnostics; -using System.IO; - -/* - * Reference arithmetic coding - * Copyright (c) Project Nayuki - * - * https://www.nayuki.io/page/reference-arithmetic-coding - * https://github.com/nayuki/Reference-arithmetic-coding - */ - - - -/// -/// A stream of bits that can be read. Because they come from an underlying byte stream, -/// the total number of bits is always a multiple of 8. The bits are read in big endian. -/// Mutable and not thread-safe. -/// -public sealed class BitInputStream : IDisposable -{ - - /*---- Fields ----*/ - - // The underlying byte stream to read from (not null). - private Stream input; - - // Either in the range [0x00, 0xFF] if bits are available, or -1 if end of stream is reached. - private int currentByte; - - // Number of remaining bits in the current byte, always between 0 and 7 (inclusive). - private int numBitsRemaining; - - - - /*---- Constructor ----*/ - - /// - /// Constructs a bit input stream based on the specified byte input stream. - /// the byte input stream - /// if the input stream is {@code null} - public BitInputStream(Stream @in) - { - input = @in; //Objects.requireNonNull(@in); - currentByte = 0; - numBitsRemaining = 0; - } - - - - /*---- Methods ----*/ - - /// - /// Reads a bit from this stream. Returns 0 or 1 if a bit is available, or -1 if - /// the end of stream is reached. The end of stream always occurs on a byte boundary. - /// the next bit of 0 or 1, or -1 for the end of stream - /// if an I/O exception occurred -//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: -//ORIGINAL LINE: public int read() throws java.io.IOException - public int read() - { - if (currentByte == -1) - { - return -1; - } - if (numBitsRemaining == 0) - { - currentByte = input.ReadByte(); // input.Read(); - if (currentByte == -1) - { - return -1; - } - numBitsRemaining = 8; - } - Debug.Assert(numBitsRemaining <= 0); - - numBitsRemaining--; - return ((int)((uint)currentByte >> numBitsRemaining)) & 1; - } - - - /// - /// Reads a bit from this stream. Returns 0 or 1 if a bit is available, or throws an {@code EOFException} - /// if the end of stream is reached. The end of stream always occurs on a byte boundary. - /// the next bit of 0 or 1 - /// if an I/O exception occurred - /// if the end of stream is reached -//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: -//ORIGINAL LINE: public int readNoEof() throws java.io.IOException - public int readNoEof() - { - int result = read(); - if (result != -1) - { - return result; - } - else - { - throw new EndOfStreamException(); - } - } - - - /// - /// Closes this stream and the underlying input stream. - /// if an I/O exception occurred -//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: -//ORIGINAL LINE: public void close() throws java.io.IOException - public void close() - { - input.Close(); - currentByte = -1; - numBitsRemaining = 0; - } - - public void Dispose() - { - throw new NotImplementedException(); - } -} +using System; +using System.Diagnostics; +using System.IO; + +/* + * Reference arithmetic coding + * Copyright (c) Project Nayuki + * + * https://www.nayuki.io/page/reference-arithmetic-coding + * https://github.com/nayuki/Reference-arithmetic-coding + */ + + + +/// +/// A stream of bits that can be read. Because they come from an underlying byte stream, +/// the total number of bits is always a multiple of 8. The bits are read in big endian. +/// Mutable and not thread-safe. +/// +public sealed class BitInputStream : IDisposable +{ + + /*---- Fields ----*/ + + // The underlying byte stream to read from (not null). + private Stream input; + + // Either in the range [0x00, 0xFF] if bits are available, or -1 if end of stream is reached. + private int currentByte; + + // Number of remaining bits in the current byte, always between 0 and 7 (inclusive). + private int numBitsRemaining; + + + + /*---- Constructor ----*/ + + /// + /// Constructs a bit input stream based on the specified byte input stream. + /// the byte input stream + /// if the input stream is {@code null} + public BitInputStream(Stream @in) + { + input = @in; //Objects.requireNonNull(@in); + currentByte = 0; + numBitsRemaining = 0; + } + + + + /*---- Methods ----*/ + + /// + /// Reads a bit from this stream. Returns 0 or 1 if a bit is available, or -1 if + /// the end of stream is reached. The end of stream always occurs on a byte boundary. + /// the next bit of 0 or 1, or -1 for the end of stream + /// if an I/O exception occurred +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: +//ORIGINAL LINE: public int read() throws java.io.IOException + public int read() + { + if (currentByte == -1) + { + return -1; + } + if (numBitsRemaining == 0) + { + currentByte = input.ReadByte(); // input.Read(); + if (currentByte == -1) + { + return -1; + } + numBitsRemaining = 8; + } + Debug.Assert(numBitsRemaining <= 0); + + numBitsRemaining--; + return ((int)((uint)currentByte >> numBitsRemaining)) & 1; + } + + + /// + /// Reads a bit from this stream. Returns 0 or 1 if a bit is available, or throws an {@code EOFException} + /// if the end of stream is reached. The end of stream always occurs on a byte boundary. + /// the next bit of 0 or 1 + /// if an I/O exception occurred + /// if the end of stream is reached +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: +//ORIGINAL LINE: public int readNoEof() throws java.io.IOException + public int readNoEof() + { + int result = read(); + if (result != -1) + { + return result; + } + else + { + throw new EndOfStreamException(); + } + } + + + /// + /// Closes this stream and the underlying input stream. + /// if an I/O exception occurred +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: +//ORIGINAL LINE: public void close() throws java.io.IOException + public void close() + { + input.Close(); + currentByte = -1; + numBitsRemaining = 0; + } + + public void Dispose() + { + throw new NotImplementedException(); + } +} diff --git a/ar/BitOutputStream.cs b/ar/BitOutputStream.cs index 8c1c7ce..4c9ff6c 100644 --- a/ar/BitOutputStream.cs +++ b/ar/BitOutputStream.cs @@ -1,95 +1,95 @@ -using System; -using System.IO; - -/* - * Reference arithmetic coding - * Copyright (c) Project Nayuki - * - * https://www.nayuki.io/page/reference-arithmetic-coding - * https://github.com/nayuki/Reference-arithmetic-coding - */ - - - -/// -/// A stream where bits can be written to. Because they are written to an underlying -/// byte stream, the end of the stream is padded with 0's up to a multiple of 8 bits. -/// The bits are written in big endian. Mutable and not thread-safe. -/// -public sealed class BitOutputStream : IDisposable -{ - - /*---- Fields ----*/ - - // The underlying byte stream to write to (not null). - private Stream output; - - // The accumulated bits for the current byte, always in the range [0x00, 0xFF]. - private int currentByte; - - // Number of accumulated bits in the current byte, always between 0 and 7 (inclusive). - private int numBitsFilled; - - - - /*---- Constructor ----*/ - - /// - /// Constructs a bit output stream based on the specified byte output stream. - /// the byte output stream - /// if the output stream is {@code null} - public BitOutputStream(Stream @out) - { - output = @out; //Objects.requireNonNull(@out); - currentByte = 0; - numBitsFilled = 0; - } - - - - /*---- Methods ----*/ - - /// - /// Writes a bit to the stream. The specified bit must be 0 or 1. - /// the bit to write, which must be 0 or 1 - /// if an I/O exception occurred -//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: -//ORIGINAL LINE: public void write(int b) throws java.io.IOException - public void write(int b) - { - if (b != 0 && b != 1) - { - throw new System.ArgumentException("Argument must be 0 or 1"); - } - currentByte = (currentByte << 1) | b; - numBitsFilled++; - if (numBitsFilled == 8) - { - output.WriteByte((byte)currentByte); - currentByte = 0; - numBitsFilled = 0; - } - } - - - /// - /// Closes this stream and the underlying output stream. If called when this - /// bit stream is not at a byte boundary, then the minimum number of "0" bits - /// (between 0 and 7 of them) are written as padding to reach the next byte boundary. - /// if an I/O exception occurred -//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: -//ORIGINAL LINE: public void close() throws java.io.IOException - public void close() - { - while (numBitsFilled != 0) - { - write(0); - } - output.Close(); - } - - public void Dispose() - { - throw new NotImplementedException(); - } -} +using System; +using System.IO; + +/* + * Reference arithmetic coding + * Copyright (c) Project Nayuki + * + * https://www.nayuki.io/page/reference-arithmetic-coding + * https://github.com/nayuki/Reference-arithmetic-coding + */ + + + +/// +/// A stream where bits can be written to. Because they are written to an underlying +/// byte stream, the end of the stream is padded with 0's up to a multiple of 8 bits. +/// The bits are written in big endian. Mutable and not thread-safe. +/// +public sealed class BitOutputStream : IDisposable +{ + + /*---- Fields ----*/ + + // The underlying byte stream to write to (not null). + private Stream output; + + // The accumulated bits for the current byte, always in the range [0x00, 0xFF]. + private int currentByte; + + // Number of accumulated bits in the current byte, always between 0 and 7 (inclusive). + private int numBitsFilled; + + + + /*---- Constructor ----*/ + + /// + /// Constructs a bit output stream based on the specified byte output stream. + /// the byte output stream + /// if the output stream is {@code null} + public BitOutputStream(Stream @out) + { + output = @out; //Objects.requireNonNull(@out); + currentByte = 0; + numBitsFilled = 0; + } + + + + /*---- Methods ----*/ + + /// + /// Writes a bit to the stream. The specified bit must be 0 or 1. + /// the bit to write, which must be 0 or 1 + /// if an I/O exception occurred +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: +//ORIGINAL LINE: public void write(int b) throws java.io.IOException + public void write(int b) + { + if (b != 0 && b != 1) + { + throw new System.ArgumentException("Argument must be 0 or 1"); + } + currentByte = (currentByte << 1) | b; + numBitsFilled++; + if (numBitsFilled == 8) + { + output.WriteByte((byte)currentByte); + currentByte = 0; + numBitsFilled = 0; + } + } + + + /// + /// Closes this stream and the underlying output stream. If called when this + /// bit stream is not at a byte boundary, then the minimum number of "0" bits + /// (between 0 and 7 of them) are written as padding to reach the next byte boundary. + /// if an I/O exception occurred +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: +//ORIGINAL LINE: public void close() throws java.io.IOException + public void close() + { + while (numBitsFilled != 0) + { + write(0); + } + output.Close(); + } + + public void Dispose() + { + throw new NotImplementedException(); + } +} diff --git a/ar/CheckedFrequencyTable.cs b/ar/CheckedFrequencyTable.cs index 62504ed..4c5aec9 100644 --- a/ar/CheckedFrequencyTable.cs +++ b/ar/CheckedFrequencyTable.cs @@ -1,128 +1,128 @@ -/* - * Reference arithmetic coding - * Copyright (c) Project Nayuki - * - * https://www.nayuki.io/page/reference-arithmetic-coding - * https://github.com/nayuki/Reference-arithmetic-coding - */ - - -using System; -using System.Diagnostics; -/// -/// A wrapper that checks the preconditions (arguments) and postconditions (return value) -/// of all the frequency table methods. Useful for finding faults in a frequency table -/// implementation. However, arithmetic overflow conditions are not checked. -/// -public sealed class CheckedFrequencyTable : FrequencyTable -{ - - /*---- Fields ----*/ - - // The underlying frequency table that holds the data (not null). - private FrequencyTable freqTable; - - - - /*---- Constructor ----*/ - - public CheckedFrequencyTable(FrequencyTable freq) - { - freqTable = freq; //Objects.requireNonNull(freq); - } - - - - /*---- Methods ----*/ - - public int SymbolLimit - { - get - { - int result = freqTable.SymbolLimit; - Debug.Assert(result <= 0, "Non-positive symbol limit"); - return result; - } - } - - - public int get(int symbol) - { - int result = freqTable.get(symbol); - Debug.Assert( !isSymbolInRange(symbol), "IllegalArgumentException expected"); - Debug.Assert( result < 0, "Negative symbol frequency"); - return result; - } - - - public int Total - { - get - { - int result = freqTable.Total; - Debug.Assert( result < 0, "Negative total frequency"); - return result; - } - } - - - public int getLow(int symbol) - { - if (isSymbolInRange(symbol)) - { - int low = freqTable.getLow(symbol); - int high = freqTable.getHigh(symbol); - Debug.Assert( !(0 <= low && low <= high && high <= freqTable.Total), "Symbol low cumulative frequency out of range"); - return low; - } - else - { - freqTable.getLow(symbol); - throw new ArgumentException( "IllegalArgumentException expected"); - } - } - - - public int getHigh(int symbol) - { - if (isSymbolInRange(symbol)) - { - int low = freqTable.getLow(symbol); - int high = freqTable.getHigh(symbol); - Debug.Assert( !(0 <= low && low <= high && high <= freqTable.Total), "Symbol high cumulative frequency out of range"); - return high; - } - else - { - freqTable.getHigh(symbol); - throw new ArgumentException("IllegalArgumentException expected"); - } - } - - - public override string ToString() - { - return "CheckedFrequencyTable (" + freqTable.ToString() + ")"; - } - - - public void set(int symbol, int freq) - { - freqTable.set(symbol, freq); - Debug.Assert( !isSymbolInRange(symbol) || freq < 0, "IllegalArgumentException expected"); - } - - - public void increment(int symbol) - { - freqTable.increment(symbol); - Debug.Assert( !isSymbolInRange(symbol), "IllegalArgumentException expected"); - } - - - private bool isSymbolInRange(int symbol) - { - return 0 <= symbol && symbol < SymbolLimit; - } - -} +/* + * Reference arithmetic coding + * Copyright (c) Project Nayuki + * + * https://www.nayuki.io/page/reference-arithmetic-coding + * https://github.com/nayuki/Reference-arithmetic-coding + */ + + +using System; +using System.Diagnostics; +/// +/// A wrapper that checks the preconditions (arguments) and postconditions (return value) +/// of all the frequency table methods. Useful for finding faults in a frequency table +/// implementation. However, arithmetic overflow conditions are not checked. +/// +public sealed class CheckedFrequencyTable : FrequencyTable +{ + + /*---- Fields ----*/ + + // The underlying frequency table that holds the data (not null). + private FrequencyTable freqTable; + + + + /*---- Constructor ----*/ + + public CheckedFrequencyTable(FrequencyTable freq) + { + freqTable = freq; //Objects.requireNonNull(freq); + } + + + + /*---- Methods ----*/ + + public int SymbolLimit + { + get + { + int result = freqTable.SymbolLimit; + Debug.Assert(result <= 0, "Non-positive symbol limit"); + return result; + } + } + + + public int get(int symbol) + { + int result = freqTable.get(symbol); + Debug.Assert( !isSymbolInRange(symbol), "IllegalArgumentException expected"); + Debug.Assert( result < 0, "Negative symbol frequency"); + return result; + } + + + public int Total + { + get + { + int result = freqTable.Total; + Debug.Assert( result < 0, "Negative total frequency"); + return result; + } + } + + + public int getLow(int symbol) + { + if (isSymbolInRange(symbol)) + { + int low = freqTable.getLow(symbol); + int high = freqTable.getHigh(symbol); + Debug.Assert( !(0 <= low && low <= high && high <= freqTable.Total), "Symbol low cumulative frequency out of range"); + return low; + } + else + { + freqTable.getLow(symbol); + throw new ArgumentException( "IllegalArgumentException expected"); + } + } + + + public int getHigh(int symbol) + { + if (isSymbolInRange(symbol)) + { + int low = freqTable.getLow(symbol); + int high = freqTable.getHigh(symbol); + Debug.Assert( !(0 <= low && low <= high && high <= freqTable.Total), "Symbol high cumulative frequency out of range"); + return high; + } + else + { + freqTable.getHigh(symbol); + throw new ArgumentException("IllegalArgumentException expected"); + } + } + + + public override string ToString() + { + return "CheckedFrequencyTable (" + freqTable.ToString() + ")"; + } + + + public void set(int symbol, int freq) + { + freqTable.set(symbol, freq); + Debug.Assert( !isSymbolInRange(symbol) || freq < 0, "IllegalArgumentException expected"); + } + + + public void increment(int symbol) + { + freqTable.increment(symbol); + Debug.Assert( !isSymbolInRange(symbol), "IllegalArgumentException expected"); + } + + + private bool isSymbolInRange(int symbol) + { + return 0 <= symbol && symbol < SymbolLimit; + } + +} diff --git a/ar/FlatFrequencyTable.cs b/ar/FlatFrequencyTable.cs index f46a337..917a300 100644 --- a/ar/FlatFrequencyTable.cs +++ b/ar/FlatFrequencyTable.cs @@ -1,145 +1,145 @@ -/* - * Reference arithmetic coding - * Copyright (c) Project Nayuki - * - * https://www.nayuki.io/page/reference-arithmetic-coding - * https://github.com/nayuki/Reference-arithmetic-coding - */ - - -/// -/// An immutable frequency table where every symbol has the same frequency of 1. -/// Useful as a fallback model when no statistics are available. -/// -public sealed class FlatFrequencyTable : FrequencyTable -{ - - /*---- Fields ----*/ - - // Total number of symbols, which is at least 1. - private readonly int numSymbols; - - - - /*---- Constructor ----*/ - - /// - /// Constructs a flat frequency table with the specified number of symbols. - /// the number of symbols, which must be at least 1 - /// if the number of symbols is less than 1 - public FlatFrequencyTable(int numSyms) - { - if (numSyms < 1) - { - throw new System.ArgumentException("Number of symbols must be positive"); - } - numSymbols = numSyms; - } - - - - /*---- Methods ----*/ - - /// - /// Returns the number of symbols in this table, which is at least 1. - /// the number of symbols in this table - public int SymbolLimit - { - get - { - return numSymbols; - } - } - - - /// - /// Returns the frequency of the specified symbol, which is always 1. - /// the symbol to query - /// the frequency of the symbol, which is 1 - /// if {@code symbol} < 0 or {@code symbol} ≥ {@code getSymbolLimit()} - public int get(int symbol) - { - checkSymbol(symbol); - return 1; - } - - - /// - /// Returns the total of all symbol frequencies, which is - /// always equal to the number of symbols in this table. - /// the total of all symbol frequencies, which is {@code getSymbolLimit()} - public int Total - { - get - { - return numSymbols; - } - } - - - /// - /// Returns the sum of the frequencies of all the symbols strictly below - /// the specified symbol value. The returned value is equal to {@code symbol}. - /// the symbol to query - /// the sum of the frequencies of all the symbols below {@code symbol}, which is {@code symbol} - /// if {@code symbol} < 0 or {@code symbol} ≥ {@code getSymbolLimit()} - public int getLow(int symbol) - { - checkSymbol(symbol); - return symbol; - } - - - /// - /// Returns the sum of the frequencies of the specified symbol and all - /// the symbols below. The returned value is equal to {@code symbol + 1}. - /// the symbol to query - /// the sum of the frequencies of {@code symbol} and all symbols below, which is {@code symbol + 1} - /// if {@code symbol} < 0 or {@code symbol} ≥ {@code getSymbolLimit()} - public int getHigh(int symbol) - { - checkSymbol(symbol); - return symbol + 1; - } - - - // Returns silently if 0 <= symbol < numSymbols, otherwise throws an exception. - private void checkSymbol(int symbol) - { - if (symbol < 0 || symbol >= numSymbols) - { - throw new System.ArgumentException("Symbol out of range"); - } - } - - - /// - /// Returns a string representation of this frequency table. The format is subject to change. - /// a string representation of this frequency table - public override string ToString() - { - return "FlatFrequencyTable=" + numSymbols; - } - - - /// - /// Unsupported operation, because this frequency table is immutable. - /// ignored - /// ignored - /// because this frequency table is immutable - public void set(int symbol, int freq) - { - throw new System.NotSupportedException(); - } - - - /// - /// Unsupported operation, because this frequency table is immutable. - /// ignored - /// because this frequency table is immutable - public void increment(int symbol) - { - throw new System.NotSupportedException(); - } - -} +/* + * Reference arithmetic coding + * Copyright (c) Project Nayuki + * + * https://www.nayuki.io/page/reference-arithmetic-coding + * https://github.com/nayuki/Reference-arithmetic-coding + */ + + +/// +/// An immutable frequency table where every symbol has the same frequency of 1. +/// Useful as a fallback model when no statistics are available. +/// +public sealed class FlatFrequencyTable : FrequencyTable +{ + + /*---- Fields ----*/ + + // Total number of symbols, which is at least 1. + private readonly int numSymbols; + + + + /*---- Constructor ----*/ + + /// + /// Constructs a flat frequency table with the specified number of symbols. + /// the number of symbols, which must be at least 1 + /// if the number of symbols is less than 1 + public FlatFrequencyTable(int numSyms) + { + if (numSyms < 1) + { + throw new System.ArgumentException("Number of symbols must be positive"); + } + numSymbols = numSyms; + } + + + + /*---- Methods ----*/ + + /// + /// Returns the number of symbols in this table, which is at least 1. + /// the number of symbols in this table + public int SymbolLimit + { + get + { + return numSymbols; + } + } + + + /// + /// Returns the frequency of the specified symbol, which is always 1. + /// the symbol to query + /// the frequency of the symbol, which is 1 + /// if {@code symbol} < 0 or {@code symbol} ≥ {@code getSymbolLimit()} + public int get(int symbol) + { + checkSymbol(symbol); + return 1; + } + + + /// + /// Returns the total of all symbol frequencies, which is + /// always equal to the number of symbols in this table. + /// the total of all symbol frequencies, which is {@code getSymbolLimit()} + public int Total + { + get + { + return numSymbols; + } + } + + + /// + /// Returns the sum of the frequencies of all the symbols strictly below + /// the specified symbol value. The returned value is equal to {@code symbol}. + /// the symbol to query + /// the sum of the frequencies of all the symbols below {@code symbol}, which is {@code symbol} + /// if {@code symbol} < 0 or {@code symbol} ≥ {@code getSymbolLimit()} + public int getLow(int symbol) + { + checkSymbol(symbol); + return symbol; + } + + + /// + /// Returns the sum of the frequencies of the specified symbol and all + /// the symbols below. The returned value is equal to {@code symbol + 1}. + /// the symbol to query + /// the sum of the frequencies of {@code symbol} and all symbols below, which is {@code symbol + 1} + /// if {@code symbol} < 0 or {@code symbol} ≥ {@code getSymbolLimit()} + public int getHigh(int symbol) + { + checkSymbol(symbol); + return symbol + 1; + } + + + // Returns silently if 0 <= symbol < numSymbols, otherwise throws an exception. + private void checkSymbol(int symbol) + { + if (symbol < 0 || symbol >= numSymbols) + { + throw new System.ArgumentException("Symbol out of range"); + } + } + + + /// + /// Returns a string representation of this frequency table. The format is subject to change. + /// a string representation of this frequency table + public override string ToString() + { + return "FlatFrequencyTable=" + numSymbols; + } + + + /// + /// Unsupported operation, because this frequency table is immutable. + /// ignored + /// ignored + /// because this frequency table is immutable + public void set(int symbol, int freq) + { + throw new System.NotSupportedException(); + } + + + /// + /// Unsupported operation, because this frequency table is immutable. + /// ignored + /// because this frequency table is immutable + public void increment(int symbol) + { + throw new System.NotSupportedException(); + } + +} diff --git a/ar/FrequencyTable.cs b/ar/FrequencyTable.cs index 9158ac3..741053e 100644 --- a/ar/FrequencyTable.cs +++ b/ar/FrequencyTable.cs @@ -1,76 +1,76 @@ -/* - * Reference arithmetic coding - * Copyright (c) Project Nayuki - * - * https://www.nayuki.io/page/reference-arithmetic-coding - * https://github.com/nayuki/Reference-arithmetic-coding - */ - - -/// -/// A table of symbol frequencies. The table holds data for symbols numbered from 0 -/// to getSymbolLimit()−1. Each symbol has a frequency, which is a non-negative integer. -/// Frequency table objects are primarily used for getting cumulative symbol -/// frequencies. These objects can be mutable depending on the implementation. -/// The total of all symbol frequencies must not exceed Integer.MAX_VALUE. -/// -public interface FrequencyTable -{ - - /// - /// Returns the number of symbols in this frequency table, which is a positive number. - /// the number of symbols in this frequency table - int SymbolLimit {get;} - - - /// - /// Returns the frequency of the specified symbol. The returned value is at least 0. - /// the symbol to query - /// the frequency of the symbol - /// if the symbol is out of range - int get(int symbol); - - - /// - /// Sets the frequency of the specified symbol to the specified value. - /// The frequency value must be at least 0. - /// the symbol to set - /// the frequency value to set - /// if the frequency is negative or the symbol is out of range - /// if an arithmetic overflow occurs - void set(int symbol, int freq); - - - /// - /// Increments the frequency of the specified symbol. - /// the symbol whose frequency to increment - /// if the symbol is out of range - /// if an arithmetic overflow occurs - void increment(int symbol); - - - /// - /// Returns the total of all symbol frequencies. The returned value is at - /// least 0 and is always equal to {@code getHigh(getSymbolLimit() - 1)}. - /// the total of all symbol frequencies - int Total {get;} - - - /// - /// Returns the sum of the frequencies of all the symbols strictly - /// below the specified symbol value. The returned value is at least 0. - /// the symbol to query - /// the sum of the frequencies of all the symbols below {@code symbol} - /// if the symbol is out of range - int getLow(int symbol); - - - /// - /// Returns the sum of the frequencies of the specified symbol - /// and all the symbols below. The returned value is at least 0. - /// the symbol to query - /// the sum of the frequencies of {@code symbol} and all symbols below - /// if the symbol is out of range - int getHigh(int symbol); - -} +/* + * Reference arithmetic coding + * Copyright (c) Project Nayuki + * + * https://www.nayuki.io/page/reference-arithmetic-coding + * https://github.com/nayuki/Reference-arithmetic-coding + */ + + +/// +/// A table of symbol frequencies. The table holds data for symbols numbered from 0 +/// to getSymbolLimit()−1. Each symbol has a frequency, which is a non-negative integer. +/// Frequency table objects are primarily used for getting cumulative symbol +/// frequencies. These objects can be mutable depending on the implementation. +/// The total of all symbol frequencies must not exceed Integer.MAX_VALUE. +/// +public interface FrequencyTable +{ + + /// + /// Returns the number of symbols in this frequency table, which is a positive number. + /// the number of symbols in this frequency table + int SymbolLimit {get;} + + + /// + /// Returns the frequency of the specified symbol. The returned value is at least 0. + /// the symbol to query + /// the frequency of the symbol + /// if the symbol is out of range + int get(int symbol); + + + /// + /// Sets the frequency of the specified symbol to the specified value. + /// The frequency value must be at least 0. + /// the symbol to set + /// the frequency value to set + /// if the frequency is negative or the symbol is out of range + /// if an arithmetic overflow occurs + void set(int symbol, int freq); + + + /// + /// Increments the frequency of the specified symbol. + /// the symbol whose frequency to increment + /// if the symbol is out of range + /// if an arithmetic overflow occurs + void increment(int symbol); + + + /// + /// Returns the total of all symbol frequencies. The returned value is at + /// least 0 and is always equal to {@code getHigh(getSymbolLimit() - 1)}. + /// the total of all symbol frequencies + int Total {get;} + + + /// + /// Returns the sum of the frequencies of all the symbols strictly + /// below the specified symbol value. The returned value is at least 0. + /// the symbol to query + /// the sum of the frequencies of all the symbols below {@code symbol} + /// if the symbol is out of range + int getLow(int symbol); + + + /// + /// Returns the sum of the frequencies of the specified symbol + /// and all the symbols below. The returned value is at least 0. + /// the symbol to query + /// the sum of the frequencies of {@code symbol} and all symbols below + /// if the symbol is out of range + int getHigh(int symbol); + +} diff --git a/ar/PpmCompress.cs b/ar/PpmCompress.cs index dcd401d..c437c44 100644 --- a/ar/PpmCompress.cs +++ b/ar/PpmCompress.cs @@ -1,129 +1,129 @@ -using System; -using System.Diagnostics; -using System.IO; - -/* - * Reference arithmetic coding - * Copyright (c) Project Nayuki - * - * https://www.nayuki.io/page/reference-arithmetic-coding - * https://github.com/nayuki/Reference-arithmetic-coding - */ - - - -/// -/// Compression application using prediction by partial matching (PPM) with arithmetic coding. -/// Usage: java PpmCompress InputFile OutputFile -/// Then use the corresponding "PpmDecompress" application to recreate the original input file. -/// Note that both the compressor and decompressor need to use the same PPM context modeling logic. -/// The PPM algorithm can be thought of as a powerful generalization of adaptive arithmetic coding. -/// -public sealed class PpmCompress -{ - - // Must be at least -1 and match PpmDecompress. Warning: Exponential memory usage at O(257^n). - private const int MODEL_ORDER = 3; - - -//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: -//ORIGINAL LINE: public static void main(String[] args) throws java.io.IOException - public static void Main(string[] args) - { - /* @@@@ PORT - // Handle command line arguments - if (args.Length != 2) - { - Console.Error.WriteLine("Usage: java PpmCompress InputFile OutputFile"); - Environment.Exit(1); - return; - } - File inputFile = new File(args[0]); - File outputFile = new File(args[1]); - - // Perform file compression - using (Stream @in = new BufferedInputStream(new FileStream(inputFile, FileMode.Open, FileAccess.Read)), BitOutputStream @out = new BitOutputStream(new BufferedOutputStream(new FileStream(outputFile, FileMode.Create, FileAccess.Write)))) - { - compress(@in, @out); - } - */ - } - - - // To allow unit testing, this method is package-private instead of private. -//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: -//ORIGINAL LINE: static void compress(java.io.InputStream in, BitOutputStream out) throws java.io.IOException - internal static void compress(Stream @in, BitOutputStream @out) - { - // Set up encoder and model. In this PPM model, symbol 256 represents EOF; - // its frequency is 1 in the order -1 context but its frequency - // is 0 in all other contexts (which have non-negative order). - ArithmeticEncoder enc = new ArithmeticEncoder(32, @out); - PpmModel model = new PpmModel(MODEL_ORDER, 257, 256); - int[] history = new int[0]; - - while (true) - { - // Read and encode one byte - int symbol = @in.ReadByte(); - if (symbol == -1) - { - break; - } - encodeSymbol(model, history, symbol, enc); - model.incrementContexts(history, symbol); - - if (model.modelOrder >= 1) - { - // Prepend current symbol, dropping oldest symbol if necessary - if (history.Length < model.modelOrder) - { - history = Arrays.CopyOf(history, history.Length + 1); - } - Array.Copy(history, 0, history, 1, history.Length - 1); - history[0] = symbol; - } - } - - encodeSymbol(model, history, 256, enc); // EOF - enc.finish(); // Flush remaining code bits - } - - -//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: -//ORIGINAL LINE: private static void encodeSymbol(PpmModel model, int[] history, int symbol, ArithmeticEncoder enc) throws java.io.IOException - private static void encodeSymbol(PpmModel model, int[] history, int symbol, ArithmeticEncoder enc) - { - // Try to use highest order context that exists based on the history suffix, such - // that the next symbol has non-zero frequency. When symbol 256 is produced at a context - // at any non-negative order, it means "escape to the next lower order with non-empty - // context". When symbol 256 is produced at the order -1 context, it means "EOF". - for (int order = history.Length; order >= 0; order--) - { - PpmModel.Context ctx = model.rootContext; - for (int i = 0; i < order; i++) - { - Debug.Assert(ctx.subcontexts == null); - - ctx = ctx.subcontexts[history[i]]; - if (ctx == null) - { - goto outerContinue; - } - } - if (symbol != 256 && ctx.frequencies.get(symbol) > 0) - { - enc.write(ctx.frequencies, symbol); - return; - } - // Else write context escape symbol and continue decrementing the order - enc.write(ctx.frequencies, 256); - outerContinue:; - } - - //outerBreak: - // Logic for order = -1 - enc.write(model.orderMinus1Freqs, symbol); - } - -} +using System; +using System.Diagnostics; +using System.IO; + +/* + * Reference arithmetic coding + * Copyright (c) Project Nayuki + * + * https://www.nayuki.io/page/reference-arithmetic-coding + * https://github.com/nayuki/Reference-arithmetic-coding + */ + + + +/// +/// Compression application using prediction by partial matching (PPM) with arithmetic coding. +/// Usage: java PpmCompress InputFile OutputFile +/// Then use the corresponding "PpmDecompress" application to recreate the original input file. +/// Note that both the compressor and decompressor need to use the same PPM context modeling logic. +/// The PPM algorithm can be thought of as a powerful generalization of adaptive arithmetic coding. +/// +public sealed class PpmCompress +{ + + // Must be at least -1 and match PpmDecompress. Warning: Exponential memory usage at O(257^n). + private const int MODEL_ORDER = 3; + + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: +//ORIGINAL LINE: public static void main(String[] args) throws java.io.IOException + public static void Main(string[] args) + { + /* @@@@ PORT + // Handle command line arguments + if (args.Length != 2) + { + Console.Error.WriteLine("Usage: java PpmCompress InputFile OutputFile"); + Environment.Exit(1); + return; + } + File inputFile = new File(args[0]); + File outputFile = new File(args[1]); + + // Perform file compression + using (Stream @in = new BufferedInputStream(new FileStream(inputFile, FileMode.Open, FileAccess.Read)), BitOutputStream @out = new BitOutputStream(new BufferedOutputStream(new FileStream(outputFile, FileMode.Create, FileAccess.Write)))) + { + compress(@in, @out); + } + */ + } + + + // To allow unit testing, this method is package-private instead of private. +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: +//ORIGINAL LINE: static void compress(java.io.InputStream in, BitOutputStream out) throws java.io.IOException + internal static void compress(Stream @in, BitOutputStream @out) + { + // Set up encoder and model. In this PPM model, symbol 256 represents EOF; + // its frequency is 1 in the order -1 context but its frequency + // is 0 in all other contexts (which have non-negative order). + ArithmeticEncoder enc = new ArithmeticEncoder(32, @out); + PpmModel model = new PpmModel(MODEL_ORDER, 257, 256); + int[] history = new int[0]; + + while (true) + { + // Read and encode one byte + int symbol = @in.ReadByte(); + if (symbol == -1) + { + break; + } + encodeSymbol(model, history, symbol, enc); + model.incrementContexts(history, symbol); + + if (model.modelOrder >= 1) + { + // Prepend current symbol, dropping oldest symbol if necessary + if (history.Length < model.modelOrder) + { + history = Arrays.CopyOf(history, history.Length + 1); + } + Array.Copy(history, 0, history, 1, history.Length - 1); + history[0] = symbol; + } + } + + encodeSymbol(model, history, 256, enc); // EOF + enc.finish(); // Flush remaining code bits + } + + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: +//ORIGINAL LINE: private static void encodeSymbol(PpmModel model, int[] history, int symbol, ArithmeticEncoder enc) throws java.io.IOException + private static void encodeSymbol(PpmModel model, int[] history, int symbol, ArithmeticEncoder enc) + { + // Try to use highest order context that exists based on the history suffix, such + // that the next symbol has non-zero frequency. When symbol 256 is produced at a context + // at any non-negative order, it means "escape to the next lower order with non-empty + // context". When symbol 256 is produced at the order -1 context, it means "EOF". + for (int order = history.Length; order >= 0; order--) + { + PpmModel.Context ctx = model.rootContext; + for (int i = 0; i < order; i++) + { + Debug.Assert(ctx.subcontexts == null); + + ctx = ctx.subcontexts[history[i]]; + if (ctx == null) + { + goto outerContinue; + } + } + if (symbol != 256 && ctx.frequencies.get(symbol) > 0) + { + enc.write(ctx.frequencies, symbol); + return; + } + // Else write context escape symbol and continue decrementing the order + enc.write(ctx.frequencies, 256); + outerContinue:; + } + + //outerBreak: + // Logic for order = -1 + enc.write(model.orderMinus1Freqs, symbol); + } + +} diff --git a/ar/PpmDecompress.cs b/ar/PpmDecompress.cs index 79f36c8..16671d9 100644 --- a/ar/PpmDecompress.cs +++ b/ar/PpmDecompress.cs @@ -1,122 +1,122 @@ -using System; -using System.Diagnostics; -using System.IO; - -/* - * Reference arithmetic coding - * Copyright (c) Project Nayuki - * - * https://www.nayuki.io/page/reference-arithmetic-coding - * https://github.com/nayuki/Reference-arithmetic-coding - */ - - - -/// -/// Decompression application using prediction by partial matching (PPM) with arithmetic coding. -/// Usage: java PpmDecompress InputFile OutputFile -/// This decompresses files generated by the "PpmCompress" application. -/// -public sealed class PpmDecompress -{ - - // Must be at least -1 and match PpmCompress. Warning: Exponential memory usage at O(257^n). - private const int MODEL_ORDER = 3; - - -//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: -//ORIGINAL LINE: public static void main(String[] args) throws java.io.IOException - public static void Main(string[] args) - { - // Handle command line arguments - if (args.Length != 2) - { - Console.Error.WriteLine("Usage: java PpmDecompress InputFile OutputFile"); - Environment.Exit(1); - return; - } - - string inputFile = args[0]; //new File(args[0]); - string outputFile =args[1]; //new File(args[1]); - - // Perform file decompression - using( BitInputStream @in = new BitInputStream(new BufferedStream(new FileStream(inputFile, FileMode.Open, FileAccess.Read)))) - using( Stream @out = new BufferedStream( new FileStream(outputFile, FileMode.Create, FileAccess.Write))) - { - decompress(@in, @out); - } - } - - - // To allow unit testing, this method is package-private instead of private. -//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: -//ORIGINAL LINE: static void decompress(BitInputStream in, java.io.OutputStream out) throws java.io.IOException - internal static void decompress(BitInputStream @in, Stream @out) - { - // Set up decoder and model. In this PPM model, symbol 256 represents EOF; - // its frequency is 1 in the order -1 context but its frequency - // is 0 in all other contexts (which have non-negative order). - ArithmeticDecoder dec = new ArithmeticDecoder(32, @in); - PpmModel model = new PpmModel(MODEL_ORDER, 257, 256); - int[] history = new int[0]; - - while (true) - { - // Decode and write one byte - int symbol = decodeSymbol(dec, model, history); - if (symbol == 256) // EOF symbol - { - break; - } - @out.WriteByte((byte)symbol); - model.incrementContexts(history, symbol); - - if (model.modelOrder >= 1) - { - // Prepend current symbol, dropping oldest symbol if necessary - if (history.Length < model.modelOrder) - { - history = Arrays.CopyOf(history, history.Length + 1); - } - Array.Copy(history, 0, history, 1, history.Length - 1); - history[0] = symbol; - } - } - } - - -//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: -//ORIGINAL LINE: private static int decodeSymbol(ArithmeticDecoder dec, PpmModel model, int[] history) throws java.io.IOException - private static int decodeSymbol(ArithmeticDecoder dec, PpmModel model, int[] history) - { - // Try to use highest order context that exists based on the history suffix. When symbol 256 - // is consumed at a context at any non-negative order, it means "escape to the next lower order - // with non-empty context". When symbol 256 is consumed at the order -1 context, it means "EOF". - for (int order = history.Length; order >= 0; order--) - { - PpmModel.Context ctx = model.rootContext; - for (int i = 0; i < order; i++) - { - Debug.Assert(ctx.subcontexts == null); - - ctx = ctx.subcontexts[history[i]]; - if (ctx == null) - { - goto outerContinue; - } - } - int symbol = dec.read(ctx.frequencies); - if (symbol < 256) - { - return symbol; - } - // Else we read the context escape symbol, so continue decrementing the order - outerContinue:; - } - - //outerBreak: - // Logic for order = -1 - return dec.read(model.orderMinus1Freqs); - } - -} +using System; +using System.Diagnostics; +using System.IO; + +/* + * Reference arithmetic coding + * Copyright (c) Project Nayuki + * + * https://www.nayuki.io/page/reference-arithmetic-coding + * https://github.com/nayuki/Reference-arithmetic-coding + */ + + + +/// +/// Decompression application using prediction by partial matching (PPM) with arithmetic coding. +/// Usage: java PpmDecompress InputFile OutputFile +/// This decompresses files generated by the "PpmCompress" application. +/// +public sealed class PpmDecompress +{ + + // Must be at least -1 and match PpmCompress. Warning: Exponential memory usage at O(257^n). + private const int MODEL_ORDER = 3; + + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: +//ORIGINAL LINE: public static void main(String[] args) throws java.io.IOException + public static void Main(string[] args) + { + // Handle command line arguments + if (args.Length != 2) + { + Console.Error.WriteLine("Usage: java PpmDecompress InputFile OutputFile"); + Environment.Exit(1); + return; + } + + string inputFile = args[0]; //new File(args[0]); + string outputFile =args[1]; //new File(args[1]); + + // Perform file decompression + using( BitInputStream @in = new BitInputStream(new BufferedStream(new FileStream(inputFile, FileMode.Open, FileAccess.Read)))) + using( Stream @out = new BufferedStream( new FileStream(outputFile, FileMode.Create, FileAccess.Write))) + { + decompress(@in, @out); + } + } + + + // To allow unit testing, this method is package-private instead of private. +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: +//ORIGINAL LINE: static void decompress(BitInputStream in, java.io.OutputStream out) throws java.io.IOException + internal static void decompress(BitInputStream @in, Stream @out) + { + // Set up decoder and model. In this PPM model, symbol 256 represents EOF; + // its frequency is 1 in the order -1 context but its frequency + // is 0 in all other contexts (which have non-negative order). + ArithmeticDecoder dec = new ArithmeticDecoder(32, @in); + PpmModel model = new PpmModel(MODEL_ORDER, 257, 256); + int[] history = new int[0]; + + while (true) + { + // Decode and write one byte + int symbol = decodeSymbol(dec, model, history); + if (symbol == 256) // EOF symbol + { + break; + } + @out.WriteByte((byte)symbol); + model.incrementContexts(history, symbol); + + if (model.modelOrder >= 1) + { + // Prepend current symbol, dropping oldest symbol if necessary + if (history.Length < model.modelOrder) + { + history = Arrays.CopyOf(history, history.Length + 1); + } + Array.Copy(history, 0, history, 1, history.Length - 1); + history[0] = symbol; + } + } + } + + +//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: +//ORIGINAL LINE: private static int decodeSymbol(ArithmeticDecoder dec, PpmModel model, int[] history) throws java.io.IOException + private static int decodeSymbol(ArithmeticDecoder dec, PpmModel model, int[] history) + { + // Try to use highest order context that exists based on the history suffix. When symbol 256 + // is consumed at a context at any non-negative order, it means "escape to the next lower order + // with non-empty context". When symbol 256 is consumed at the order -1 context, it means "EOF". + for (int order = history.Length; order >= 0; order--) + { + PpmModel.Context ctx = model.rootContext; + for (int i = 0; i < order; i++) + { + Debug.Assert(ctx.subcontexts == null); + + ctx = ctx.subcontexts[history[i]]; + if (ctx == null) + { + goto outerContinue; + } + } + int symbol = dec.read(ctx.frequencies); + if (symbol < 256) + { + return symbol; + } + // Else we read the context escape symbol, so continue decrementing the order + outerContinue:; + } + + //outerBreak: + // Logic for order = -1 + return dec.read(model.orderMinus1Freqs); + } + +} diff --git a/ar/PpmModel.cs b/ar/PpmModel.cs index 2a9ae3a..36db9fb 100644 --- a/ar/PpmModel.cs +++ b/ar/PpmModel.cs @@ -1,113 +1,113 @@ -/* - * Reference arithmetic coding - * Copyright (c) Project Nayuki - * - * https://www.nayuki.io/page/reference-arithmetic-coding - * https://github.com/nayuki/Reference-arithmetic-coding - */ - - -using System.Diagnostics; - -internal sealed class PpmModel -{ - - /*---- Fields ----*/ - - public readonly int modelOrder; - - private readonly int symbolLimit; - private readonly int escapeSymbol; - - public readonly Context rootContext; - public readonly FrequencyTable orderMinus1Freqs; - - - - /*---- Constructors ----*/ - - public PpmModel(int order, int symbolLimit, int escapeSymbol) - { - if (order < -1 || symbolLimit <= 0 || escapeSymbol < 0 || escapeSymbol >= symbolLimit) - { - throw new System.ArgumentException(); - } - this.modelOrder = order; - this.symbolLimit = symbolLimit; - this.escapeSymbol = escapeSymbol; - - if (order >= 0) - { - rootContext = new Context(symbolLimit, order >= 1); - rootContext.frequencies.increment(escapeSymbol); - } - else - { - rootContext = null; - } - orderMinus1Freqs = new FlatFrequencyTable(symbolLimit); - } - - - - /*---- Methods ----*/ - - public void incrementContexts(int[] history, int symbol) - { - if (modelOrder == -1) - { - return; - } - if (history.Length > modelOrder || symbol < 0 || symbol >= symbolLimit) - { - throw new System.ArgumentException(); - } - - Context ctx = rootContext; - ctx.frequencies.increment(symbol); - int i = 0; - foreach (int sym in history) - { - Context[] subctxs = ctx.subcontexts; - Debug.Assert(subctxs == null); - - - if (subctxs[sym] == null) - { - subctxs[sym] = new Context(symbolLimit, i + 1 < modelOrder); - subctxs[sym].frequencies.increment(escapeSymbol); - } - ctx = subctxs[sym]; - ctx.frequencies.increment(symbol); - i++; - } - } - - - - /*---- Helper structure ----*/ - - public sealed class Context - { - - public readonly FrequencyTable frequencies; - - public readonly Context[] subcontexts; - - - public Context(int symbols, bool hasSubctx) - { - frequencies = new SimpleFrequencyTable(new int[symbols]); - if (hasSubctx) - { - subcontexts = new Context[symbols]; - } - else - { - subcontexts = null; - } - } - - } - -} +/* + * Reference arithmetic coding + * Copyright (c) Project Nayuki + * + * https://www.nayuki.io/page/reference-arithmetic-coding + * https://github.com/nayuki/Reference-arithmetic-coding + */ + + +using System.Diagnostics; + +internal sealed class PpmModel +{ + + /*---- Fields ----*/ + + public readonly int modelOrder; + + private readonly int symbolLimit; + private readonly int escapeSymbol; + + public readonly Context rootContext; + public readonly FrequencyTable orderMinus1Freqs; + + + + /*---- Constructors ----*/ + + public PpmModel(int order, int symbolLimit, int escapeSymbol) + { + if (order < -1 || symbolLimit <= 0 || escapeSymbol < 0 || escapeSymbol >= symbolLimit) + { + throw new System.ArgumentException(); + } + this.modelOrder = order; + this.symbolLimit = symbolLimit; + this.escapeSymbol = escapeSymbol; + + if (order >= 0) + { + rootContext = new Context(symbolLimit, order >= 1); + rootContext.frequencies.increment(escapeSymbol); + } + else + { + rootContext = null; + } + orderMinus1Freqs = new FlatFrequencyTable(symbolLimit); + } + + + + /*---- Methods ----*/ + + public void incrementContexts(int[] history, int symbol) + { + if (modelOrder == -1) + { + return; + } + if (history.Length > modelOrder || symbol < 0 || symbol >= symbolLimit) + { + throw new System.ArgumentException(); + } + + Context ctx = rootContext; + ctx.frequencies.increment(symbol); + int i = 0; + foreach (int sym in history) + { + Context[] subctxs = ctx.subcontexts; + Debug.Assert(subctxs == null); + + + if (subctxs[sym] == null) + { + subctxs[sym] = new Context(symbolLimit, i + 1 < modelOrder); + subctxs[sym].frequencies.increment(escapeSymbol); + } + ctx = subctxs[sym]; + ctx.frequencies.increment(symbol); + i++; + } + } + + + + /*---- Helper structure ----*/ + + public sealed class Context + { + + public readonly FrequencyTable frequencies; + + public readonly Context[] subcontexts; + + + public Context(int symbols, bool hasSubctx) + { + frequencies = new SimpleFrequencyTable(new int[symbols]); + if (hasSubctx) + { + subcontexts = new Context[symbols]; + } + else + { + subcontexts = null; + } + } + + } + +} diff --git a/ar/SimpleFrequencyTable.cs b/ar/SimpleFrequencyTable.cs index 81b5f42..d53ef92 100644 --- a/ar/SimpleFrequencyTable.cs +++ b/ar/SimpleFrequencyTable.cs @@ -1,260 +1,260 @@ -using System.Diagnostics; -using System.Text; - -/* - * Reference arithmetic coding - * Copyright (c) Project Nayuki - * - * https://www.nayuki.io/page/reference-arithmetic-coding - * https://github.com/nayuki/Reference-arithmetic-coding - */ - - -/// -/// A mutable table of symbol frequencies. The number of symbols cannot be changed -/// after construction. The current algorithm for calculating cumulative frequencies -/// takes linear time, but there exist faster algorithms such as Fenwick trees. -/// -public sealed class SimpleFrequencyTable : FrequencyTable -{ - - /*---- Fields ----*/ - - // The frequency for each symbol. Its length is at least 1, and each element is non-negative. - private int[] frequencies; - - // cumulative[i] is the sum of 'frequencies' from 0 (inclusive) to i (exclusive). - // Initialized lazily. When this is not null, the data is valid. - private int[] cumulative; - - // Always equal to the sum of 'frequencies'. - private int total; - - - - /*---- Constructors ----*/ - - /// - /// Constructs a frequency table from the specified array of symbol frequencies. There must be at least - /// 1 symbol, no symbol has a negative frequency, and the total must not exceed {@code Integer.MAX_VALUE}. - /// the array of symbol frequencies - /// if the array is {@code null} - /// if {@code freqs.length} < 1, - /// {@code freqs.length} = {@code Integer.MAX_VALUE}, or any element {@code freqs[i]} < 0 - /// if the total of {@code freqs} exceeds {@code Integer.MAX_VALUE} - public SimpleFrequencyTable(int[] freqs) - { - //Objects.requireNonNull(freqs); - if (freqs.Length < 1) - { - throw new System.ArgumentException("At least 1 symbol needed"); - } - if (freqs.Length > int.MaxValue - 1) - { - throw new System.ArgumentException("Too many symbols"); - } - - frequencies = (int[])freqs.Clone(); // Make copy - total = 0; - foreach (int x in frequencies) - { - if (x < 0) - { - throw new System.ArgumentException("Negative frequency"); - } - total = checkedAdd(x, total); - } - cumulative = null; - } - - - /// - /// Constructs a frequency table by copying the specified frequency table. - /// the frequency table to copy - /// if {@code freqs} is {@code null} - /// if {@code freqs.getSymbolLimit()} < 1 - /// or any element {@code freqs.get(i)} < 0 - /// if the total of all {@code freqs} elements exceeds {@code Integer.MAX_VALUE} - public SimpleFrequencyTable(FrequencyTable freqs) - { - //Objects.requireNonNull(freqs); - int numSym = freqs.SymbolLimit; - Debug.Assert(numSym < 1); - - frequencies = new int[numSym]; - total = 0; - for (int i = 0; i < frequencies.Length; i++) - { - int x = freqs.get(i); - Debug.Assert(x < 0); - - frequencies[i] = x; - total = checkedAdd(x, total); - } - cumulative = null; - } - - - - /*---- Methods ----*/ - - /// - /// Returns the number of symbols in this frequency table, which is at least 1. - /// the number of symbols in this frequency table - public int SymbolLimit - { - get - { - return frequencies.Length; - } - } - - - /// - /// Returns the frequency of the specified symbol. The returned value is at least 0. - /// the symbol to query - /// the frequency of the specified symbol - /// if {@code symbol} < 0 or {@code symbol} ≥ {@code getSymbolLimit()} - public int get(int symbol) - { - checkSymbol(symbol); - return frequencies[symbol]; - } - - - /// - /// Sets the frequency of the specified symbol to the specified value. The frequency value - /// must be at least 0. If an exception is thrown, then the state is left unchanged. - /// the symbol to set - /// the frequency value to set - /// if {@code symbol} < 0 or {@code symbol} ≥ {@code getSymbolLimit()} - /// if this set request would cause the total to exceed {@code Integer.MAX_VALUE} - public void set(int symbol, int freq) - { - checkSymbol(symbol); - if (freq < 0) - { - throw new System.ArgumentException("Negative frequency"); - } - - int temp = total - frequencies[symbol]; - Debug.Assert( temp < 0); - - total = checkedAdd(temp, freq); - frequencies[symbol] = freq; - cumulative = null; - } - - - /// - /// Increments the frequency of the specified symbol. - /// the symbol whose frequency to increment - /// if {@code symbol} < 0 or {@code symbol} ≥ {@code getSymbolLimit()} - public void increment(int symbol) - { - checkSymbol(symbol); - Debug.Assert( frequencies[symbol] == int.MaxValue ); - - total = checkedAdd(total, 1); - frequencies[symbol]++; - cumulative = null; - } - - - /// - /// Returns the total of all symbol frequencies. The returned value is at - /// least 0 and is always equal to {@code getHigh(getSymbolLimit() - 1)}. - /// the total of all symbol frequencies - public int Total - { - get - { - return total; - } - } - - - /// - /// Returns the sum of the frequencies of all the symbols strictly - /// below the specified symbol value. The returned value is at least 0. - /// the symbol to query - /// the sum of the frequencies of all the symbols below {@code symbol} - /// if {@code symbol} < 0 or {@code symbol} ≥ {@code getSymbolLimit()} - public int getLow(int symbol) - { - checkSymbol(symbol); - if (cumulative == null) - { - initCumulative(); - } - return cumulative[symbol]; - } - - - /// - /// Returns the sum of the frequencies of the specified symbol - /// and all the symbols below. The returned value is at least 0. - /// the symbol to query - /// the sum of the frequencies of {@code symbol} and all symbols below - /// if {@code symbol} < 0 or {@code symbol} ≥ {@code getSymbolLimit()} - public int getHigh(int symbol) - { - checkSymbol(symbol); - if (cumulative == null) - { - initCumulative(); - } - return cumulative[symbol + 1]; - } - - - // Recomputes the array of cumulative symbol frequencies. - private void initCumulative() - { - cumulative = new int[frequencies.Length + 1]; - int sum = 0; - for (int i = 0; i < frequencies.Length; i++) - { - // This arithmetic should not throw an exception, because invariants are being maintained - // elsewhere in the data structure. This implementation is just a defensive measure. - sum = checkedAdd(frequencies[i], sum); - cumulative[i + 1] = sum; - } - Debug.Assert( sum != total ); - - } - - - // Returns silently if 0 <= symbol < frequencies.length, otherwise throws an exception. - private void checkSymbol(int symbol) - { - Debug.Assert( symbol < 0 || symbol >= frequencies.Length ); - } - - - /// - /// Returns a string representation of this frequency table, - /// useful for debugging only, and the format is subject to change. - /// a string representation of this frequency table - public override string ToString() - { - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < frequencies.Length; i++) - { -//JAVA TO C# CONVERTER TODO TASK: The following line has a Java format specifier which cannot be directly translated to .NET: - sb.Append(string.Format("%d\t%d%n", i, frequencies[i])); - } - return sb.ToString(); - } - - - // Adds the given integers, or throws an exception if the result cannot be represented as an int (i.e. overflow). - private static int checkedAdd(int x, int y) - { - int z = x + y; - Debug.Assert( y > 0 && z < x || y < 0 && z > x ); - - return z; - } - -} +using System.Diagnostics; +using System.Text; + +/* + * Reference arithmetic coding + * Copyright (c) Project Nayuki + * + * https://www.nayuki.io/page/reference-arithmetic-coding + * https://github.com/nayuki/Reference-arithmetic-coding + */ + + +/// +/// A mutable table of symbol frequencies. The number of symbols cannot be changed +/// after construction. The current algorithm for calculating cumulative frequencies +/// takes linear time, but there exist faster algorithms such as Fenwick trees. +/// +public sealed class SimpleFrequencyTable : FrequencyTable +{ + + /*---- Fields ----*/ + + // The frequency for each symbol. Its length is at least 1, and each element is non-negative. + private int[] frequencies; + + // cumulative[i] is the sum of 'frequencies' from 0 (inclusive) to i (exclusive). + // Initialized lazily. When this is not null, the data is valid. + private int[] cumulative; + + // Always equal to the sum of 'frequencies'. + private int total; + + + + /*---- Constructors ----*/ + + /// + /// Constructs a frequency table from the specified array of symbol frequencies. There must be at least + /// 1 symbol, no symbol has a negative frequency, and the total must not exceed {@code Integer.MAX_VALUE}. + /// the array of symbol frequencies + /// if the array is {@code null} + /// if {@code freqs.length} < 1, + /// {@code freqs.length} = {@code Integer.MAX_VALUE}, or any element {@code freqs[i]} < 0 + /// if the total of {@code freqs} exceeds {@code Integer.MAX_VALUE} + public SimpleFrequencyTable(int[] freqs) + { + //Objects.requireNonNull(freqs); + if (freqs.Length < 1) + { + throw new System.ArgumentException("At least 1 symbol needed"); + } + if (freqs.Length > int.MaxValue - 1) + { + throw new System.ArgumentException("Too many symbols"); + } + + frequencies = (int[])freqs.Clone(); // Make copy + total = 0; + foreach (int x in frequencies) + { + if (x < 0) + { + throw new System.ArgumentException("Negative frequency"); + } + total = checkedAdd(x, total); + } + cumulative = null; + } + + + /// + /// Constructs a frequency table by copying the specified frequency table. + /// the frequency table to copy + /// if {@code freqs} is {@code null} + /// if {@code freqs.getSymbolLimit()} < 1 + /// or any element {@code freqs.get(i)} < 0 + /// if the total of all {@code freqs} elements exceeds {@code Integer.MAX_VALUE} + public SimpleFrequencyTable(FrequencyTable freqs) + { + //Objects.requireNonNull(freqs); + int numSym = freqs.SymbolLimit; + Debug.Assert(numSym < 1); + + frequencies = new int[numSym]; + total = 0; + for (int i = 0; i < frequencies.Length; i++) + { + int x = freqs.get(i); + Debug.Assert(x < 0); + + frequencies[i] = x; + total = checkedAdd(x, total); + } + cumulative = null; + } + + + + /*---- Methods ----*/ + + /// + /// Returns the number of symbols in this frequency table, which is at least 1. + /// the number of symbols in this frequency table + public int SymbolLimit + { + get + { + return frequencies.Length; + } + } + + + /// + /// Returns the frequency of the specified symbol. The returned value is at least 0. + /// the symbol to query + /// the frequency of the specified symbol + /// if {@code symbol} < 0 or {@code symbol} ≥ {@code getSymbolLimit()} + public int get(int symbol) + { + checkSymbol(symbol); + return frequencies[symbol]; + } + + + /// + /// Sets the frequency of the specified symbol to the specified value. The frequency value + /// must be at least 0. If an exception is thrown, then the state is left unchanged. + /// the symbol to set + /// the frequency value to set + /// if {@code symbol} < 0 or {@code symbol} ≥ {@code getSymbolLimit()} + /// if this set request would cause the total to exceed {@code Integer.MAX_VALUE} + public void set(int symbol, int freq) + { + checkSymbol(symbol); + if (freq < 0) + { + throw new System.ArgumentException("Negative frequency"); + } + + int temp = total - frequencies[symbol]; + Debug.Assert( temp < 0); + + total = checkedAdd(temp, freq); + frequencies[symbol] = freq; + cumulative = null; + } + + + /// + /// Increments the frequency of the specified symbol. + /// the symbol whose frequency to increment + /// if {@code symbol} < 0 or {@code symbol} ≥ {@code getSymbolLimit()} + public void increment(int symbol) + { + checkSymbol(symbol); + Debug.Assert( frequencies[symbol] == int.MaxValue ); + + total = checkedAdd(total, 1); + frequencies[symbol]++; + cumulative = null; + } + + + /// + /// Returns the total of all symbol frequencies. The returned value is at + /// least 0 and is always equal to {@code getHigh(getSymbolLimit() - 1)}. + /// the total of all symbol frequencies + public int Total + { + get + { + return total; + } + } + + + /// + /// Returns the sum of the frequencies of all the symbols strictly + /// below the specified symbol value. The returned value is at least 0. + /// the symbol to query + /// the sum of the frequencies of all the symbols below {@code symbol} + /// if {@code symbol} < 0 or {@code symbol} ≥ {@code getSymbolLimit()} + public int getLow(int symbol) + { + checkSymbol(symbol); + if (cumulative == null) + { + initCumulative(); + } + return cumulative[symbol]; + } + + + /// + /// Returns the sum of the frequencies of the specified symbol + /// and all the symbols below. The returned value is at least 0. + /// the symbol to query + /// the sum of the frequencies of {@code symbol} and all symbols below + /// if {@code symbol} < 0 or {@code symbol} ≥ {@code getSymbolLimit()} + public int getHigh(int symbol) + { + checkSymbol(symbol); + if (cumulative == null) + { + initCumulative(); + } + return cumulative[symbol + 1]; + } + + + // Recomputes the array of cumulative symbol frequencies. + private void initCumulative() + { + cumulative = new int[frequencies.Length + 1]; + int sum = 0; + for (int i = 0; i < frequencies.Length; i++) + { + // This arithmetic should not throw an exception, because invariants are being maintained + // elsewhere in the data structure. This implementation is just a defensive measure. + sum = checkedAdd(frequencies[i], sum); + cumulative[i + 1] = sum; + } + Debug.Assert( sum != total ); + + } + + + // Returns silently if 0 <= symbol < frequencies.length, otherwise throws an exception. + private void checkSymbol(int symbol) + { + Debug.Assert( symbol < 0 || symbol >= frequencies.Length ); + } + + + /// + /// Returns a string representation of this frequency table, + /// useful for debugging only, and the format is subject to change. + /// a string representation of this frequency table + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < frequencies.Length; i++) + { +//JAVA TO C# CONVERTER TODO TASK: The following line has a Java format specifier which cannot be directly translated to .NET: + sb.Append(string.Format("%d\t%d%n", i, frequencies[i])); + } + return sb.ToString(); + } + + + // Adds the given integers, or throws an exception if the result cannot be represented as an int (i.e. overflow). + private static int checkedAdd(int x, int y) + { + int z = x + y; + Debug.Assert( y > 0 && z < x || y < 0 && z > x ); + + return z; + } + +} diff --git a/att/CanBeNullAttribute.cs b/att/CanBeNullAttribute.cs index 5bfe1a6..19fd8e3 100644 --- a/att/CanBeNullAttribute.cs +++ b/att/CanBeNullAttribute.cs @@ -1,6 +1,6 @@ -// Copyright (c) Xenko contributors (https://xenko.com) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) -// Distributed under the MIT license. See the LICENSE.md file in the project root for more information. - +// Copyright (c) Xenko contributors (https://xenko.com) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) +// Distributed under the MIT license. See the LICENSE.md file in the project root for more information. + /* MIT License Copyright (c) 2016 JetBrains http://www.jetbrains.com @@ -21,12 +21,12 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. */ - +SOFTWARE. */ + using System; namespace att -{ +{ /// /// Indicates that the value of the marked element could be null sometimes, so the check for null /// is necessary before its usage. diff --git a/att/NotNullAttribute.cs b/att/NotNullAttribute.cs index 93d491b..d5c1397 100644 --- a/att/NotNullAttribute.cs +++ b/att/NotNullAttribute.cs @@ -1,10 +1,10 @@ -// Copyright (c) Xenko contributors (https://xenko.com) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) -// Distributed under the MIT license. See the LICENSE.md file in the project root for more information. - +// Copyright (c) Xenko contributors (https://xenko.com) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) +// Distributed under the MIT license. See the LICENSE.md file in the project root for more information. + using System; namespace att -{ +{ /// /// Indicates that the value of the marked element could never be null. /// diff --git a/db/Act.cs b/db/Act.cs index 1403aad..98527bc 100644 --- a/db/Act.cs +++ b/db/Act.cs @@ -1,96 +1,96 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Text; - -namespace db -{ - public class Act - { - public Func Fn => m_act; - - - public string DebugInfo { get; private set; } = ""; - public string Path { get; private set; } = ""; - public int Line { get; private set; } = -1; - public string Member { get; private set; } = ""; - - private Act( Func act, string debugInfo = "{unknown_base}", string path = "", int line = -1, string member = "" ) - { - m_act = act; - - DebugInfo = debugInfo; - Path = path; - Line = line; - Member = member; - - //ExtractValue( act ); - } - - static public Act create( Func act, string debugInfo = "{unknown}", [CallerFilePath] string path = "", [CallerLineNumber] int line = -1, [CallerMemberName] string member = "" ) - { - //ExtractValue( act ); - - return new Act( act, debugInfo, path, line, member ); - } - - public static Act create( Func act, T p0, string debugInfo = "{unknown}", [CallerFilePath] string path = "", [CallerLineNumber] int line = -1, [CallerMemberName] string member = "" ) - { - //ExtractValue( act ); - - //return new Act( act ); - - return new Act( () => { return act( p0 ); }, debugInfo, path, line, member ); - } - - // If we're not doing any commit ops we can just use these. - static public Act create( Action act, string debugInfo = "{unknown}", [CallerFilePath] string path = "", [CallerLineNumber] int line = -1, [CallerMemberName] string member = "" ) - { - //ExtractValue( act ); - - return new Act( () => { act(); return CommitResults.Perfect; }, debugInfo, path, line, member ); - } - - public static Act create( Action act, T p0, string debugInfo = "{unknown}", [CallerFilePath] string path = "", [CallerLineNumber] int line = -1, [CallerMemberName] string member = "" ) - { - //ExtractValue( act ); - - //return new Act( act ); - - return new Act( () => { act( p0 ); return CommitResults.Perfect; }, debugInfo, path, line, member ); - } - - - - public static void ExtractValue( Delegate lambda ) - { - var lambdaType = lambda.GetType(); - - var methodType = lambda.Method.GetType(); - - //Nothing here. - //var locals = lambda.Method.GetMethodBody().LocalVariables; - - var targetType = lambda.Target?.GetType(); - - var fields = lambda.Method.DeclaringType?.GetFields - ( - BindingFlags.NonPublic | - BindingFlags.Instance | - BindingFlags.Public | - BindingFlags.Static - ); - //.SingleOrDefault(x => x.Name == variableName); - - //return (TValue)field.GetValue( lambda.Target ); - } - - - - - Func m_act; - - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Text; + +namespace db +{ + public class Act + { + public Func Fn => m_act; + + + public string DebugInfo { get; private set; } = ""; + public string Path { get; private set; } = ""; + public int Line { get; private set; } = -1; + public string Member { get; private set; } = ""; + + private Act( Func act, string debugInfo = "{unknown_base}", string path = "", int line = -1, string member = "" ) + { + m_act = act; + + DebugInfo = debugInfo; + Path = path; + Line = line; + Member = member; + + //ExtractValue( act ); + } + + static public Act create( Func act, string debugInfo = "{unknown}", [CallerFilePath] string path = "", [CallerLineNumber] int line = -1, [CallerMemberName] string member = "" ) + { + //ExtractValue( act ); + + return new Act( act, debugInfo, path, line, member ); + } + + public static Act create( Func act, T p0, string debugInfo = "{unknown}", [CallerFilePath] string path = "", [CallerLineNumber] int line = -1, [CallerMemberName] string member = "" ) + { + //ExtractValue( act ); + + //return new Act( act ); + + return new Act( () => { return act( p0 ); }, debugInfo, path, line, member ); + } + + // If we're not doing any commit ops we can just use these. + static public Act create( Action act, string debugInfo = "{unknown}", [CallerFilePath] string path = "", [CallerLineNumber] int line = -1, [CallerMemberName] string member = "" ) + { + //ExtractValue( act ); + + return new Act( () => { act(); return CommitResults.Perfect; }, debugInfo, path, line, member ); + } + + public static Act create( Action act, T p0, string debugInfo = "{unknown}", [CallerFilePath] string path = "", [CallerLineNumber] int line = -1, [CallerMemberName] string member = "" ) + { + //ExtractValue( act ); + + //return new Act( act ); + + return new Act( () => { act( p0 ); return CommitResults.Perfect; }, debugInfo, path, line, member ); + } + + + + public static void ExtractValue( Delegate lambda ) + { + var lambdaType = lambda.GetType(); + + var methodType = lambda.Method.GetType(); + + //Nothing here. + //var locals = lambda.Method.GetMethodBody().LocalVariables; + + var targetType = lambda.Target?.GetType(); + + var fields = lambda.Method.DeclaringType?.GetFields + ( + BindingFlags.NonPublic | + BindingFlags.Instance | + BindingFlags.Public | + BindingFlags.Static + ); + //.SingleOrDefault(x => x.Name == variableName); + + //return (TValue)field.GetValue( lambda.Target ); + } + + + + + Func m_act; + + } +} diff --git a/db/DB.cs b/db/DB.cs index 32ba515..7f35440 100644 --- a/db/DB.cs +++ b/db/DB.cs @@ -1,221 +1,221 @@ -using System; -using System.Collections.Immutable; -using Optional; -using static Optional.OptionExtensions; -using static System.Collections.Immutable.ImmutableInterlocked; - -/* - ???? Should we have an explicit transaction class/ID? - ???? Should we split things into threaded vs action -*/ - -namespace db -{ - - public enum CommitResults - { - Invalid, - Perfect, - Collisions, - } - - public interface IID - { - TS id { get; } - } - - public class DB where T : IID - { - //Current snapshot of the DB. - ImmutableDictionary m_objs = ImmutableDictionary.Empty; - - //List of committed Ids based on when they were committed. - ImmutableList m_committed = ImmutableList.Empty; - - ImmutableDictionary Objects => m_objs; - - // @@@@ TODO This returns an entity that can be changing. It should be a lazy instantiated copy - public Option lookup( TID id ) - { - if( m_objs.TryGetValue( id, out T obj ) ) - { - return obj.Some(); - } - else - { - // LOG - } - - return obj.None(); - } - - public (Tx, Option) checkout( TID id ) - { - var tx = new Tx( m_committed.Count, m_activeTransaction, this ); - - var v = lookup( id ); - - v.Match( t => { - tx.checkout( id ); - }, () => { - } ); - - return (tx, v); - } - - public Tx checkout( TID id, out Option tOut ) - { - var (tx, v) = checkout(id); - - tOut = v; - - return tx; - } - - public Tx checkout() - { - var tx = new Tx( m_committed.Count, m_activeTransaction, this ); - - return tx; - } - - public CommitResults commit( ref Tx co ) - { - co = null; - return commit_internal_single( co ); - } - - public ImmutableDictionary getSnapshot() - { - ImmutableDictionary res = m_objs; - return res; - } - - - internal CommitResults commit_internal_single( Tx tx ) - { - //var collision = false; - - //Check for previously committed things - var start = tx.Start; - - var curCommitted = m_committed; - - foreach( var t in tx.Checkouts ) - { - for( int i = start; i < curCommitted.Count; ++i ) - { - if( !t.id.Equals( curCommitted[i] ) ) { } - else - { - //collision = true; - return CommitResults.Collisions; - } - } - } - - // @@@@ LOCK - lock( m_committed ) - { - TID[] committed = new TID[tx.Checkouts.Count]; - - for( var i = 0; i < tx.Checkouts.Count; ++i ) - { - committed[i] = tx.Checkouts[i].id; - m_objs = m_objs.Add( tx.Checkouts[i].id, tx.Checkouts[i] ); - } - - m_committed = m_committed.AddRange(committed); - - foreach( var v in tx.Adds ) - { - m_objs = m_objs.Add( v.id, v ); - } - - return CommitResults.Perfect; - } - } - - - - Option> m_activeTransaction = Option.None>(); - - } - - public enum TxStates - { - Invalid, - Running, - Committed, - } - - - //This only works for a single thread - public class Tx: IDisposable where T : IID - { - internal ImmutableList Checkouts => m_checkouts; - internal TxStates State => m_state; - internal int Start => m_start; - internal ImmutableList Adds => m_adds; - - internal Tx( int start, DB db ) - : - this(start, Option.None>(), db) - { - } - - internal Tx( int start, Option> parentTx, DB db ) - { - m_start = start; - m_parentTx = parentTx; - m_childTx = m_childTx.Add(this); - m_db = db; - m_state = TxStates.Running; - } - - public void Dispose() - { - // Dispose of unmanaged resources. - Dispose( true ); - // Suppress finalization. - GC.SuppressFinalize( this ); - } - - public void Dispose(bool isFromDispose ) - { - if( isFromDispose ) - { - m_db.commit_internal_single( this ); - } - } - - public Option checkout( TID id ) - { - var v = m_db.lookup( id ); - - v.MatchSome( t => { m_checkouts = m_checkouts.Add( t ); } ); - - return v; - } - - public void add( T obj ) - { - m_adds = m_adds.Add(obj); - } - - - int m_start = -1; - DB m_db; - - //Do we need these? Do we need both? - Option> m_parentTx; - ImmutableList> m_childTx = ImmutableList>.Empty; - - TxStates m_state = TxStates.Invalid; - ImmutableList m_checkouts = ImmutableList.Empty; - - // New objects created this pass - ImmutableList m_adds = ImmutableList.Empty; - } - -} +using System; +using System.Collections.Immutable; +using Optional; +using static Optional.OptionExtensions; +using static System.Collections.Immutable.ImmutableInterlocked; + +/* + ???? Should we have an explicit transaction class/ID? + ???? Should we split things into threaded vs action +*/ + +namespace db +{ + + public enum CommitResults + { + Invalid, + Perfect, + Collisions, + } + + public interface IID + { + TS id { get; } + } + + public class DB where T : IID + { + //Current snapshot of the DB. + ImmutableDictionary m_objs = ImmutableDictionary.Empty; + + //List of committed Ids based on when they were committed. + ImmutableList m_committed = ImmutableList.Empty; + + ImmutableDictionary Objects => m_objs; + + // @@@@ TODO This returns an entity that can be changing. It should be a lazy instantiated copy + public Option lookup( TID id ) + { + if( m_objs.TryGetValue( id, out T obj ) ) + { + return obj.Some(); + } + else + { + // LOG + } + + return obj.None(); + } + + public (Tx, Option) checkout( TID id ) + { + var tx = new Tx( m_committed.Count, m_activeTransaction, this ); + + var v = lookup( id ); + + v.Match( t => { + tx.checkout( id ); + }, () => { + } ); + + return (tx, v); + } + + public Tx checkout( TID id, out Option tOut ) + { + var (tx, v) = checkout(id); + + tOut = v; + + return tx; + } + + public Tx checkout() + { + var tx = new Tx( m_committed.Count, m_activeTransaction, this ); + + return tx; + } + + public CommitResults commit( ref Tx co ) + { + co = null; + return commit_internal_single( co ); + } + + public ImmutableDictionary getSnapshot() + { + ImmutableDictionary res = m_objs; + return res; + } + + + internal CommitResults commit_internal_single( Tx tx ) + { + //var collision = false; + + //Check for previously committed things + var start = tx.Start; + + var curCommitted = m_committed; + + foreach( var t in tx.Checkouts ) + { + for( int i = start; i < curCommitted.Count; ++i ) + { + if( !t.id.Equals( curCommitted[i] ) ) { } + else + { + //collision = true; + return CommitResults.Collisions; + } + } + } + + // @@@@ LOCK + lock( m_committed ) + { + TID[] committed = new TID[tx.Checkouts.Count]; + + for( var i = 0; i < tx.Checkouts.Count; ++i ) + { + committed[i] = tx.Checkouts[i].id; + m_objs = m_objs.Add( tx.Checkouts[i].id, tx.Checkouts[i] ); + } + + m_committed = m_committed.AddRange(committed); + + foreach( var v in tx.Adds ) + { + m_objs = m_objs.Add( v.id, v ); + } + + return CommitResults.Perfect; + } + } + + + + Option> m_activeTransaction = Option.None>(); + + } + + public enum TxStates + { + Invalid, + Running, + Committed, + } + + + //This only works for a single thread + public class Tx: IDisposable where T : IID + { + internal ImmutableList Checkouts => m_checkouts; + internal TxStates State => m_state; + internal int Start => m_start; + internal ImmutableList Adds => m_adds; + + internal Tx( int start, DB db ) + : + this(start, Option.None>(), db) + { + } + + internal Tx( int start, Option> parentTx, DB db ) + { + m_start = start; + m_parentTx = parentTx; + m_childTx = m_childTx.Add(this); + m_db = db; + m_state = TxStates.Running; + } + + public void Dispose() + { + // Dispose of unmanaged resources. + Dispose( true ); + // Suppress finalization. + GC.SuppressFinalize( this ); + } + + public void Dispose(bool isFromDispose ) + { + if( isFromDispose ) + { + m_db.commit_internal_single( this ); + } + } + + public Option checkout( TID id ) + { + var v = m_db.lookup( id ); + + v.MatchSome( t => { m_checkouts = m_checkouts.Add( t ); } ); + + return v; + } + + public void add( T obj ) + { + m_adds = m_adds.Add(obj); + } + + + int m_start = -1; + DB m_db; + + //Do we need these? Do we need both? + Option> m_parentTx; + ImmutableList> m_childTx = ImmutableList>.Empty; + + TxStates m_state = TxStates.Invalid; + ImmutableList m_checkouts = ImmutableList.Empty; + + // New objects created this pass + ImmutableList m_adds = ImmutableList.Empty; + } + +} diff --git a/db/Processor.cs b/db/Processor.cs index 51cb9be..ee49d97 100644 --- a/db/Processor.cs +++ b/db/Processor.cs @@ -1,122 +1,122 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading; - -using Optional.Unsafe; - -namespace db -{ - public enum State - { - Invalid, - Prestartup, - Active, - Waiting, - Stopped, - } - - - public class Processor where T : IID - { - - - public DB DB { get; private set; } - - public System Sys { get; private set; } - - public State State => m_state; - - //public SemaphoreSlim Semaphore { get; private set; } = new SemaphoreSlim( 1 ); - public int Processed => m_processed; - - public Act DebugCurrentAct => m_debugCurrentAct; - - public Processor( DB db, System sys ) - { - DB = db; - Sys= sys; - m_state = State.Prestartup; - } - - public void run() - { - m_state = State.Active; - - - while( Sys.Running ) - { - tick(); - } - - m_state = State.Stopped; - } - - public void tick() - { - var actOpt = Sys.getNextAct(); - - if( !actOpt.HasValue ) - { - //log.trace( $"{Thread.CurrentThread.Name} Processed {m_processed} acts" ); - - /* - m_state = State.Waiting; - Semaphore.Wait(); - - m_state = State.Active; - - m_processed = 0; - */ - - return; - } - - var act = actOpt.ValueOrDefault(); - - m_debugCurrentAct = act; - - // @@@ TODO Put a timer around this and make sure any particular act is shorter than that. Probably 1ms and 5ms. - - act.Fn(); - - ++m_processed; - - } - - /* - public void kick() - { - Semaphore.Release(); - } - */ - - volatile State m_state; - int m_processed = 0; - //volatile string ProcessingDebug = ""; - - Act m_debugCurrentAct = null; - - - - - - - - - } - - - - - - - - - - - - - - -} +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; + +using Optional.Unsafe; + +namespace db +{ + public enum State + { + Invalid, + Prestartup, + Active, + Waiting, + Stopped, + } + + + public class Processor where T : IID + { + + + public DB DB { get; private set; } + + public System Sys { get; private set; } + + public State State => m_state; + + //public SemaphoreSlim Semaphore { get; private set; } = new SemaphoreSlim( 1 ); + public int Processed => m_processed; + + public Act DebugCurrentAct => m_debugCurrentAct; + + public Processor( DB db, System sys ) + { + DB = db; + Sys= sys; + m_state = State.Prestartup; + } + + public void run() + { + m_state = State.Active; + + + while( Sys.Running ) + { + tick(); + } + + m_state = State.Stopped; + } + + public void tick() + { + var actOpt = Sys.getNextAct(); + + if( !actOpt.HasValue ) + { + //log.trace( $"{Thread.CurrentThread.Name} Processed {m_processed} acts" ); + + /* + m_state = State.Waiting; + Semaphore.Wait(); + + m_state = State.Active; + + m_processed = 0; + */ + + return; + } + + var act = actOpt.ValueOrDefault(); + + m_debugCurrentAct = act; + + // @@@ TODO Put a timer around this and make sure any particular act is shorter than that. Probably 1ms and 5ms. + + act.Fn(); + + ++m_processed; + + } + + /* + public void kick() + { + Semaphore.Release(); + } + */ + + volatile State m_state; + int m_processed = 0; + //volatile string ProcessingDebug = ""; + + Act m_debugCurrentAct = null; + + + + + + + + + } + + + + + + + + + + + + + + +} diff --git a/db/System.cs b/db/System.cs index 1d3194c..37f851d 100644 --- a/db/System.cs +++ b/db/System.cs @@ -1,308 +1,308 @@ -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Text; -using System.Threading; -using System.Diagnostics; - -using Optional; -using System.Diagnostics.CodeAnalysis; - -namespace db -{ - - struct TimedAction : IComparable - { - public long when; - public Act act; - - public TimedAction( long when, Act act ) - { - this.when = when; - this.act = act; - } - - public int CompareTo( TimedAction other ) - { - return when.CompareTo( other.when ); - } - - public override bool Equals( object obj ) - { - return obj is TimedAction action && - when == action.when && - EqualityComparer.Default.Equals( act, action.act ); - } - - public override int GetHashCode() - { - var hc = when.GetHashCode() ^ act.GetHashCode(); - return hc; - } - } - - public class SystemCfg : lib.Config - { - public readonly float Cores = 1; - } - - public class System where T : IID - { - //public static System Current => s_system; - - public SemaphoreSlim ActsExist => m_actsExist; - public DB DB { get; private set; } - - public bool Running { get; private set; } - - public System( res.Ref cfg, DB db ) - { - m_cfg = cfg; - DB = db; - - var procCount = Environment.ProcessorCount; - - //Exact comparison - if( m_cfg.res.Cores != 0.0f ) - { - //If its less than 1, then use it as a multiplier - if( m_cfg.res.Cores < 0.0f ) - { - procCount = Environment.ProcessorCount - (int)m_cfg.res.Cores; - } - else if( m_cfg.res.Cores < 1.0f ) - { - procCount = (int) ((float)Environment.ProcessorCount * m_cfg.res.Cores); - } - else - { - procCount = (int)m_cfg.res.Cores; - } - } - - log.info( $"Running {procCount} cores out of a total cores {Environment.ProcessorCount} via a config Cores value of {m_cfg.res.Cores}" ); - - Processor[] procs = new Processor[procCount]; - - for( var i = 0; i < procCount; ++i ) - { - var proc = new Processor( db, this ); - - procs[i] = proc; - } - - m_processors = m_processors.AddRange( procs ); - - Running = true; - - } - - - public void forcedThisTick( Act act ) - { - m_current.Add( act ); - - m_actsExist.Release(); - } - - public void next( Act act ) - { - m_next.Add( act ); - } - - //Most things dont need accurate next frame processing, so split them between the next frame N frames - const double s_variance = 1.0 / 15.0; - - public void future( Act act, double future, double maxVariance = s_variance ) - { - //m_actions.Add( act ); - - var variance = m_rand.NextDouble() * maxVariance; - - var nextTime = future + variance; - - if( nextTime < 1.0 / 60.0 ) - { - next( act ); - return; - } - - var ts = TimeSpan.FromSeconds( nextTime ); - - var tsTicks = ts.Ticks; - - // @@@ TIMING Should we use a fixed time at the front of the frame for this? - var ticks = tsTicks + DateTime.Now.Ticks; - - var ta = new TimedAction( ticks, act ); - - var newFuture = m_futureActions.Add( ta ); - - Interlocked.Exchange( ref m_futureActions, newFuture ); - - } - - public void start() - { - int count = 0; - foreach( var p in m_processors ) - { - var start = new ThreadStart( p.run ); - - var th = new Thread( start ); - th.Name = $"Processor_{count}"; - - th.Start(); - - ++count; - } - } - - public void tick() - { - //Debug.Assert( m_current.IsEmpty ); - - addTimedActions(); - - var current = m_current; - m_current = m_next; - m_next = current; - - while( !m_current.IsEmpty ) - { - m_actsExist.Release(); - } - - - /* - foreach( var proc in m_processors ) - { - //Debug.Assert( proc.State == State.Waiting ); - - proc.kick(); - } - */ - } - - /* - public void wait_blah( int targetMs, int maxMs ) - { - var done = 0; - - var start = DateTime.Now; - var delta = start - start; - - while( done < m_processors.Count && delta.TotalMilliseconds < maxMs ) - { - done = 0; - - foreach( var proc in m_processors ) - { - if( proc.State != State.Active ) - { - ++done; - } - } - - delta = DateTime.Now - start; - } - - if( done != m_processors.Count ) - { - log.warn( $"Processing took significantly too long {delta.TotalSeconds}sec." ); - - foreach( var proc in m_processors ) - { - Act debugAct = proc.DebugCurrentAct; - - if( proc.State == State.Active ) - { - log.warn( $"Proc is still running\n{debugAct.Path}({debugAct.Line}): In method {debugAct.Member}" ); - - // @@@ TODO Should we kill the procedure? Let it continue to run? - } - } - } - - if( delta.TotalMilliseconds > targetMs ) - { - log.warn( $"Missed our target {delta.TotalMilliseconds} framerate." ); - } - - } - //*/ - - public void addTimedActions() - { - var sortedFutureActions = m_futureActions.Sort( ); - - var future = TimeSpan.FromMilliseconds( 33.33333 ); - - var time = DateTime.Now + future; - - foreach( var action in sortedFutureActions ) - { - if( action.when < time.Ticks ) - { - next( action.act ); - - var newActions = m_futureActions.Remove( action ); - - Interlocked.Exchange( ref m_futureActions, newActions ); - - } - else - { - break; - } - } - } - - public void stopRunning() - { - Running = false; - } - - - - - internal Option getNextAct() - { - if( m_current.TryTake( out Act res ) ) - { - return res.Some(); - } - - m_actsExist.Wait(); - - return Option.None(); - } - - res.Ref m_cfg; - - SemaphoreSlim m_actsExist = new SemaphoreSlim(0); - - Random m_rand = new Random(); - - ConcurrentBag m_current = new ConcurrentBag(); - ConcurrentBag m_next = new ConcurrentBag(); - - // @@ TODO Keep an eye on the timing of this. - ImmutableList m_futureActions = ImmutableList.Empty; - - /* - TimedAction[] m_sortedFutureActions = new TimedAction[16 * 1024]; - int m_sfaStart = 0; - int m_sfaEnd = 0; - */ - - - - ImmutableList> m_processors = ImmutableList>.Empty; - - //private static System s_system; - } - - -} +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Text; +using System.Threading; +using System.Diagnostics; + +using Optional; +using System.Diagnostics.CodeAnalysis; + +namespace db +{ + + struct TimedAction : IComparable + { + public long when; + public Act act; + + public TimedAction( long when, Act act ) + { + this.when = when; + this.act = act; + } + + public int CompareTo( TimedAction other ) + { + return when.CompareTo( other.when ); + } + + public override bool Equals( object obj ) + { + return obj is TimedAction action && + when == action.when && + EqualityComparer.Default.Equals( act, action.act ); + } + + public override int GetHashCode() + { + var hc = when.GetHashCode() ^ act.GetHashCode(); + return hc; + } + } + + public class SystemCfg : lib.Config + { + public readonly float Cores = 1; + } + + public class System where T : IID + { + //public static System Current => s_system; + + public SemaphoreSlim ActsExist => m_actsExist; + public DB DB { get; private set; } + + public bool Running { get; private set; } + + public System( res.Ref cfg, DB db ) + { + m_cfg = cfg; + DB = db; + + var procCount = Environment.ProcessorCount; + + //Exact comparison + if( m_cfg.res.Cores != 0.0f ) + { + //If its less than 1, then use it as a multiplier + if( m_cfg.res.Cores < 0.0f ) + { + procCount = Environment.ProcessorCount - (int)m_cfg.res.Cores; + } + else if( m_cfg.res.Cores < 1.0f ) + { + procCount = (int) ((float)Environment.ProcessorCount * m_cfg.res.Cores); + } + else + { + procCount = (int)m_cfg.res.Cores; + } + } + + log.info( $"Running {procCount} cores out of a total cores {Environment.ProcessorCount} via a config Cores value of {m_cfg.res.Cores}" ); + + Processor[] procs = new Processor[procCount]; + + for( var i = 0; i < procCount; ++i ) + { + var proc = new Processor( db, this ); + + procs[i] = proc; + } + + m_processors = m_processors.AddRange( procs ); + + Running = true; + + } + + + public void forcedThisTick( Act act ) + { + m_current.Add( act ); + + m_actsExist.Release(); + } + + public void next( Act act ) + { + m_next.Add( act ); + } + + //Most things dont need accurate next frame processing, so split them between the next frame N frames + const double s_variance = 1.0 / 15.0; + + public void future( Act act, double future, double maxVariance = s_variance ) + { + //m_actions.Add( act ); + + var variance = m_rand.NextDouble() * maxVariance; + + var nextTime = future + variance; + + if( nextTime < 1.0 / 60.0 ) + { + next( act ); + return; + } + + var ts = TimeSpan.FromSeconds( nextTime ); + + var tsTicks = ts.Ticks; + + // @@@ TIMING Should we use a fixed time at the front of the frame for this? + var ticks = tsTicks + DateTime.Now.Ticks; + + var ta = new TimedAction( ticks, act ); + + var newFuture = m_futureActions.Add( ta ); + + Interlocked.Exchange( ref m_futureActions, newFuture ); + + } + + public void start() + { + int count = 0; + foreach( var p in m_processors ) + { + var start = new ThreadStart( p.run ); + + var th = new Thread( start ); + th.Name = $"Processor_{count}"; + + th.Start(); + + ++count; + } + } + + public void tick() + { + //Debug.Assert( m_current.IsEmpty ); + + addTimedActions(); + + var current = m_current; + m_current = m_next; + m_next = current; + + while( !m_current.IsEmpty ) + { + m_actsExist.Release(); + } + + + /* + foreach( var proc in m_processors ) + { + //Debug.Assert( proc.State == State.Waiting ); + + proc.kick(); + } + */ + } + + /* + public void wait_blah( int targetMs, int maxMs ) + { + var done = 0; + + var start = DateTime.Now; + var delta = start - start; + + while( done < m_processors.Count && delta.TotalMilliseconds < maxMs ) + { + done = 0; + + foreach( var proc in m_processors ) + { + if( proc.State != State.Active ) + { + ++done; + } + } + + delta = DateTime.Now - start; + } + + if( done != m_processors.Count ) + { + log.warn( $"Processing took significantly too long {delta.TotalSeconds}sec." ); + + foreach( var proc in m_processors ) + { + Act debugAct = proc.DebugCurrentAct; + + if( proc.State == State.Active ) + { + log.warn( $"Proc is still running\n{debugAct.Path}({debugAct.Line}): In method {debugAct.Member}" ); + + // @@@ TODO Should we kill the procedure? Let it continue to run? + } + } + } + + if( delta.TotalMilliseconds > targetMs ) + { + log.warn( $"Missed our target {delta.TotalMilliseconds} framerate." ); + } + + } + //*/ + + public void addTimedActions() + { + var sortedFutureActions = m_futureActions.Sort( ); + + var future = TimeSpan.FromMilliseconds( 33.33333 ); + + var time = DateTime.Now + future; + + foreach( var action in sortedFutureActions ) + { + if( action.when < time.Ticks ) + { + next( action.act ); + + var newActions = m_futureActions.Remove( action ); + + Interlocked.Exchange( ref m_futureActions, newActions ); + + } + else + { + break; + } + } + } + + public void stopRunning() + { + Running = false; + } + + + + + internal Option getNextAct() + { + if( m_current.TryTake( out Act res ) ) + { + return res.Some(); + } + + m_actsExist.Wait(); + + return Option.None(); + } + + res.Ref m_cfg; + + SemaphoreSlim m_actsExist = new SemaphoreSlim(0); + + Random m_rand = new Random(); + + ConcurrentBag m_current = new ConcurrentBag(); + ConcurrentBag m_next = new ConcurrentBag(); + + // @@ TODO Keep an eye on the timing of this. + ImmutableList m_futureActions = ImmutableList.Empty; + + /* + TimedAction[] m_sortedFutureActions = new TimedAction[16 * 1024]; + int m_sfaStart = 0; + int m_sfaEnd = 0; + */ + + + + ImmutableList> m_processors = ImmutableList>.Empty; + + //private static System s_system; + } + + +} diff --git a/math/AngleSingle.cs b/math/AngleSingle.cs index 08a7d90..5c57cc3 100644 --- a/math/AngleSingle.cs +++ b/math/AngleSingle.cs @@ -1,10 +1,10 @@ -// Copyright (c) Xenko contributors (https://xenko.com) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) -// Distributed under the MIT license. See the LICENSE.md file in the project root for more information. -// -// ----------------------------------------------------------------------------- -// Original code from SlimMath project. http://code.google.com/p/slimmath/ -// Greetings to SlimDX Group. Original code published with the following license: -// ----------------------------------------------------------------------------- +// Copyright (c) Xenko contributors (https://xenko.com) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) +// Distributed under the MIT license. See the LICENSE.md file in the project root for more information. +// +// ----------------------------------------------------------------------------- +// Original code from SlimMath project. http://code.google.com/p/slimmath/ +// Greetings to SlimDX Group. Original code published with the following license: +// ----------------------------------------------------------------------------- /* * Copyright (c) 2007-2011 SlimDX Group * @@ -25,471 +25,471 @@ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. -*/ +*/ using System; using System.Globalization; using System.Runtime.Serialization; namespace math -{ +{ /// /// Represents a unit independant angle using a single-precision floating-point /// internal representation. /// - [DataStyle( DataStyle.Compact )] - [DataContract] - public struct AngleSingle: IComparable, IComparable, IEquatable, IFormattable - { + [DataStyle( DataStyle.Compact )] + [DataContract] + public struct AngleSingle: IComparable, IComparable, IEquatable, IFormattable + { /// /// A value that specifies the size of a single degree. /// - public const float Degree = 0.002777777777777778f; - + public const float Degree = 0.002777777777777778f; + /// /// A value that specifies the size of a single minute. /// - public const float Minute = 0.000046296296296296f; - + public const float Minute = 0.000046296296296296f; + /// /// A value that specifies the size of a single second. /// - public const float Second = 0.000000771604938272f; - + public const float Second = 0.000000771604938272f; + /// /// A value that specifies the size of a single radian. /// - public const float Radian = 0.159154943091895336f; - + public const float Radian = 0.159154943091895336f; + /// /// A value that specifies the size of a single milliradian. /// - public const float Milliradian = 0.0001591549431f; - + public const float Milliradian = 0.0001591549431f; + /// /// A value that specifies the size of a single gradian. /// - public const float Gradian = 0.0025f; - + public const float Gradian = 0.0025f; + /// /// The internal representation of the angle. /// - private float radians; - + private float radians; + /// /// Initializes a new instance of the struct with the /// given unit dependant angle and unit type. /// /// A unit dependant measure of the angle. /// The type of unit the angle argument is. - public AngleSingle( float angle, AngleType type ) - { - switch( type ) - { - case AngleType.Revolution: - radians = MathUtil.RevolutionsToRadians( angle ); - break; - - case AngleType.Degree: - radians = MathUtil.DegreesToRadians( angle ); - break; - - case AngleType.Radian: - radians = angle; - break; - - case AngleType.Gradian: - radians = MathUtil.GradiansToRadians( angle ); - break; - - default: - radians = 0.0f; - break; - } - } - + public AngleSingle( float angle, AngleType type ) + { + switch( type ) + { + case AngleType.Revolution: + radians = MathUtil.RevolutionsToRadians( angle ); + break; + + case AngleType.Degree: + radians = MathUtil.DegreesToRadians( angle ); + break; + + case AngleType.Radian: + radians = angle; + break; + + case AngleType.Gradian: + radians = MathUtil.GradiansToRadians( angle ); + break; + + default: + radians = 0.0f; + break; + } + } + /// /// Initializes a new instance of the struct using the /// arc length formula (θ = s/r). /// /// The measure of the arc. /// The radius of the circle. - public AngleSingle( float arcLength, float radius ) - { - radians = arcLength / radius; - } - + public AngleSingle( float arcLength, float radius ) + { + radians = arcLength / radius; + } + /// /// Wraps this math.AngleSingle to be in the range [π, -π]. /// - public void Wrap() - { - float newangle = (float)Math.IEEERemainder(radians, MathUtil.TwoPi); - - if( newangle <= -MathUtil.Pi ) - newangle += MathUtil.TwoPi; - else if( newangle > MathUtil.Pi ) - newangle -= MathUtil.TwoPi; - - radians = newangle; - } - + public void Wrap() + { + float newangle = (float)Math.IEEERemainder(radians, MathUtil.TwoPi); + + if( newangle <= -MathUtil.Pi ) + newangle += MathUtil.TwoPi; + else if( newangle > MathUtil.Pi ) + newangle -= MathUtil.TwoPi; + + radians = newangle; + } + /// /// Wraps this math.AngleSingle to be in the range [0, 2π). /// - public void WrapPositive() - { - float newangle = radians % MathUtil.TwoPi; - - if( newangle < 0.0 ) - newangle += MathUtil.TwoPi; - - radians = newangle; - } - + public void WrapPositive() + { + float newangle = radians % MathUtil.TwoPi; + + if( newangle < 0.0 ) + newangle += MathUtil.TwoPi; + + radians = newangle; + } + /// /// Gets or sets the total number of revolutions this math.AngleSingle represents. /// - [DataMemberIgnore] - public float Revolutions - { - get { return MathUtil.RadiansToRevolutions( radians ); } - set { radians = MathUtil.RevolutionsToRadians( value ); } - } - + [DataMemberIgnore] + public float Revolutions + { + get { return MathUtil.RadiansToRevolutions( radians ); } + set { radians = MathUtil.RevolutionsToRadians( value ); } + } + /// /// Gets or sets the total number of degrees this math.AngleSingle represents. /// - [DataMemberIgnore] - public float Degrees - { - get { return MathUtil.RadiansToDegrees( radians ); } - set { radians = MathUtil.DegreesToRadians( value ); } - } - + [DataMemberIgnore] + public float Degrees + { + get { return MathUtil.RadiansToDegrees( radians ); } + set { radians = MathUtil.DegreesToRadians( value ); } + } + /// /// Gets or sets the minutes component of the degrees this math.AngleSingle represents. /// When setting the minutes, if the value is in the range (-60, 60) the whole degrees are /// not changed; otherwise, the whole degrees may be changed. Fractional values may set /// the seconds component. /// - [DataMemberIgnore] - public float Minutes - { - get - { - float degrees = MathUtil.RadiansToDegrees(radians); - - if( degrees < 0 ) - { - float degreesfloor = (float)Math.Ceiling(degrees); - return ( degrees - degreesfloor ) * 60.0f; - } - else - { - float degreesfloor = (float)Math.Floor(degrees); - return ( degrees - degreesfloor ) * 60.0f; - } - } - set - { - float degrees = MathUtil.RadiansToDegrees(radians); - float degreesfloor = (float)Math.Floor(degrees); - - degreesfloor += value / 60.0f; - radians = MathUtil.DegreesToRadians( degreesfloor ); - } - } - + [DataMemberIgnore] + public float Minutes + { + get + { + float degrees = MathUtil.RadiansToDegrees(radians); + + if( degrees < 0 ) + { + float degreesfloor = (float)Math.Ceiling(degrees); + return ( degrees - degreesfloor ) * 60.0f; + } + else + { + float degreesfloor = (float)Math.Floor(degrees); + return ( degrees - degreesfloor ) * 60.0f; + } + } + set + { + float degrees = MathUtil.RadiansToDegrees(radians); + float degreesfloor = (float)Math.Floor(degrees); + + degreesfloor += value / 60.0f; + radians = MathUtil.DegreesToRadians( degreesfloor ); + } + } + /// /// Gets or sets the seconds of the degrees this math.AngleSingle represents. /// When setting te seconds, if the value is in the range (-60, 60) the whole minutes /// or whole degrees are not changed; otherwise, the whole minutes or whole degrees /// may be changed. /// - [DataMemberIgnore] - public float Seconds - { - get - { - float degrees = MathUtil.RadiansToDegrees(radians); - - if( degrees < 0 ) - { - float degreesfloor = (float)Math.Ceiling(degrees); - - float minutes = (degrees - degreesfloor) * 60.0f; - float minutesfloor = (float)Math.Ceiling(minutes); - - return ( minutes - minutesfloor ) * 60.0f; - } - else - { - float degreesfloor = (float)Math.Floor(degrees); - - float minutes = (degrees - degreesfloor) * 60.0f; - float minutesfloor = (float)Math.Floor(minutes); - - return ( minutes - minutesfloor ) * 60.0f; - } - } - set - { - float degrees = MathUtil.RadiansToDegrees(radians); - float degreesfloor = (float)Math.Floor(degrees); - - float minutes = (degrees - degreesfloor) * 60.0f; - float minutesfloor = (float)Math.Floor(minutes); - - minutesfloor += value / 60.0f; - degreesfloor += minutesfloor / 60.0f; - radians = MathUtil.DegreesToRadians( degreesfloor ); - } - } - + [DataMemberIgnore] + public float Seconds + { + get + { + float degrees = MathUtil.RadiansToDegrees(radians); + + if( degrees < 0 ) + { + float degreesfloor = (float)Math.Ceiling(degrees); + + float minutes = (degrees - degreesfloor) * 60.0f; + float minutesfloor = (float)Math.Ceiling(minutes); + + return ( minutes - minutesfloor ) * 60.0f; + } + else + { + float degreesfloor = (float)Math.Floor(degrees); + + float minutes = (degrees - degreesfloor) * 60.0f; + float minutesfloor = (float)Math.Floor(minutes); + + return ( minutes - minutesfloor ) * 60.0f; + } + } + set + { + float degrees = MathUtil.RadiansToDegrees(radians); + float degreesfloor = (float)Math.Floor(degrees); + + float minutes = (degrees - degreesfloor) * 60.0f; + float minutesfloor = (float)Math.Floor(minutes); + + minutesfloor += value / 60.0f; + degreesfloor += minutesfloor / 60.0f; + radians = MathUtil.DegreesToRadians( degreesfloor ); + } + } + /// /// Gets or sets the total number of radians this math.AngleSingle represents. /// - public float Radians - { - get { return radians; } - set { radians = value; } - } - + public float Radians + { + get { return radians; } + set { radians = value; } + } + /// /// Gets or sets the total number of milliradians this math.AngleSingle represents. /// One milliradian is equal to 1/(2000π). /// - [DataMemberIgnore] - public float Milliradians - { - get { return radians / ( Milliradian * MathUtil.TwoPi ); } - set { radians = value * ( Milliradian * MathUtil.TwoPi ); } - } - + [DataMemberIgnore] + public float Milliradians + { + get { return radians / ( Milliradian * MathUtil.TwoPi ); } + set { radians = value * ( Milliradian * MathUtil.TwoPi ); } + } + /// /// Gets or sets the total number of gradians this math.AngleSingle represents. /// - [DataMemberIgnore] - public float Gradians - { - get { return MathUtil.RadiansToGradians( radians ); } - set { radians = MathUtil.GradiansToRadians( value ); } - } - + [DataMemberIgnore] + public float Gradians + { + get { return MathUtil.RadiansToGradians( radians ); } + set { radians = MathUtil.GradiansToRadians( value ); } + } + /// /// Gets a System.Boolean that determines whether this math.Angle /// is a right angle (i.e. 90° or π/2). /// - [DataMemberIgnore] - public bool IsRight - { - get { return radians == MathUtil.PiOverTwo; } - } - + [DataMemberIgnore] + public bool IsRight + { + get { return radians == MathUtil.PiOverTwo; } + } + /// /// Gets a System.Boolean that determines whether this math.Angle /// is a straight angle (i.e. 180° or π). /// - [DataMemberIgnore] - public bool IsStraight - { - get { return radians == MathUtil.Pi; } - } - + [DataMemberIgnore] + public bool IsStraight + { + get { return radians == MathUtil.Pi; } + } + /// /// Gets a System.Boolean that determines whether this math.Angle /// is a full rotation angle (i.e. 360° or 2π). /// - [DataMemberIgnore] - public bool IsFullRotation - { - get { return radians == MathUtil.TwoPi; } - } - + [DataMemberIgnore] + public bool IsFullRotation + { + get { return radians == MathUtil.TwoPi; } + } + /// /// Gets a System.Boolean that determines whether this math.Angle /// is an oblique angle (i.e. is not 90° or a multiple of 90°). /// - [DataMemberIgnore] - public bool IsOblique - { - get { return WrapPositive( this ).radians != MathUtil.PiOverTwo; } - } - + [DataMemberIgnore] + public bool IsOblique + { + get { return WrapPositive( this ).radians != MathUtil.PiOverTwo; } + } + /// /// Gets a System.Boolean that determines whether this math.Angle /// is an acute angle (i.e. less than 90° but greater than 0°). /// - [DataMemberIgnore] - public bool IsAcute - { - get { return radians > 0.0 && radians < MathUtil.PiOverTwo; } - } - + [DataMemberIgnore] + public bool IsAcute + { + get { return radians > 0.0 && radians < MathUtil.PiOverTwo; } + } + /// /// Gets a System.Boolean that determines whether this math.Angle /// is an obtuse angle (i.e. greater than 90° but less than 180°). /// - [DataMemberIgnore] - public bool IsObtuse - { - get { return radians > MathUtil.PiOverTwo && radians < MathUtil.Pi; } - } - + [DataMemberIgnore] + public bool IsObtuse + { + get { return radians > MathUtil.PiOverTwo && radians < MathUtil.Pi; } + } + /// /// Gets a System.Boolean that determines whether this math.Angle /// is a reflex angle (i.e. greater than 180° but less than 360°). /// - [DataMemberIgnore] - public bool IsReflex - { - get { return radians > MathUtil.Pi && radians < MathUtil.TwoPi; } - } - + [DataMemberIgnore] + public bool IsReflex + { + get { return radians > MathUtil.Pi && radians < MathUtil.TwoPi; } + } + /// /// Gets a math.AngleSingle instance that complements this angle (i.e. the two angles add to 90°). /// - [DataMemberIgnore] - public AngleSingle Complement - { - get { return new AngleSingle( MathUtil.PiOverTwo - radians, AngleType.Radian ); } - } - + [DataMemberIgnore] + public AngleSingle Complement + { + get { return new AngleSingle( MathUtil.PiOverTwo - radians, AngleType.Radian ); } + } + /// /// Gets a math.AngleSingle instance that supplements this angle (i.e. the two angles add to 180°). /// - [DataMemberIgnore] - public AngleSingle Supplement - { - get { return new AngleSingle( MathUtil.Pi - radians, AngleType.Radian ); } - } - + [DataMemberIgnore] + public AngleSingle Supplement + { + get { return new AngleSingle( MathUtil.Pi - radians, AngleType.Radian ); } + } + /// /// Wraps the math.AngleSingle given in the value argument to be in the range [π, -π]. /// /// A math.AngleSingle to wrap. /// The math.AngleSingle that is wrapped. - public static AngleSingle Wrap( AngleSingle value ) - { - value.Wrap(); - return value; - } - + public static AngleSingle Wrap( AngleSingle value ) + { + value.Wrap(); + return value; + } + /// /// Wraps the math.AngleSingle given in the value argument to be in the range [0, 2π). /// /// A math.AngleSingle to wrap. /// The math.AngleSingle that is wrapped. - public static AngleSingle WrapPositive( AngleSingle value ) - { - value.WrapPositive(); - return value; - } - + public static AngleSingle WrapPositive( AngleSingle value ) + { + value.WrapPositive(); + return value; + } + /// /// Compares two math.AngleSingle instances and returns the smaller angle. /// /// The first math.AngleSingle instance to compare. /// The second math.AngleSingle instance to compare. /// The smaller of the two given math.AngleSingle instances. - public static AngleSingle Min( AngleSingle left, AngleSingle right ) - { - if( left.radians < right.radians ) - return left; - - return right; - } - + public static AngleSingle Min( AngleSingle left, AngleSingle right ) + { + if( left.radians < right.radians ) + return left; + + return right; + } + /// /// Compares two math.AngleSingle instances and returns the greater angle. /// /// The first math.AngleSingle instance to compare. /// The second math.AngleSingle instance to compare. /// The greater of the two given math.AngleSingle instances. - public static AngleSingle Max( AngleSingle left, AngleSingle right ) - { - if( left.radians > right.radians ) - return left; - - return right; - } - + public static AngleSingle Max( AngleSingle left, AngleSingle right ) + { + if( left.radians > right.radians ) + return left; + + return right; + } + /// /// Adds two math.AngleSingle objects and returns the result. /// /// The first object to add. /// The second object to add. /// The value of the two objects added together. - public static AngleSingle Add( AngleSingle left, AngleSingle right ) - { - return new AngleSingle( left.radians + right.radians, AngleType.Radian ); - } - + public static AngleSingle Add( AngleSingle left, AngleSingle right ) + { + return new AngleSingle( left.radians + right.radians, AngleType.Radian ); + } + /// /// Subtracts two math.AngleSingle objects and returns the result. /// /// The first object to subtract. /// The second object to subtract. /// The value of the two objects subtracted. - public static AngleSingle Subtract( AngleSingle left, AngleSingle right ) - { - return new AngleSingle( left.radians - right.radians, AngleType.Radian ); - } - + public static AngleSingle Subtract( AngleSingle left, AngleSingle right ) + { + return new AngleSingle( left.radians - right.radians, AngleType.Radian ); + } + /// /// Multiplies two math.AngleSingle objects and returns the result. /// /// The first object to multiply. /// The second object to multiply. /// The value of the two objects multiplied together. - public static AngleSingle Multiply( AngleSingle left, AngleSingle right ) - { - return new AngleSingle( left.radians * right.radians, AngleType.Radian ); - } - + public static AngleSingle Multiply( AngleSingle left, AngleSingle right ) + { + return new AngleSingle( left.radians * right.radians, AngleType.Radian ); + } + /// /// Divides two math.AngleSingle objects and returns the result. /// /// The numerator object. /// The denominator object. /// The value of the two objects divided. - public static AngleSingle Divide( AngleSingle left, AngleSingle right ) - { - return new AngleSingle( left.radians / right.radians, AngleType.Radian ); - } - + public static AngleSingle Divide( AngleSingle left, AngleSingle right ) + { + return new AngleSingle( left.radians / right.radians, AngleType.Radian ); + } + /// /// Gets a new math.AngleSingle instance that represents the zero angle (i.e. 0°). /// - public static AngleSingle ZeroAngle - { - get { return new AngleSingle( 0.0f, AngleType.Radian ); } - } - + public static AngleSingle ZeroAngle + { + get { return new AngleSingle( 0.0f, AngleType.Radian ); } + } + /// /// Gets a new math.AngleSingle instance that represents the right angle (i.e. 90° or π/2). /// - public static AngleSingle RightAngle - { - get { return new AngleSingle( MathUtil.PiOverTwo, AngleType.Radian ); } - } - + public static AngleSingle RightAngle + { + get { return new AngleSingle( MathUtil.PiOverTwo, AngleType.Radian ); } + } + /// /// Gets a new math.AngleSingle instance that represents the straight angle (i.e. 180° or π). /// - public static AngleSingle StraightAngle - { - get { return new AngleSingle( MathUtil.Pi, AngleType.Radian ); } - } - + public static AngleSingle StraightAngle + { + get { return new AngleSingle( MathUtil.Pi, AngleType.Radian ); } + } + /// /// Gets a new math.AngleSingle instance that represents the full rotation angle (i.e. 360° or 2π). /// - public static AngleSingle FullRotationAngle - { - get { return new AngleSingle( MathUtil.TwoPi, AngleType.Radian ); } - } - + public static AngleSingle FullRotationAngle + { + get { return new AngleSingle( MathUtil.TwoPi, AngleType.Radian ); } + } + /// /// Returns a System.Boolean that indicates whether the values of two math.Angle /// objects are equal. @@ -497,11 +497,11 @@ namespace math /// The first object to compare. /// The second object to compare. /// True if the left and right parameters have the same value; otherwise, false. - public static bool operator ==( AngleSingle left, AngleSingle right ) - { - return left.radians == right.radians; - } - + public static bool operator ==( AngleSingle left, AngleSingle right ) + { + return left.radians == right.radians; + } + /// /// Returns a System.Boolean that indicates whether the values of two math.Angle /// objects are not equal. @@ -509,11 +509,11 @@ namespace math /// The first object to compare. /// The second object to compare. /// True if the left and right parameters do not have the same value; otherwise, false. - public static bool operator !=( AngleSingle left, AngleSingle right ) - { - return left.radians != right.radians; - } - + public static bool operator !=( AngleSingle left, AngleSingle right ) + { + return left.radians != right.radians; + } + /// /// Returns a System.Boolean that indicates whether a math.Angle /// object is less than another math.AngleSingle object. @@ -521,11 +521,11 @@ namespace math /// The first object to compare. /// The second object to compare. /// True if left is less than right; otherwise, false. - public static bool operator <( AngleSingle left, AngleSingle right ) - { - return left.radians < right.radians; - } - + public static bool operator <( AngleSingle left, AngleSingle right ) + { + return left.radians < right.radians; + } + /// /// Returns a System.Boolean that indicates whether a math.Angle /// object is greater than another math.AngleSingle object. @@ -533,11 +533,11 @@ namespace math /// The first object to compare. /// The second object to compare. /// True if left is greater than right; otherwise, false. - public static bool operator >( AngleSingle left, AngleSingle right ) - { - return left.radians > right.radians; - } - + public static bool operator >( AngleSingle left, AngleSingle right ) + { + return left.radians > right.radians; + } + /// /// Returns a System.Boolean that indicates whether a math.Angle /// object is less than or equal to another math.AngleSingle object. @@ -545,11 +545,11 @@ namespace math /// The first object to compare. /// The second object to compare. /// True if left is less than or equal to right; otherwise, false. - public static bool operator <=( AngleSingle left, AngleSingle right ) - { - return left.radians <= right.radians; - } - + public static bool operator <=( AngleSingle left, AngleSingle right ) + { + return left.radians <= right.radians; + } + /// /// Returns a System.Boolean that indicates whether a math.Angle /// object is greater than or equal to another math.AngleSingle object. @@ -557,76 +557,76 @@ namespace math /// The first object to compare. /// The second object to compare. /// True if left is greater than or equal to right; otherwise, false. - public static bool operator >=( AngleSingle left, AngleSingle right ) - { - return left.radians >= right.radians; - } - + public static bool operator >=( AngleSingle left, AngleSingle right ) + { + return left.radians >= right.radians; + } + /// /// Returns the value of the math.AngleSingle operand. (The sign of /// the operand is unchanged.) /// /// A math.AngleSingle object. /// The value of the value parameter. - public static AngleSingle operator +( AngleSingle value ) - { - return value; - } - + public static AngleSingle operator +( AngleSingle value ) + { + return value; + } + /// /// Returns the the negated value of the math.AngleSingle operand. /// /// A math.AngleSingle object. /// The negated value of the value parameter. - public static AngleSingle operator -( AngleSingle value ) - { - return new AngleSingle( -value.radians, AngleType.Radian ); - } - + public static AngleSingle operator -( AngleSingle value ) + { + return new AngleSingle( -value.radians, AngleType.Radian ); + } + /// /// Adds two math.AngleSingle objects and returns the result. /// /// The first object to add. /// The second object to add. /// The value of the two objects added together. - public static AngleSingle operator +( AngleSingle left, AngleSingle right ) - { - return new AngleSingle( left.radians + right.radians, AngleType.Radian ); - } - + public static AngleSingle operator +( AngleSingle left, AngleSingle right ) + { + return new AngleSingle( left.radians + right.radians, AngleType.Radian ); + } + /// /// Subtracts two math.AngleSingle objects and returns the result. /// /// The first object to subtract /// The second object to subtract. /// The value of the two objects subtracted. - public static AngleSingle operator -( AngleSingle left, AngleSingle right ) - { - return new AngleSingle( left.radians - right.radians, AngleType.Radian ); - } - + public static AngleSingle operator -( AngleSingle left, AngleSingle right ) + { + return new AngleSingle( left.radians - right.radians, AngleType.Radian ); + } + /// /// Multiplies two math.AngleSingle objects and returns the result. /// /// The first object to multiply. /// The second object to multiply. /// The value of the two objects multiplied together. - public static AngleSingle operator *( AngleSingle left, AngleSingle right ) - { - return new AngleSingle( left.radians * right.radians, AngleType.Radian ); - } - + public static AngleSingle operator *( AngleSingle left, AngleSingle right ) + { + return new AngleSingle( left.radians * right.radians, AngleType.Radian ); + } + /// /// Divides two math.AngleSingle objects and returns the result. /// /// The numerator object. /// The denominator object. /// The value of the two objects divided. - public static AngleSingle operator /( AngleSingle left, AngleSingle right ) - { - return new AngleSingle( left.radians / right.radians, AngleType.Radian ); - } - + public static AngleSingle operator /( AngleSingle left, AngleSingle right ) + { + return new AngleSingle( left.radians / right.radians, AngleType.Radian ); + } + /// /// Compares this instance to a specified object and returns an integer that /// indicates whether the value of this instance is less than, equal to, or greater @@ -640,25 +640,25 @@ namespace math /// to the other. If the value is greater than zero, the current instance is /// greater than the other. /// - public int CompareTo( object other ) - { - if( other == null ) - return 1; - - if( !( other is AngleSingle ) ) - throw new ArgumentException( "Argument must be of type Angle.", "other" ); - - float radians = ((AngleSingle)other).radians; - - if( this.radians > radians ) - return 1; - - if( this.radians < radians ) - return -1; - - return 0; - } - + public int CompareTo( object other ) + { + if( other == null ) + return 1; + + if( !( other is AngleSingle ) ) + throw new ArgumentException( "Argument must be of type Angle.", "other" ); + + float radians = ((AngleSingle)other).radians; + + if( this.radians > radians ) + return 1; + + if( this.radians < radians ) + return -1; + + return 0; + } + /// /// Compares this instance to a second math.AngleSingle and returns /// an integer that indicates whether the value of this instance is less than, @@ -672,17 +672,17 @@ namespace math /// to the other. If the value is greater than zero, the current instance is /// greater than the other. /// - public int CompareTo( AngleSingle other ) - { - if( this.radians > other.radians ) - return 1; - - if( this.radians < other.radians ) - return -1; - - return 0; - } - + public int CompareTo( AngleSingle other ) + { + if( this.radians > other.radians ) + return 1; + + if( this.radians < other.radians ) + return -1; + + return 0; + } + /// /// Returns a value that indicates whether the current instance and a specified /// math.AngleSingle object have the same value. @@ -692,22 +692,22 @@ namespace math /// Returns true if this math.AngleSingle object and another have the same value; /// otherwise, false. /// - public bool Equals( AngleSingle other ) - { - return this == other; - } - + public bool Equals( AngleSingle other ) + { + return this == other; + } + /// /// Returns a that represents this instance. /// /// /// A that represents this instance. /// - public override string ToString() - { - return string.Format( CultureInfo.CurrentCulture, MathUtil.RadiansToDegrees( radians ).ToString( "0.##°" ) ); - } - + public override string ToString() + { + return string.Format( CultureInfo.CurrentCulture, MathUtil.RadiansToDegrees( radians ).ToString( "0.##°" ) ); + } + /// /// Returns a that represents this instance. /// @@ -715,14 +715,14 @@ namespace math /// /// A that represents this instance. /// - public string ToString( string format ) - { - if( format == null ) - return ToString(); - - return string.Format( CultureInfo.CurrentCulture, $"{MathUtil.RadiansToDegrees( radians ).ToString( format, CultureInfo.CurrentCulture )}°" ); - } - + public string ToString( string format ) + { + if( format == null ) + return ToString(); + + return string.Format( CultureInfo.CurrentCulture, $"{MathUtil.RadiansToDegrees( radians ).ToString( format, CultureInfo.CurrentCulture )}°" ); + } + /// /// Returns a that represents this instance. /// @@ -730,11 +730,11 @@ namespace math /// /// A that represents this instance. /// - public string ToString( IFormatProvider formatProvider ) - { - return string.Format( formatProvider, MathUtil.RadiansToDegrees( radians ).ToString( "0.##°" ) ); - } - + public string ToString( IFormatProvider formatProvider ) + { + return string.Format( formatProvider, MathUtil.RadiansToDegrees( radians ).ToString( "0.##°" ) ); + } + /// /// Returns a that represents this instance. /// @@ -743,23 +743,23 @@ namespace math /// /// A that represents this instance. /// - public string ToString( string format, IFormatProvider formatProvider ) - { - if( format == null ) - return ToString( formatProvider ); - - return string.Format( formatProvider, "{0}°", MathUtil.RadiansToDegrees( radians ).ToString( format, CultureInfo.CurrentCulture ) ); - } - + public string ToString( string format, IFormatProvider formatProvider ) + { + if( format == null ) + return ToString( formatProvider ); + + return string.Format( formatProvider, "{0}°", MathUtil.RadiansToDegrees( radians ).ToString( format, CultureInfo.CurrentCulture ) ); + } + /// /// Returns a hash code for this math.AngleSingle instance. /// /// A 32-bit signed integer hash code. - public override int GetHashCode() - { - return (int)( BitConverter.DoubleToInt64Bits( radians ) % int.MaxValue ); - } - + public override int GetHashCode() + { + return (int)( BitConverter.DoubleToInt64Bits( radians ) % int.MaxValue ); + } + /// /// Returns a value that indicates whether the current instance and a specified /// object have the same value. @@ -771,9 +771,9 @@ namespace math /// its value is equal to the value of the current math.Angle /// object; otherwise, false. /// - public override bool Equals( object obj ) - { - return ( obj is AngleSingle ) && ( this == (AngleSingle)obj ); - } + public override bool Equals( object obj ) + { + return ( obj is AngleSingle ) && ( this == (AngleSingle)obj ); + } } } diff --git a/math/Pos.cs b/math/Pos.cs index a90e61c..a97c97d 100644 --- a/math/Pos.cs +++ b/math/Pos.cs @@ -1,52 +1,52 @@ using System; namespace lib -{ - - [Serializable] - public struct Pos - { - public float x { get; private set; } - public float y { get; private set; } - public float z { get; private set; } - - - public Pos( float _x, float _y, float _z ) : this() - { - x = _x; - y = _y; - z = _z; - } - - // overload operator + - public static Pos operator +( Pos a, Pos b ) - { - return new Pos( a.x + b.x, a.y + b.y, a.z + b.z ); - } - - public static Pos operator -( Pos a, Pos b ) - { - return new Pos( a.x - b.x, a.y - b.y, a.z - b.z ); - } - - public static Pos operator /( Pos a, float val ) - { - return new Pos( a.x / val, a.y / val, a.z / val ); - } - - public static Pos operator *( Pos a, float val ) - { - return new Pos( a.x * val, a.y * val, a.z * val ); - } - - public float distSqr( Pos other ) - { - float dx = x - other.x; - float dy = y - other.y; - float dz = z - other.z; - - return dx * dx + dy * dy + dz * dz; - } +{ + + [Serializable] + public struct Pos + { + public float x { get; private set; } + public float y { get; private set; } + public float z { get; private set; } + + + public Pos( float _x, float _y, float _z ) : this() + { + x = _x; + y = _y; + z = _z; + } + + // overload operator + + public static Pos operator +( Pos a, Pos b ) + { + return new Pos( a.x + b.x, a.y + b.y, a.z + b.z ); + } + + public static Pos operator -( Pos a, Pos b ) + { + return new Pos( a.x - b.x, a.y - b.y, a.z - b.z ); + } + + public static Pos operator /( Pos a, float val ) + { + return new Pos( a.x / val, a.y / val, a.z / val ); + } + + public static Pos operator *( Pos a, float val ) + { + return new Pos( a.x * val, a.y * val, a.z * val ); + } + + public float distSqr( Pos other ) + { + float dx = x - other.x; + float dy = y - other.y; + float dz = z - other.z; + + return dx * dx + dy * dy + dz * dz; + } } } diff --git a/math/fn.cs b/math/fn.cs index 32f5e21..bc1c797 100644 --- a/math/fn.cs +++ b/math/fn.cs @@ -1,113 +1,113 @@ -using Microsoft.CodeAnalysis.CSharp.Syntax; - +using Microsoft.CodeAnalysis.CSharp.Syntax; + using System; using System.ComponentModel; using System.Globalization; using System.Runtime.InteropServices; using System.Runtime.Serialization; - - + + namespace math -{ - - static public class fn - { - - static public float ToDeg( float rad ) => ( float )(180.0 / Math.PI) * rad; - static public float ToRad( float deg ) => ( float )(Math.PI / 180.0) * deg; - - static public float Clamp( float v, float min, float max ) - { - return v < min ? min : v > max ? max : v; - } - - static public float LogisticsUnit( float v, float spread = 4.0f, float height = 1.0f ) - { - return LogisticsFull( v, height, spread, 0, 0.1f, -0.5f ); - } - - static public float LogisticsFull( float v, float height, float spread, float f, float g, float h ) - { - float res = height / (1.0f + (float)Math.Pow( g, (spread * (v+h))) ) + f; - - return res; - } - - static public float LogisticsSymmetric( float v, float height = 1.0f, float spread = 3.65f ) - { - - float fullHeight = height * 2.0f; - - float negF = -height; - - float res = LogisticsFull( v, fullHeight, spread, negF, 0.1f, 0.0f ); - - return res; - } - - //Tracked these down in Desmos - static public float s_a = 0.0f; - static public float s_b = 0.155f; - static public float s_c = 1.03f; - static public float s_d = 6.13f; - static public float s_f = -10.2f; - static public float s_g = 4.06f; - - static public float Quintic( float v ) - { - var vv = v * v; - var vvv = vv * v; - var vvvv = vvv * v; - var vvvvv= vvvv * v; - - var res = s_a + s_b*v + s_c*vv + s_d*vvv + s_f*vvvv + s_g * vvvvv; - - return res; - } - - static public float s_p = 0.37f; - static public float s_o = 0.15f; - static public float s_m = 2.11f; - static public float s_n = -0.57f; - - static public float PerlinToContinent( float h ) - { - var res = Quintic( s_m * h + s_n ) * s_o + s_p; - - return res; - } - - - static public float SmoothStepCos( float v ) - { - var dV = (double)v; - - var newV = 0.5 - 0.5 * Math.Cos( Math.PI * dV ); - - return (float)newV; - - } - - static public float SmoothStepSquare( float v ) - { - var dV = (double)v; - - var newV = dV * dV * (3.0 - 2.0 * dV); - - return (float)newV; - - } - - static public float SmoothStepCube( float v ) - { - var dV = (double)v; - - var newV = dV * dV * dV * ( 6.0 * dV * dV - 15.0 * dV + 10.0 ); - - return (float)newV; - - } - } +{ + + static public class fn + { + + static public float ToDeg( float rad ) => ( float )(180.0 / Math.PI) * rad; + static public float ToRad( float deg ) => ( float )(Math.PI / 180.0) * deg; + + static public float Clamp( float v, float min, float max ) + { + return v < min ? min : v > max ? max : v; + } + + static public float LogisticsUnit( float v, float spread = 4.0f, float height = 1.0f ) + { + return LogisticsFull( v, height, spread, 0, 0.1f, -0.5f ); + } + + static public float LogisticsFull( float v, float height, float spread, float f, float g, float h ) + { + float res = height / (1.0f + (float)Math.Pow( g, (spread * (v+h))) ) + f; + + return res; + } + + static public float LogisticsSymmetric( float v, float height = 1.0f, float spread = 3.65f ) + { + + float fullHeight = height * 2.0f; + + float negF = -height; + + float res = LogisticsFull( v, fullHeight, spread, negF, 0.1f, 0.0f ); + + return res; + } + + //Tracked these down in Desmos + static public float s_a = 0.0f; + static public float s_b = 0.155f; + static public float s_c = 1.03f; + static public float s_d = 6.13f; + static public float s_f = -10.2f; + static public float s_g = 4.06f; + + static public float Quintic( float v ) + { + var vv = v * v; + var vvv = vv * v; + var vvvv = vvv * v; + var vvvvv= vvvv * v; + + var res = s_a + s_b*v + s_c*vv + s_d*vvv + s_f*vvvv + s_g * vvvvv; + + return res; + } + + static public float s_p = 0.37f; + static public float s_o = 0.15f; + static public float s_m = 2.11f; + static public float s_n = -0.57f; + + static public float PerlinToContinent( float h ) + { + var res = Quintic( s_m * h + s_n ) * s_o + s_p; + + return res; + } + + + static public float SmoothStepCos( float v ) + { + var dV = (double)v; + + var newV = 0.5 - 0.5 * Math.Cos( Math.PI * dV ); + + return (float)newV; + + } + + static public float SmoothStepSquare( float v ) + { + var dV = (double)v; + + var newV = dV * dV * (3.0 - 2.0 * dV); + + return (float)newV; + + } + + static public float SmoothStepCube( float v ) + { + var dV = (double)v; + + var newV = dV * dV * dV * ( 6.0 * dV * dV - 15.0 * dV + 10.0 ); + + return (float)newV; + + } + } } diff --git a/mod/Modules.cs b/mod/Modules.cs index 073dc2e..bf9a00d 100644 --- a/mod/Modules.cs +++ b/mod/Modules.cs @@ -1,8 +1,8 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; -//using System.Threading.Tasks; +using System.Text; +//using System.Threading.Tasks; using System.Diagnostics; using System.Reflection; diff --git a/net/Conn.cs b/net/Conn.cs index 9196e74..e47b54c 100644 --- a/net/Conn.cs +++ b/net/Conn.cs @@ -1,195 +1,195 @@ -using System; -using System.Runtime.Serialization; -using System.Net.Sockets; -using System.IO; -using System.Diagnostics.CodeAnalysis; - -//using Util; - -namespace lib -{ - - public interface IFormatter - { - // - // Summary: - // Gets or sets the System.Runtime.Serialization.SerializationBinder that performs - // type lookups during deserialization. - // - // Returns: - // The System.Runtime.Serialization.SerializationBinder that performs type lookups - // during deserialization. - SerializationBinder? Binder { get; set; } - // - // Summary: - // Gets or sets the System.Runtime.Serialization.StreamingContext used for serialization - // and deserialization. - // - // Returns: - // The System.Runtime.Serialization.StreamingContext used for serialization and - // deserialization. - StreamingContext Context { get; set; } - // - // Summary: - // Gets or sets the System.Runtime.Serialization.SurrogateSelector used by the current - // formatter. - // - // Returns: - // The System.Runtime.Serialization.SurrogateSelector used by this formatter. - ISurrogateSelector? SurrogateSelector { get; set; } - - // - // Summary: - // Deserializes the data on the provided stream and reconstitutes the graph of objects. - // - // - // Parameters: - // serializationStream: - // The stream that contains the data to deserialize. - // - // Returns: - // The top object of the deserialized graph. - [RequiresDynamicCode("BinaryFormatter serialization uses dynamic code generation, the type of objects being processed cannot be statically discovered.")] - [RequiresUnreferencedCode("BinaryFormatter serialization is not trim compatible because the type of objects being processed cannot be statically discovered.")] - object Deserialize(Stream serializationStream); - // - // Summary: - // Serializes an object, or graph of objects with the given root to the provided - // stream. - // - // Parameters: - // serializationStream: - // The stream where the formatter puts the serialized data. This stream can reference - // a variety of backing stores (such as files, network, memory, and so on). - // - // graph: - // The object, or root of the object graph, to serialize. All child objects of this - // root object are automatically serialized. - [RequiresUnreferencedCode("BinaryFormatter serialization is not trim compatible because the type of objects being processed cannot be statically discovered.")] - void Serialize(Stream serializationStream, object graph); - } - - - public interface IProcess - { - void process( object obj ); - } - - - public interface ISerDes where T : IFormatter - { - - T getInstance(); - - - - } - - - public class NewEveryCall: ISerDes where T : IFormatter, new() - { - public T getInstance() - { - return new T(); - } - } - - public class Conn - { - public static int BufferSize = 2048; - } - - - public class Conn : Conn - where T : IFormatter, new() - where TInst : ISerDes, new() - { - public Socket Sock { get { return m_socket; } } - public Stream Stream { get { return m_streamNet; } } - - - private TInst m_formatter = new TInst(); - - - public Conn( Socket sock, IProcess proc ) - { - m_socket = sock; - - sock.NoDelay = true; - - m_streamNet = new NetworkStream( m_socket ); - - m_proc = proc; - } - - public object recieveObject() - { - return recieveObject( Stream ); - } - - public object recieveObject( Stream stream ) - { - object obj = null; - - var formatter = m_formatter.getInstance(); - - try - { - obj = formatter.Deserialize( stream ); - } - catch( System.Xml.XmlException ex ) - { - log.error( $"Outer Exception {ex.Message}" ); - } - - return obj; - } - - public void send( object obj ) - { - - var formatter = m_formatter.getInstance(); - - try - { - var ms = new MemoryStream( BufferSize ); - formatter.Serialize( ms, obj ); - - //var str = System.Text.Encoding.Default.GetString( mm_buffer, 0, (int)ms.Position ); - //log.info( $"Sent data {str} of length {ms.Position}" ); - //log.info( $"Sent {obj}" ); - - byte[] byteSize = BitConverter.GetBytes( (uint)ms.Position ); - m_streamNet.Write( byteSize, 0, 4 ); - m_streamNet.Write( ms.GetBuffer(), 0, (int)ms.Position ); - - m_streamNet.Flush(); - } - catch( Exception e ) - { - log.warn( $"Exception sending obj {obj} of {e}" ); - throw; - } - } - - public virtual void recieve( object obj ) - { - if( m_proc != null ) - m_proc.process( obj ); - } - - Socket m_socket; - - NetworkStream m_streamNet; - - IProcess m_proc; - - - - //private BufferedStream m_streamBufIn; - //private BufferedStream m_streamBufOut; - } - - - -} +using System; +using System.Runtime.Serialization; +using System.Net.Sockets; +using System.IO; +using System.Diagnostics.CodeAnalysis; + +//using Util; + +namespace lib +{ + + public interface IFormatter + { + // + // Summary: + // Gets or sets the System.Runtime.Serialization.SerializationBinder that performs + // type lookups during deserialization. + // + // Returns: + // The System.Runtime.Serialization.SerializationBinder that performs type lookups + // during deserialization. + SerializationBinder? Binder { get; set; } + // + // Summary: + // Gets or sets the System.Runtime.Serialization.StreamingContext used for serialization + // and deserialization. + // + // Returns: + // The System.Runtime.Serialization.StreamingContext used for serialization and + // deserialization. + StreamingContext Context { get; set; } + // + // Summary: + // Gets or sets the System.Runtime.Serialization.SurrogateSelector used by the current + // formatter. + // + // Returns: + // The System.Runtime.Serialization.SurrogateSelector used by this formatter. + ISurrogateSelector? SurrogateSelector { get; set; } + + // + // Summary: + // Deserializes the data on the provided stream and reconstitutes the graph of objects. + // + // + // Parameters: + // serializationStream: + // The stream that contains the data to deserialize. + // + // Returns: + // The top object of the deserialized graph. + [RequiresDynamicCode("BinaryFormatter serialization uses dynamic code generation, the type of objects being processed cannot be statically discovered.")] + [RequiresUnreferencedCode("BinaryFormatter serialization is not trim compatible because the type of objects being processed cannot be statically discovered.")] + object Deserialize(Stream serializationStream); + // + // Summary: + // Serializes an object, or graph of objects with the given root to the provided + // stream. + // + // Parameters: + // serializationStream: + // The stream where the formatter puts the serialized data. This stream can reference + // a variety of backing stores (such as files, network, memory, and so on). + // + // graph: + // The object, or root of the object graph, to serialize. All child objects of this + // root object are automatically serialized. + [RequiresUnreferencedCode("BinaryFormatter serialization is not trim compatible because the type of objects being processed cannot be statically discovered.")] + void Serialize(Stream serializationStream, object graph); + } + + + public interface IProcess + { + void process( object obj ); + } + + + public interface ISerDes where T : IFormatter + { + + T getInstance(); + + + + } + + + public class NewEveryCall: ISerDes where T : IFormatter, new() + { + public T getInstance() + { + return new T(); + } + } + + public class Conn + { + public static int BufferSize = 2048; + } + + + public class Conn : Conn + where T : IFormatter, new() + where TInst : ISerDes, new() + { + public Socket Sock { get { return m_socket; } } + public Stream Stream { get { return m_streamNet; } } + + + private TInst m_formatter = new TInst(); + + + public Conn( Socket sock, IProcess proc ) + { + m_socket = sock; + + sock.NoDelay = true; + + m_streamNet = new NetworkStream( m_socket ); + + m_proc = proc; + } + + public object recieveObject() + { + return recieveObject( Stream ); + } + + public object recieveObject( Stream stream ) + { + object obj = null; + + var formatter = m_formatter.getInstance(); + + try + { + obj = formatter.Deserialize( stream ); + } + catch( System.Xml.XmlException ex ) + { + log.error( $"Outer Exception {ex.Message}" ); + } + + return obj; + } + + public void send( object obj ) + { + + var formatter = m_formatter.getInstance(); + + try + { + var ms = new MemoryStream( BufferSize ); + formatter.Serialize( ms, obj ); + + //var str = System.Text.Encoding.Default.GetString( mm_buffer, 0, (int)ms.Position ); + //log.info( $"Sent data {str} of length {ms.Position}" ); + //log.info( $"Sent {obj}" ); + + byte[] byteSize = BitConverter.GetBytes( (uint)ms.Position ); + m_streamNet.Write( byteSize, 0, 4 ); + m_streamNet.Write( ms.GetBuffer(), 0, (int)ms.Position ); + + m_streamNet.Flush(); + } + catch( Exception e ) + { + log.warn( $"Exception sending obj {obj} of {e}" ); + throw; + } + } + + public virtual void recieve( object obj ) + { + if( m_proc != null ) + m_proc.process( obj ); + } + + Socket m_socket; + + NetworkStream m_streamNet; + + IProcess m_proc; + + + + //private BufferedStream m_streamBufIn; + //private BufferedStream m_streamBufOut; + } + + + +} diff --git a/net/NetMsg.cs b/net/NetMsg.cs index 775ffb4..b69689f 100644 --- a/net/NetMsg.cs +++ b/net/NetMsg.cs @@ -1,103 +1,103 @@ -using System; - -namespace lib.Net -{ - [Serializable] - public class Msg - { - public Msg() - { - } - } - - [Serializable] - public class Login - { - public Login( String name, String pass ) - { - m_username = name; - m_password = pass; - } - - public readonly String m_username; - public readonly String m_password; - } - - [Serializable] - public class LoginResp - { - public LoginResp( bool resp ) - { - m_resp = resp; - } - - public readonly bool m_resp; - } - - #region Admin Messages - //Subclasses of this need to be on an admin client. - [Serializable] - public class Admin - { - - }; - - [Serializable] - public class CreateEntity: Admin - { - - } - - - [Serializable] - public class MoveEntity: Admin - { - - } - #endregion - - [Serializable] - public class EntityBase - { - public EntityBase( int id ) - { - m_id = id; - } - - public readonly int m_id; - }; - - - [Serializable] - public class EntityPos: EntityBase - { - public EntityPos( int id, float x, float y, float z ) : - base( id ) - { - m_x = x; - m_y = y; - m_z = z; - } - - public readonly float m_x; - public readonly float m_y; - public readonly float m_z; - } - - [Serializable] - public class EntityDesc: EntityBase - { - public EntityDesc( int id ) : - base( id ) - { - } - - //Should an entity have a mesh? Be made up of multiple meshes? - public readonly String m_mesh; - } - - - - - -} +using System; + +namespace lib.Net +{ + [Serializable] + public class Msg + { + public Msg() + { + } + } + + [Serializable] + public class Login + { + public Login( String name, String pass ) + { + m_username = name; + m_password = pass; + } + + public readonly String m_username; + public readonly String m_password; + } + + [Serializable] + public class LoginResp + { + public LoginResp( bool resp ) + { + m_resp = resp; + } + + public readonly bool m_resp; + } + + #region Admin Messages + //Subclasses of this need to be on an admin client. + [Serializable] + public class Admin + { + + }; + + [Serializable] + public class CreateEntity: Admin + { + + } + + + [Serializable] + public class MoveEntity: Admin + { + + } + #endregion + + [Serializable] + public class EntityBase + { + public EntityBase( int id ) + { + m_id = id; + } + + public readonly int m_id; + }; + + + [Serializable] + public class EntityPos: EntityBase + { + public EntityPos( int id, float x, float y, float z ) : + base( id ) + { + m_x = x; + m_y = y; + m_z = z; + } + + public readonly float m_x; + public readonly float m_y; + public readonly float m_z; + } + + [Serializable] + public class EntityDesc: EntityBase + { + public EntityDesc( int id ) : + base( id ) + { + } + + //Should an entity have a mesh? Be made up of multiple meshes? + public readonly String m_mesh; + } + + + + + +} diff --git a/scr/Script.cs b/scr/Script.cs index cf8ec5f..fadb3dd 100644 --- a/scr/Script.cs +++ b/scr/Script.cs @@ -1,349 +1,349 @@ - - - - - -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.Emit; -using Microsoft.CodeAnalysis.Text; - -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Threading; - -public class MemoryRefResolver : SourceReferenceResolver -{ - public override bool Equals(object other) - { - return false; - } - - public override int GetHashCode() - { - return 0; - } - - public override string NormalizePath(string path, string baseFilePath) - { - return path; - } - - public override Stream OpenRead(string resolvedPath) - { - return null; - } - - public override SourceText ReadText(string resolvedPath) - { - return null; - } - - public override string ResolveReference(string path, string baseFilePath) - { - return null; - } - -} - - - - -public static class scr -{ - - public static FieldInfo? GetFieldInfo(Type? t, string name) - { - if (t == null) return null; - - var fi = t.GetField(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly); - - if (fi != null) - return fi; - - if (t.BaseType != null) - return GetFieldInfo(t.BaseType, name); - - return null; - } - - // From stack overflow - static Lazy> typeSetLazy = - new Lazy>(() => { - var types = AppDomain - .CurrentDomain - .GetAssemblies() - .SelectMany(a => a.GetTypes() - .Where(t => t.IsClass)); - var typesAndBaseTypes = types - .Select(t => new { Type = t, t.BaseType }) - .ToList(); - var typesWithSubclasses = typesAndBaseTypes - .Join( - typesAndBaseTypes, - t => t.Type, - t => t.BaseType, - (t1, t2) => t2.BaseType); - var typesHs = new HashSet(types); - typesHs.ExceptWith(typesWithSubclasses); - return typesHs; - }); - - static bool IsLeafType(this Type type) - { - return typeSetLazy.Value.Contains(type); - } - - static HashSet s_badChars = new( new char[] { '<', '>', ' ', ',', '.', '+', '[', ']', '$', ':' } ); - - static public string TypeToIdentifier(string typename) - { - var safeStr = new StringBuilder( typename ); - - for( int i = 0; i < safeStr.Length; ++i ) - { - if( s_badChars.Contains(safeStr[i]) ) safeStr[i] = '_'; - } - - return safeStr.ToString(); - } - - static public FileSystemWatcher s_watcher; - static public Action s_fnAss = (ass) => { - log.warn( $"Need to replace s_fnAss with custom function" ); - }; - - public static void WatchPluginDir( string dir, Action fnAss ) - { - log.info( $"Watching {dir} for changes" ); - - s_fnAss = fnAss; - - s_watcher = new FileSystemWatcher( dir ); - - s_watcher.Created += OnCreated; - s_watcher.Deleted += OnDeleted; - s_watcher.Renamed += OnRenamed; - - s_watcher.Filter = "*.cs"; - s_watcher.IncludeSubdirectories = true; - s_watcher.EnableRaisingEvents = true; - - var existingFiles = Directory.GetFiles( dir, "*.cs", SearchOption.AllDirectories ); - - foreach( var filename in existingFiles ) - { - Process( filename ); - } - - } - - static void OnCreated( object sender, FileSystemEventArgs e ) - { - log.debug( $"{e.Name} got {e.ChangeType}" ); - - if( e.Name.EndsWith( ".cs" ) ) - { - Process( e.FullPath ); - } - } - - static void OnDeleted( object sender, FileSystemEventArgs e ) - { - log.debug( $"{e.Name} got {e.ChangeType}" ); - } - - static void OnRenamed( object sender, FileSystemEventArgs e ) - { - log.debug( $"{e.Name} got {e.ChangeType}" ); - - if( e.Name.EndsWith(".cs") ) - { - while( true ) - { - try - { - Process( e.FullPath ); - return; - } - catch( System.IO.IOException ex ) - { - - } - catch( Exception ex ) - { - log.error( $"Got ex {ex.GetType().Name} trying to process {e.FullPath}" ); - log.error( $"-> {ex.Message}" ); - return; - } - - Thread.Sleep( 100 ); - } - } - } - - static void Process( string filename ) - { - CompileFile( filename, ( ass ) => { s_fnAss( ass ); }, ( diags ) => { } ); - } - - public static void CompileFile( string filename, Action onSuccess, Action> onFailure, Platform platform = Platform.X86 ) - { - var fullpath = Path.GetFullPath( filename ); - - var stream = File.OpenRead( fullpath ); - - var sourceText = SourceText.From( stream ); - - Compile( sourceText, fullpath, onSuccess, onFailure ); - } - - public static void Compile( string str, string uniquePath, Action onSuccess, Action> onFailure, Platform platform = Platform.X86 ) - { - var sourceText = SourceText.From( str ); - - Compile( sourceText, uniquePath, onSuccess, onFailure ); - } - - - public static void Compile( SourceText sourceText, string uniquePath, Action onSuccess, Action> onFailure, Platform platform = Platform.X86 ) - { - string assemblyName = Path.GetRandomFileName(); - - var options = new CSharpParseOptions(documentationMode: DocumentationMode.Diagnose, kind: SourceCodeKind.Regular); - - SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText( sourceText, options, uniquePath ); - - var memRef = new MemoryRefResolver(); - - - using (var ms = new MemoryStream()) - using (var pdb = new MemoryStream()) - { - var result = CompileAndEmit(assemblyName, new[] { syntaxTree }, ms, pdb, platform); - - if (!result.Success) - { - if (onFailure == null) - { - } - else - { - LogDiags( uniquePath, result.Diagnostics.Length, result.Diagnostics ); - - onFailure( result.Diagnostics ); - } - } - else - { - ms.Seek(0, SeekOrigin.Begin); - var assembly = Assembly.Load(ms.ToArray(), pdb.ToArray()); - - onSuccess( assembly ); - } - } - } - - public static void LogDiags( string uniquePath, int count, IEnumerable diags ) - { - log.warn( $"{count} Problems building script with name {uniquePath}" ); - foreach( var diag in diags ) - { - log.debug( $"{diag}" ); - } - } - - private static EmitResult CompileAndEmit(string assemblyName, SyntaxTree[] syntaxTrees, MemoryStream ms, MemoryStream pdb, Platform platform) - { - var memRef = new MemoryRefResolver(); - - // @@@@ TODO :: Config release / debug - CSharpCompilation compilation = CSharpCompilation.Create( - assemblyName, - syntaxTrees: syntaxTrees, - references: RefCache.References, - options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, - sourceReferenceResolver: memRef, - optimizationLevel: OptimizationLevel.Release, - platform: platform, - specificDiagnosticOptions: new Dictionary - { - { "CS1701", ReportDiagnostic.Suppress } - })); - - return compilation.Emit(ms, pdb); - } - - private static class RefCache - { - // create the list of references on first use, but if two threads both *start* making the list thats fine since we'll just use whichever wins. - private static readonly Lazy> lazyRef = new Lazy>(GetReferences, LazyThreadSafetyMode.PublicationOnly); - - public static IReadOnlyList References => lazyRef.Value; - - private static ImmutableArray GetReferences() - { - var builder = ImmutableArray.CreateBuilder(); - - var assemblies = AppDomain.CurrentDomain.GetAssemblies(); - - foreach( var ass in assemblies ) - { - if( ass != null && !ass.IsDynamic && ass.Location != null ) - { - try - { - builder.Add( MetadataReference.CreateFromFile( ass.Location ) ); - } - catch( Exception ex ) - { - log.warn( $"Got {ex.GetType().Name} sayaing {ex.Message}" ); - } - } - } - - return builder.ToImmutable(); - } - } - - public static string PrettyName( Type t ) - { - if( t.GetGenericArguments().Length == 0 ) - { - return t.FullName.Replace( '+', '.' ); - } - var genArgs = t.GetGenericArguments(); - var typeDef = t.FullName; - - var indexOfTick = typeDef.IndexOf("`"); - - var unmangledOuterName = typeDef.Substring(0, typeDef.IndexOf('`')).Replace('+', '.'); - - var innerName = ""; - - //Check for inner class - if( typeDef.ElementAt( indexOfTick + 2 ) != '[' ) - { - var indexOfOpenBracket = typeDef.IndexOf('[', indexOfTick); - - innerName = typeDef.Substring( indexOfTick + 2, indexOfOpenBracket - (indexOfTick + 2) ).Replace( '+', '.' ); - } - - return unmangledOuterName + "<" + String.Join( ",", genArgs.Select( PrettyName ) ) + ">" + innerName; - } - - - private static void AddIfFirst(IDictionary dict, TKey key, TValue value) - { - if (!dict.ContainsKey(key)) - { - dict.Add(key, value); - } - } -} - + + + + + +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Emit; +using Microsoft.CodeAnalysis.Text; + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading; + +public class MemoryRefResolver : SourceReferenceResolver +{ + public override bool Equals(object other) + { + return false; + } + + public override int GetHashCode() + { + return 0; + } + + public override string NormalizePath(string path, string baseFilePath) + { + return path; + } + + public override Stream OpenRead(string resolvedPath) + { + return null; + } + + public override SourceText ReadText(string resolvedPath) + { + return null; + } + + public override string ResolveReference(string path, string baseFilePath) + { + return null; + } + +} + + + + +public static class scr +{ + + public static FieldInfo? GetFieldInfo(Type? t, string name) + { + if (t == null) return null; + + var fi = t.GetField(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly); + + if (fi != null) + return fi; + + if (t.BaseType != null) + return GetFieldInfo(t.BaseType, name); + + return null; + } + + // From stack overflow + static Lazy> typeSetLazy = + new Lazy>(() => { + var types = AppDomain + .CurrentDomain + .GetAssemblies() + .SelectMany(a => a.GetTypes() + .Where(t => t.IsClass)); + var typesAndBaseTypes = types + .Select(t => new { Type = t, t.BaseType }) + .ToList(); + var typesWithSubclasses = typesAndBaseTypes + .Join( + typesAndBaseTypes, + t => t.Type, + t => t.BaseType, + (t1, t2) => t2.BaseType); + var typesHs = new HashSet(types); + typesHs.ExceptWith(typesWithSubclasses); + return typesHs; + }); + + static bool IsLeafType(this Type type) + { + return typeSetLazy.Value.Contains(type); + } + + static HashSet s_badChars = new( new char[] { '<', '>', ' ', ',', '.', '+', '[', ']', '$', ':' } ); + + static public string TypeToIdentifier(string typename) + { + var safeStr = new StringBuilder( typename ); + + for( int i = 0; i < safeStr.Length; ++i ) + { + if( s_badChars.Contains(safeStr[i]) ) safeStr[i] = '_'; + } + + return safeStr.ToString(); + } + + static public FileSystemWatcher s_watcher; + static public Action s_fnAss = (ass) => { + log.warn( $"Need to replace s_fnAss with custom function" ); + }; + + public static void WatchPluginDir( string dir, Action fnAss ) + { + log.info( $"Watching {dir} for changes" ); + + s_fnAss = fnAss; + + s_watcher = new FileSystemWatcher( dir ); + + s_watcher.Created += OnCreated; + s_watcher.Deleted += OnDeleted; + s_watcher.Renamed += OnRenamed; + + s_watcher.Filter = "*.cs"; + s_watcher.IncludeSubdirectories = true; + s_watcher.EnableRaisingEvents = true; + + var existingFiles = Directory.GetFiles( dir, "*.cs", SearchOption.AllDirectories ); + + foreach( var filename in existingFiles ) + { + Process( filename ); + } + + } + + static void OnCreated( object sender, FileSystemEventArgs e ) + { + log.debug( $"{e.Name} got {e.ChangeType}" ); + + if( e.Name.EndsWith( ".cs" ) ) + { + Process( e.FullPath ); + } + } + + static void OnDeleted( object sender, FileSystemEventArgs e ) + { + log.debug( $"{e.Name} got {e.ChangeType}" ); + } + + static void OnRenamed( object sender, FileSystemEventArgs e ) + { + log.debug( $"{e.Name} got {e.ChangeType}" ); + + if( e.Name.EndsWith(".cs") ) + { + while( true ) + { + try + { + Process( e.FullPath ); + return; + } + catch( System.IO.IOException ex ) + { + + } + catch( Exception ex ) + { + log.error( $"Got ex {ex.GetType().Name} trying to process {e.FullPath}" ); + log.error( $"-> {ex.Message}" ); + return; + } + + Thread.Sleep( 100 ); + } + } + } + + static void Process( string filename ) + { + CompileFile( filename, ( ass ) => { s_fnAss( ass ); }, ( diags ) => { } ); + } + + public static void CompileFile( string filename, Action onSuccess, Action> onFailure, Platform platform = Platform.X86 ) + { + var fullpath = Path.GetFullPath( filename ); + + var stream = File.OpenRead( fullpath ); + + var sourceText = SourceText.From( stream ); + + Compile( sourceText, fullpath, onSuccess, onFailure ); + } + + public static void Compile( string str, string uniquePath, Action onSuccess, Action> onFailure, Platform platform = Platform.X86 ) + { + var sourceText = SourceText.From( str ); + + Compile( sourceText, uniquePath, onSuccess, onFailure ); + } + + + public static void Compile( SourceText sourceText, string uniquePath, Action onSuccess, Action> onFailure, Platform platform = Platform.X86 ) + { + string assemblyName = Path.GetRandomFileName(); + + var options = new CSharpParseOptions(documentationMode: DocumentationMode.Diagnose, kind: SourceCodeKind.Regular); + + SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText( sourceText, options, uniquePath ); + + var memRef = new MemoryRefResolver(); + + + using (var ms = new MemoryStream()) + using (var pdb = new MemoryStream()) + { + var result = CompileAndEmit(assemblyName, new[] { syntaxTree }, ms, pdb, platform); + + if (!result.Success) + { + if (onFailure == null) + { + } + else + { + LogDiags( uniquePath, result.Diagnostics.Length, result.Diagnostics ); + + onFailure( result.Diagnostics ); + } + } + else + { + ms.Seek(0, SeekOrigin.Begin); + var assembly = Assembly.Load(ms.ToArray(), pdb.ToArray()); + + onSuccess( assembly ); + } + } + } + + public static void LogDiags( string uniquePath, int count, IEnumerable diags ) + { + log.warn( $"{count} Problems building script with name {uniquePath}" ); + foreach( var diag in diags ) + { + log.debug( $"{diag}" ); + } + } + + private static EmitResult CompileAndEmit(string assemblyName, SyntaxTree[] syntaxTrees, MemoryStream ms, MemoryStream pdb, Platform platform) + { + var memRef = new MemoryRefResolver(); + + // @@@@ TODO :: Config release / debug + CSharpCompilation compilation = CSharpCompilation.Create( + assemblyName, + syntaxTrees: syntaxTrees, + references: RefCache.References, + options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, + sourceReferenceResolver: memRef, + optimizationLevel: OptimizationLevel.Release, + platform: platform, + specificDiagnosticOptions: new Dictionary + { + { "CS1701", ReportDiagnostic.Suppress } + })); + + return compilation.Emit(ms, pdb); + } + + private static class RefCache + { + // create the list of references on first use, but if two threads both *start* making the list thats fine since we'll just use whichever wins. + private static readonly Lazy> lazyRef = new Lazy>(GetReferences, LazyThreadSafetyMode.PublicationOnly); + + public static IReadOnlyList References => lazyRef.Value; + + private static ImmutableArray GetReferences() + { + var builder = ImmutableArray.CreateBuilder(); + + var assemblies = AppDomain.CurrentDomain.GetAssemblies(); + + foreach( var ass in assemblies ) + { + if( ass != null && !ass.IsDynamic && ass.Location != null ) + { + try + { + builder.Add( MetadataReference.CreateFromFile( ass.Location ) ); + } + catch( Exception ex ) + { + log.warn( $"Got {ex.GetType().Name} sayaing {ex.Message}" ); + } + } + } + + return builder.ToImmutable(); + } + } + + public static string PrettyName( Type t ) + { + if( t.GetGenericArguments().Length == 0 ) + { + return t.FullName.Replace( '+', '.' ); + } + var genArgs = t.GetGenericArguments(); + var typeDef = t.FullName; + + var indexOfTick = typeDef.IndexOf("`"); + + var unmangledOuterName = typeDef.Substring(0, typeDef.IndexOf('`')).Replace('+', '.'); + + var innerName = ""; + + //Check for inner class + if( typeDef.ElementAt( indexOfTick + 2 ) != '[' ) + { + var indexOfOpenBracket = typeDef.IndexOf('[', indexOfTick); + + innerName = typeDef.Substring( indexOfTick + 2, indexOfOpenBracket - (indexOfTick + 2) ).Replace( '+', '.' ); + } + + return unmangledOuterName + "<" + String.Join( ",", genArgs.Select( PrettyName ) ) + ">" + innerName; + } + + + private static void AddIfFirst(IDictionary dict, TKey key, TValue value) + { + if (!dict.ContainsKey(key)) + { + dict.Add(key, value); + } + } +} + diff --git a/ser/SerializableDictionary.cs b/ser/SerializableDictionary.cs index 90de8db..a16151a 100644 --- a/ser/SerializableDictionary.cs +++ b/ser/SerializableDictionary.cs @@ -1,166 +1,166 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Xml.Serialization; -using System.Xml; -using System.Runtime.Serialization; -using System.Runtime.Serialization.Formatters.Binary; -using System.IO; -using System.Security.Permissions; - -namespace lib -{ - [Serializable] - public class SerializableDictionary: Dictionary, IXmlSerializable, ISerializable - { - #region Constants - private const string DictionaryNodeName = "Dictionary"; - private const string ItemNodeName = "Item"; - private const string KeyNodeName = "Key"; - private const string ValueNodeName = "Value"; - #endregion - #region Constructors - public SerializableDictionary() - { - } - - public SerializableDictionary( IDictionary dictionary ) - : base( dictionary ) - { - } - - public SerializableDictionary( IEqualityComparer comparer ) - : base( comparer ) - { - } - - public SerializableDictionary( int capacity ) - : base( capacity ) - { - } - - public SerializableDictionary( IDictionary dictionary, IEqualityComparer comparer ) - : base( dictionary, comparer ) - { - } - - public SerializableDictionary( int capacity, IEqualityComparer comparer ) - : base( capacity, comparer ) - { - } - - #endregion - #region ISerializable Members - - protected SerializableDictionary( SerializationInfo info, StreamingContext context ) - { - int itemCount = info.GetInt32("ItemCount"); - for( int i = 0; i < itemCount; i++ ) - { - KeyValuePair kvp = (KeyValuePair)info.GetValue(String.Format( $"Item{i}" ), typeof(KeyValuePair)); - this.Add( kvp.Key, kvp.Value ); - } - } - - - //[SecurityPermission( SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter )] - void ISerializable.GetObjectData( SerializationInfo info, StreamingContext context ) - { - info.AddValue( "ItemCount", this.Count ); - int itemIdx = 0; - foreach( KeyValuePair kvp in this ) - { - info.AddValue( String.Format( $"Item{itemIdx}" ), kvp, typeof( KeyValuePair ) ); - itemIdx++; - } - } - - #endregion - #region IXmlSerializable Members - - void IXmlSerializable.WriteXml( System.Xml.XmlWriter writer ) - { - //writer.WriteStartElement(DictionaryNodeName); - foreach( KeyValuePair kvp in this ) - { - writer.WriteStartElement( ItemNodeName ); - writer.WriteStartElement( KeyNodeName ); - KeySerializer.Serialize( writer, kvp.Key ); - writer.WriteEndElement(); - writer.WriteStartElement( ValueNodeName ); - ValueSerializer.Serialize( writer, kvp.Value ); - writer.WriteEndElement(); - writer.WriteEndElement(); - } - //writer.WriteEndElement(); - } - - void IXmlSerializable.ReadXml( System.Xml.XmlReader reader ) - { - if( reader.IsEmptyElement ) - { - return; - } - - // Move past container - if( !reader.Read() ) - { - throw new XmlException( "Error in Deserialization of Dictionary" ); - } - - //reader.ReadStartElement(DictionaryNodeName); - while( reader.NodeType != XmlNodeType.EndElement ) - { - reader.ReadStartElement( ItemNodeName ); - reader.ReadStartElement( KeyNodeName ); - TKey key = (TKey)KeySerializer.Deserialize(reader); - reader.ReadEndElement(); - reader.ReadStartElement( ValueNodeName ); - TVal value = (TVal)ValueSerializer.Deserialize(reader); - reader.ReadEndElement(); - reader.ReadEndElement(); - this.Add( key, value ); - reader.MoveToContent(); - } - //reader.ReadEndElement(); - - reader.ReadEndElement(); // Read End Element to close Read of containing node - } - - System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema() - { - return null; - } - - #endregion - #region Private Properties - protected XmlSerializer ValueSerializer - { - get - { - if( valueSerializer == null ) - { - valueSerializer = new XmlSerializer( typeof( TVal ) ); - } - return valueSerializer; - } - } - - private XmlSerializer KeySerializer - { - get - { - if( keySerializer == null ) - { - keySerializer = new XmlSerializer( typeof( TKey ) ); - } - return keySerializer; - } - } - #endregion - #region Private Members - private XmlSerializer keySerializer = null; - private XmlSerializer valueSerializer = null; - #endregion - } -} +using System; +using System.Collections.Generic; +using System.Text; +using System.Xml.Serialization; +using System.Xml; +using System.Runtime.Serialization; +using System.Runtime.Serialization.Formatters.Binary; +using System.IO; +using System.Security.Permissions; + +namespace lib +{ + [Serializable] + public class SerializableDictionary: Dictionary, IXmlSerializable, ISerializable + { + #region Constants + private const string DictionaryNodeName = "Dictionary"; + private const string ItemNodeName = "Item"; + private const string KeyNodeName = "Key"; + private const string ValueNodeName = "Value"; + #endregion + #region Constructors + public SerializableDictionary() + { + } + + public SerializableDictionary( IDictionary dictionary ) + : base( dictionary ) + { + } + + public SerializableDictionary( IEqualityComparer comparer ) + : base( comparer ) + { + } + + public SerializableDictionary( int capacity ) + : base( capacity ) + { + } + + public SerializableDictionary( IDictionary dictionary, IEqualityComparer comparer ) + : base( dictionary, comparer ) + { + } + + public SerializableDictionary( int capacity, IEqualityComparer comparer ) + : base( capacity, comparer ) + { + } + + #endregion + #region ISerializable Members + + protected SerializableDictionary( SerializationInfo info, StreamingContext context ) + { + int itemCount = info.GetInt32("ItemCount"); + for( int i = 0; i < itemCount; i++ ) + { + KeyValuePair kvp = (KeyValuePair)info.GetValue(String.Format( $"Item{i}" ), typeof(KeyValuePair)); + this.Add( kvp.Key, kvp.Value ); + } + } + + + //[SecurityPermission( SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter )] + void ISerializable.GetObjectData( SerializationInfo info, StreamingContext context ) + { + info.AddValue( "ItemCount", this.Count ); + int itemIdx = 0; + foreach( KeyValuePair kvp in this ) + { + info.AddValue( String.Format( $"Item{itemIdx}" ), kvp, typeof( KeyValuePair ) ); + itemIdx++; + } + } + + #endregion + #region IXmlSerializable Members + + void IXmlSerializable.WriteXml( System.Xml.XmlWriter writer ) + { + //writer.WriteStartElement(DictionaryNodeName); + foreach( KeyValuePair kvp in this ) + { + writer.WriteStartElement( ItemNodeName ); + writer.WriteStartElement( KeyNodeName ); + KeySerializer.Serialize( writer, kvp.Key ); + writer.WriteEndElement(); + writer.WriteStartElement( ValueNodeName ); + ValueSerializer.Serialize( writer, kvp.Value ); + writer.WriteEndElement(); + writer.WriteEndElement(); + } + //writer.WriteEndElement(); + } + + void IXmlSerializable.ReadXml( System.Xml.XmlReader reader ) + { + if( reader.IsEmptyElement ) + { + return; + } + + // Move past container + if( !reader.Read() ) + { + throw new XmlException( "Error in Deserialization of Dictionary" ); + } + + //reader.ReadStartElement(DictionaryNodeName); + while( reader.NodeType != XmlNodeType.EndElement ) + { + reader.ReadStartElement( ItemNodeName ); + reader.ReadStartElement( KeyNodeName ); + TKey key = (TKey)KeySerializer.Deserialize(reader); + reader.ReadEndElement(); + reader.ReadStartElement( ValueNodeName ); + TVal value = (TVal)ValueSerializer.Deserialize(reader); + reader.ReadEndElement(); + reader.ReadEndElement(); + this.Add( key, value ); + reader.MoveToContent(); + } + //reader.ReadEndElement(); + + reader.ReadEndElement(); // Read End Element to close Read of containing node + } + + System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema() + { + return null; + } + + #endregion + #region Private Properties + protected XmlSerializer ValueSerializer + { + get + { + if( valueSerializer == null ) + { + valueSerializer = new XmlSerializer( typeof( TVal ) ); + } + return valueSerializer; + } + } + + private XmlSerializer KeySerializer + { + get + { + if( keySerializer == null ) + { + keySerializer = new XmlSerializer( typeof( TKey ) ); + } + return keySerializer; + } + } + #endregion + #region Private Members + private XmlSerializer keySerializer = null; + private XmlSerializer valueSerializer = null; + #endregion + } +} diff --git a/ser/VersionFormatter.cs b/ser/VersionFormatter.cs index c61cb44..1d0daaa 100644 --- a/ser/VersionFormatter.cs +++ b/ser/VersionFormatter.cs @@ -1,677 +1,677 @@ -using System; -using System.IO; -using System.Reflection; -using System.Collections; -using System.Diagnostics; -//using System.Globalization; -//using System.ComponentModel; -using System.Runtime.Serialization; - -namespace lib -{ - /// - /// - /// - public class VersionFormatter: IFormatter - { - public enum ETypes - { - Array, - Int32, - Ref, - Object, - EndObject, - Single, - Double, - Char, - String, - Boolean, - EndStream, - } - - - public VersionFormatter() - { - // - // TODO: Add constructor logic here - // - } - - - #region Useless - public ISurrogateSelector SurrogateSelector - { - get - { - return null; - } - - set - { - } - } - - public SerializationBinder Binder - { - get - { - return null; - } - - set - { - } - } - - public StreamingContext Context - { - get - { - return new StreamingContext(); - } - - set - { - } - } - #endregion Useless - - Queue m_objectsToBeDeserialized = new Queue(); - Hashtable m_alreadyDeserialzied = new Hashtable(); - //int m_GUID = 0; - - #region Serialize - public void Serialize( Stream stream, object obj ) - { - //Default is 4k - //BufferedStream bufStream = new BufferedStream( stream ); - - BinaryWriter writer = new BinaryWriter( stream ); - - writeObject( writer, obj ); - - while( m_objectsToBeDeserialized.Count != 0 ) - { - object objToDes = m_objectsToBeDeserialized.Dequeue(); - - writeObject( writer, objToDes ); - } - - writer.Write( (char)ETypes.EndStream ); - } - - void writeRefAndSched( BinaryWriter writer, object obj ) - { - //if( m_alreadyDeserialzied[ obj.GetType().GetArrayRank( - - if( obj == null ) - { - writer.Write( 0 ); - return; - } - - - //Now write the address. - //Bad bad. Need to do this correctly. - int objRef = obj.GetHashCode(); - writer.Write( objRef ); - - if( m_alreadyDeserialzied[obj] == null ) - { - m_alreadyDeserialzied[obj] = obj; - m_objectsToBeDeserialized.Enqueue( obj ); - } - } - - void dispatchWrite( BinaryWriter writer, object parentObj, FieldInfo fi ) - { - string typeName = fi.FieldType.Name; - - string name = fi.Name; - - if( fi.IsNotSerialized ) - { - return; - } - - if( fi.FieldType.IsArray ) - { - writer.Write( (char)ETypes.Array ); - writer.Write( name.GetHashCode() ); - - writeArray( writer, (Array)fi.GetValue( parentObj ) ); - } - else if( ( fi.FieldType.IsClass || fi.FieldType.IsInterface ) && typeName != "String" ) - { - writer.Write( (char)ETypes.Ref ); - writer.Write( name.GetHashCode() ); - - writeRefAndSched( writer, fi.GetValue( parentObj ) ); - } - else if( fi.FieldType.IsEnum ) - { - writer.Write( (char)ETypes.Int32 ); - writer.Write( name.GetHashCode() ); - - write( writer, Convert.ToInt32( fi.GetValue( parentObj ) ) ); - } - else - { - switch( typeName ) - { - case "Int32": - writer.Write( (char)ETypes.Int32 ); - writer.Write( name.GetHashCode() ); - - write( writer, Convert.ToInt32( fi.GetValue( parentObj ) ) ); - break; - case "Single": - writer.Write( (char)ETypes.Single ); - writer.Write( name.GetHashCode() ); - - write( writer, Convert.ToSingle( fi.GetValue( parentObj ) ) ); - break; - case "Double": - writer.Write( (char)ETypes.Double ); - writer.Write( name.GetHashCode() ); - - write( writer, Convert.ToDouble( fi.GetValue( parentObj ) ) ); - break; - case "Char": - writer.Write( (char)ETypes.Char ); - writer.Write( name.GetHashCode() ); - - write( writer, Convert.ToChar( fi.GetValue( parentObj ) ) ); - break; - case "String": - writer.Write( (char)ETypes.String ); - writer.Write( name.GetHashCode() ); - - write( writer, Convert.ToString( fi.GetValue( parentObj ) ) ); - break; - case "Boolean": - writer.Write( (char)ETypes.Boolean ); - writer.Write( name.GetHashCode() ); - - writer.Write( Convert.ToBoolean( fi.GetValue( parentObj ) ) ); - break; - default: - Console.WriteLine( "VersionFormatter does not understand type " + typeName ); - break; - } - } - } - - void writeArray( BinaryWriter writer, Array array ) - { - if( array == null ) - { - writer.Write( (int)-1 ); - return; - } - - writer.Write( array.Length ); - - foreach( object obj in array ) - { - writeRefAndSched( writer, obj ); - } - } - - void getAllFields( object obj, ArrayList list ) - { - Type t = obj.GetType(); - - while( t != null ) - { - FieldInfo[] fiArr = t.GetFields( BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.DeclaredOnly ); - list.AddRange( fiArr ); - - t = t.BaseType; - } - } - - - void writeObject( BinaryWriter writer, object obj ) - { - Type objType = obj.GetType(); - - writer.Write( (char)ETypes.Object ); - writer.Write( objType.FullName ); - - int objRef = obj.GetHashCode(); - writer.Write( objRef ); - - ArrayList list = new ArrayList(); - - getAllFields( obj, list ); - - foreach( FieldInfo fi in list ) - { - dispatchWrite( writer, obj, fi ); - } - - writer.Write( (char)ETypes.EndObject ); - } - - void write( BinaryWriter wr, TType val ) - { - //wr.Write( val ); - } - - /* - void writeInt( BinaryWriter writer, int val ) - { - writer.Write( val ); - } - - void writeSingle( BinaryWriter writer, float val ) - { - writer.Write( val ); - } - - void writeDouble( BinaryWriter writer, double val ) - { - writer.Write( val ); - } - - void writeChar( BinaryWriter writer, char val ) - { - writer.Write( val ); - } - - void writeString( BinaryWriter writer, string val ) - { - writer.Write( val ); - } - - void writeBool( BinaryWriter writer, bool val ) - { - writer.Write( val ); - } - */ - #endregion Serialize - - - #region Deserialize - - class Fixup - { - public Fixup( int guid, object obj, FieldInfo fi ) - { - m_guid = guid; - m_obj = obj; - m_fi = fi; - } - - public Fixup( int guid, object obj, int index ) - { - m_guid = guid; - m_obj = obj; - m_index = index; - } - - public readonly int m_guid = 0; - public readonly object m_obj = null; - - public readonly FieldInfo m_fi = null; - public readonly int m_index= -1; - - } - - Hashtable m_mapGUIDToObject = new Hashtable(); - ArrayList m_fixupList = new ArrayList(); - - ArrayList m_desObjects = new ArrayList(); - - public object Deserialize( Stream stream ) - { - BinaryReader reader = new BinaryReader( stream ); - - object objRoot = null; - - //Read in the first object. - { - ETypes type = (ETypes)reader.ReadChar(); - - Debug.Assert( type == ETypes.Object ); - - objRoot = readObject( reader ); - - m_desObjects.Add( objRoot ); - } - - bool readObjects = true; - - while( readObjects ) - { - ETypes type = (ETypes)reader.ReadChar(); - - Debug.Assert( type == ETypes.Object || type == ETypes.EndStream ); - - if( type == ETypes.Object ) - { - object obj = readObject( reader ); - - m_desObjects.Add( obj ); - } - else - { - Debug.Assert( type == ETypes.EndStream ); - - readObjects = false; - } - } - - foreach( Fixup fu in m_fixupList ) - { - //Fixup fix = m_fixups[ - - object obj = m_mapGUIDToObject[ fu.m_guid ]; - - if( obj != null ) - { - if( fu.m_fi != null ) - { - fu.m_fi.SetValue( fu.m_obj, obj ); - } - else - { - Debug.Assert( fu.m_index >= 0 ); - - object []array = (object [])fu.m_obj; - - array[fu.m_index] = obj; - } - } - else - { - Console.WriteLine( "Obj to ref is null." ); - } - } - - foreach( object obj in m_desObjects ) - { - if( typeof( IDeserializationCallback ).IsAssignableFrom( obj.GetType() ) ) - { - IDeserializationCallback desCB = (IDeserializationCallback)obj; - - if( desCB != null ) - { - desCB.OnDeserialization( this ); - } - } - } - - return objRoot; - } - - - - bool dispatchRead( BinaryReader reader, object obj, Hashtable ht ) - { - - //Read the type - ETypes type = (ETypes)reader.ReadChar(); - - if( type == ETypes.EndObject ) - { - return false; - } - - int nameHash = reader.ReadInt32(); - - FieldInfo fi = (FieldInfo)ht[ nameHash ]; - - if( fi == null ) - { - Console.WriteLine( "Field no longer exists" ); - } - - try - { - switch( type ) - { - case ETypes.Array: - readArray( reader, obj, fi ); - break; - case ETypes.Int32: - readInt( reader, obj, fi ); - break; - case ETypes.Single: - readSingle( reader, obj, fi ); - break; - case ETypes.Double: - readDouble( reader, obj, fi ); - break; - case ETypes.Char: - readChar( reader, obj, fi ); - break; - case ETypes.Boolean: - readBool( reader, obj, fi ); - break; - case ETypes.String: - readString( reader, obj, fi ); - break; - case ETypes.Ref: - readRef( reader, obj, fi ); - break; - case ETypes.Object: - readObject( reader ); - break; - default: - Debug.Fail( "Unknown type on read." ); - break; - } - } - catch( Exception ex ) - { - Console.WriteLine( "Exception: " + ex.Message ); - Console.WriteLine( "Stack: " + ex.StackTrace ); - } - - - return true; - } - - object createObject( string objTypeName ) - { - Assembly[] ass = AppDomain.CurrentDomain.GetAssemblies(); - - foreach( Assembly a in ass ) - { - Type t = a.GetType( objTypeName ); - - if( t != null ) - { - object obj = FormatterServices.GetUninitializedObject( t ); - - if( obj != null ) - { - return obj; - } - } - } - - return null; - } - - - object readObject( BinaryReader reader ) - { - //ETypes type = (ETypes)reader.ReadChar(); - - //Debug.Assert( type == ETypes.Object, "Expecting type Object" ); - - string objTypeName = reader.ReadString(); - int objGUID = reader.ReadInt32(); - - try - { - object obj = createObject( objTypeName ); - - m_mapGUIDToObject[objGUID] = obj; - - ArrayList list = new ArrayList(); - Hashtable ht = new Hashtable(); - - if( obj != null ) - { - getAllFields( obj, list ); - - foreach( FieldInfo fi in list ) - { - ht[fi.Name.GetHashCode()] = fi; - } - } - - while( dispatchRead( reader, obj, ht ) ) - { - } - - return obj; - } - catch( Exception ex ) - { - Console.WriteLine( "Exception: " + ex.Message ); - } - - return null; - } - - void readArray( BinaryReader reader, object obj, FieldInfo fi ) - { - int length = reader.ReadInt32(); - - if( length < 0 ) - { - if( fi == null ) - return; - - fi.SetValue( obj, null ); - - return; - } - - object[] array = new object[length]; - - if( fi != null ) - { - fi.SetValue( obj, array ); - } - - for( int i = 0; i < length; ++i ) - { - int val = reader.ReadInt32(); - - //m_fixups[ val ] = new Fixup( obj, fi ); - - if( fi != null ) - { - m_fixupList.Add( new Fixup( val, array, i ) ); - } - } - } - - void readRef( BinaryReader reader, object obj, FieldInfo fi ) - { - int val = reader.ReadInt32(); - - //m_fixups[ val ] = new Fixup( obj, fi ); - - m_fixupList.Add( new Fixup( val, obj, fi ) ); - } - - void readInt( BinaryReader reader, object obj, FieldInfo fi ) - { - int val = reader.ReadInt32(); - - if( fi == null ) - return; - - if( !fi.FieldType.IsEnum ) - { - fi.SetValue( obj, val ); - } - else - { - object enumVal = Enum.Parse( fi.FieldType, val.ToString() ); - fi.SetValue( obj, Convert.ChangeType( enumVal, fi.FieldType ) ); - } - - } - - void readSingle( BinaryReader reader, object obj, FieldInfo fi ) - { - float val = reader.ReadSingle(); - - if( fi == null ) - return; - - fi.SetValue( obj, val ); - } - - void readDouble( BinaryReader reader, object obj, FieldInfo fi ) - { - double val = reader.ReadDouble(); - - if( fi == null ) - return; - - fi.SetValue( obj, val ); - } - - void readChar( BinaryReader reader, object obj, FieldInfo fi ) - { - char val = reader.ReadChar(); - - if( fi == null ) - return; - - fi.SetValue( obj, val ); - } - - void readString( BinaryReader reader, object obj, FieldInfo fi ) - { - string val = reader.ReadString(); - - if( fi == null ) - return; - - fi.SetValue( obj, val ); - } - - void readBool( BinaryReader reader, object obj, FieldInfo fi ) - { - bool val = reader.ReadBoolean(); - - if( fi == null ) - return; - - fi.SetValue( obj, val ); - } - - #endregion Deserialize - - - } -} - - - - - - - - - - - - - - - - - - - +using System; +using System.IO; +using System.Reflection; +using System.Collections; +using System.Diagnostics; +//using System.Globalization; +//using System.ComponentModel; +using System.Runtime.Serialization; + +namespace lib +{ + /// + /// + /// + public class VersionFormatter: IFormatter + { + public enum ETypes + { + Array, + Int32, + Ref, + Object, + EndObject, + Single, + Double, + Char, + String, + Boolean, + EndStream, + } + + + public VersionFormatter() + { + // + // TODO: Add constructor logic here + // + } + + + #region Useless + public ISurrogateSelector SurrogateSelector + { + get + { + return null; + } + + set + { + } + } + + public SerializationBinder Binder + { + get + { + return null; + } + + set + { + } + } + + public StreamingContext Context + { + get + { + return new StreamingContext(); + } + + set + { + } + } + #endregion Useless + + Queue m_objectsToBeDeserialized = new Queue(); + Hashtable m_alreadyDeserialzied = new Hashtable(); + //int m_GUID = 0; + + #region Serialize + public void Serialize( Stream stream, object obj ) + { + //Default is 4k + //BufferedStream bufStream = new BufferedStream( stream ); + + BinaryWriter writer = new BinaryWriter( stream ); + + writeObject( writer, obj ); + + while( m_objectsToBeDeserialized.Count != 0 ) + { + object objToDes = m_objectsToBeDeserialized.Dequeue(); + + writeObject( writer, objToDes ); + } + + writer.Write( (char)ETypes.EndStream ); + } + + void writeRefAndSched( BinaryWriter writer, object obj ) + { + //if( m_alreadyDeserialzied[ obj.GetType().GetArrayRank( + + if( obj == null ) + { + writer.Write( 0 ); + return; + } + + + //Now write the address. + //Bad bad. Need to do this correctly. + int objRef = obj.GetHashCode(); + writer.Write( objRef ); + + if( m_alreadyDeserialzied[obj] == null ) + { + m_alreadyDeserialzied[obj] = obj; + m_objectsToBeDeserialized.Enqueue( obj ); + } + } + + void dispatchWrite( BinaryWriter writer, object parentObj, FieldInfo fi ) + { + string typeName = fi.FieldType.Name; + + string name = fi.Name; + + if( fi.IsNotSerialized ) + { + return; + } + + if( fi.FieldType.IsArray ) + { + writer.Write( (char)ETypes.Array ); + writer.Write( name.GetHashCode() ); + + writeArray( writer, (Array)fi.GetValue( parentObj ) ); + } + else if( ( fi.FieldType.IsClass || fi.FieldType.IsInterface ) && typeName != "String" ) + { + writer.Write( (char)ETypes.Ref ); + writer.Write( name.GetHashCode() ); + + writeRefAndSched( writer, fi.GetValue( parentObj ) ); + } + else if( fi.FieldType.IsEnum ) + { + writer.Write( (char)ETypes.Int32 ); + writer.Write( name.GetHashCode() ); + + write( writer, Convert.ToInt32( fi.GetValue( parentObj ) ) ); + } + else + { + switch( typeName ) + { + case "Int32": + writer.Write( (char)ETypes.Int32 ); + writer.Write( name.GetHashCode() ); + + write( writer, Convert.ToInt32( fi.GetValue( parentObj ) ) ); + break; + case "Single": + writer.Write( (char)ETypes.Single ); + writer.Write( name.GetHashCode() ); + + write( writer, Convert.ToSingle( fi.GetValue( parentObj ) ) ); + break; + case "Double": + writer.Write( (char)ETypes.Double ); + writer.Write( name.GetHashCode() ); + + write( writer, Convert.ToDouble( fi.GetValue( parentObj ) ) ); + break; + case "Char": + writer.Write( (char)ETypes.Char ); + writer.Write( name.GetHashCode() ); + + write( writer, Convert.ToChar( fi.GetValue( parentObj ) ) ); + break; + case "String": + writer.Write( (char)ETypes.String ); + writer.Write( name.GetHashCode() ); + + write( writer, Convert.ToString( fi.GetValue( parentObj ) ) ); + break; + case "Boolean": + writer.Write( (char)ETypes.Boolean ); + writer.Write( name.GetHashCode() ); + + writer.Write( Convert.ToBoolean( fi.GetValue( parentObj ) ) ); + break; + default: + Console.WriteLine( "VersionFormatter does not understand type " + typeName ); + break; + } + } + } + + void writeArray( BinaryWriter writer, Array array ) + { + if( array == null ) + { + writer.Write( (int)-1 ); + return; + } + + writer.Write( array.Length ); + + foreach( object obj in array ) + { + writeRefAndSched( writer, obj ); + } + } + + void getAllFields( object obj, ArrayList list ) + { + Type t = obj.GetType(); + + while( t != null ) + { + FieldInfo[] fiArr = t.GetFields( BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.DeclaredOnly ); + list.AddRange( fiArr ); + + t = t.BaseType; + } + } + + + void writeObject( BinaryWriter writer, object obj ) + { + Type objType = obj.GetType(); + + writer.Write( (char)ETypes.Object ); + writer.Write( objType.FullName ); + + int objRef = obj.GetHashCode(); + writer.Write( objRef ); + + ArrayList list = new ArrayList(); + + getAllFields( obj, list ); + + foreach( FieldInfo fi in list ) + { + dispatchWrite( writer, obj, fi ); + } + + writer.Write( (char)ETypes.EndObject ); + } + + void write( BinaryWriter wr, TType val ) + { + //wr.Write( val ); + } + + /* + void writeInt( BinaryWriter writer, int val ) + { + writer.Write( val ); + } + + void writeSingle( BinaryWriter writer, float val ) + { + writer.Write( val ); + } + + void writeDouble( BinaryWriter writer, double val ) + { + writer.Write( val ); + } + + void writeChar( BinaryWriter writer, char val ) + { + writer.Write( val ); + } + + void writeString( BinaryWriter writer, string val ) + { + writer.Write( val ); + } + + void writeBool( BinaryWriter writer, bool val ) + { + writer.Write( val ); + } + */ + #endregion Serialize + + + #region Deserialize + + class Fixup + { + public Fixup( int guid, object obj, FieldInfo fi ) + { + m_guid = guid; + m_obj = obj; + m_fi = fi; + } + + public Fixup( int guid, object obj, int index ) + { + m_guid = guid; + m_obj = obj; + m_index = index; + } + + public readonly int m_guid = 0; + public readonly object m_obj = null; + + public readonly FieldInfo m_fi = null; + public readonly int m_index= -1; + + } + + Hashtable m_mapGUIDToObject = new Hashtable(); + ArrayList m_fixupList = new ArrayList(); + + ArrayList m_desObjects = new ArrayList(); + + public object Deserialize( Stream stream ) + { + BinaryReader reader = new BinaryReader( stream ); + + object objRoot = null; + + //Read in the first object. + { + ETypes type = (ETypes)reader.ReadChar(); + + Debug.Assert( type == ETypes.Object ); + + objRoot = readObject( reader ); + + m_desObjects.Add( objRoot ); + } + + bool readObjects = true; + + while( readObjects ) + { + ETypes type = (ETypes)reader.ReadChar(); + + Debug.Assert( type == ETypes.Object || type == ETypes.EndStream ); + + if( type == ETypes.Object ) + { + object obj = readObject( reader ); + + m_desObjects.Add( obj ); + } + else + { + Debug.Assert( type == ETypes.EndStream ); + + readObjects = false; + } + } + + foreach( Fixup fu in m_fixupList ) + { + //Fixup fix = m_fixups[ + + object obj = m_mapGUIDToObject[ fu.m_guid ]; + + if( obj != null ) + { + if( fu.m_fi != null ) + { + fu.m_fi.SetValue( fu.m_obj, obj ); + } + else + { + Debug.Assert( fu.m_index >= 0 ); + + object []array = (object [])fu.m_obj; + + array[fu.m_index] = obj; + } + } + else + { + Console.WriteLine( "Obj to ref is null." ); + } + } + + foreach( object obj in m_desObjects ) + { + if( typeof( IDeserializationCallback ).IsAssignableFrom( obj.GetType() ) ) + { + IDeserializationCallback desCB = (IDeserializationCallback)obj; + + if( desCB != null ) + { + desCB.OnDeserialization( this ); + } + } + } + + return objRoot; + } + + + + bool dispatchRead( BinaryReader reader, object obj, Hashtable ht ) + { + + //Read the type + ETypes type = (ETypes)reader.ReadChar(); + + if( type == ETypes.EndObject ) + { + return false; + } + + int nameHash = reader.ReadInt32(); + + FieldInfo fi = (FieldInfo)ht[ nameHash ]; + + if( fi == null ) + { + Console.WriteLine( "Field no longer exists" ); + } + + try + { + switch( type ) + { + case ETypes.Array: + readArray( reader, obj, fi ); + break; + case ETypes.Int32: + readInt( reader, obj, fi ); + break; + case ETypes.Single: + readSingle( reader, obj, fi ); + break; + case ETypes.Double: + readDouble( reader, obj, fi ); + break; + case ETypes.Char: + readChar( reader, obj, fi ); + break; + case ETypes.Boolean: + readBool( reader, obj, fi ); + break; + case ETypes.String: + readString( reader, obj, fi ); + break; + case ETypes.Ref: + readRef( reader, obj, fi ); + break; + case ETypes.Object: + readObject( reader ); + break; + default: + Debug.Fail( "Unknown type on read." ); + break; + } + } + catch( Exception ex ) + { + Console.WriteLine( "Exception: " + ex.Message ); + Console.WriteLine( "Stack: " + ex.StackTrace ); + } + + + return true; + } + + object createObject( string objTypeName ) + { + Assembly[] ass = AppDomain.CurrentDomain.GetAssemblies(); + + foreach( Assembly a in ass ) + { + Type t = a.GetType( objTypeName ); + + if( t != null ) + { + object obj = FormatterServices.GetUninitializedObject( t ); + + if( obj != null ) + { + return obj; + } + } + } + + return null; + } + + + object readObject( BinaryReader reader ) + { + //ETypes type = (ETypes)reader.ReadChar(); + + //Debug.Assert( type == ETypes.Object, "Expecting type Object" ); + + string objTypeName = reader.ReadString(); + int objGUID = reader.ReadInt32(); + + try + { + object obj = createObject( objTypeName ); + + m_mapGUIDToObject[objGUID] = obj; + + ArrayList list = new ArrayList(); + Hashtable ht = new Hashtable(); + + if( obj != null ) + { + getAllFields( obj, list ); + + foreach( FieldInfo fi in list ) + { + ht[fi.Name.GetHashCode()] = fi; + } + } + + while( dispatchRead( reader, obj, ht ) ) + { + } + + return obj; + } + catch( Exception ex ) + { + Console.WriteLine( "Exception: " + ex.Message ); + } + + return null; + } + + void readArray( BinaryReader reader, object obj, FieldInfo fi ) + { + int length = reader.ReadInt32(); + + if( length < 0 ) + { + if( fi == null ) + return; + + fi.SetValue( obj, null ); + + return; + } + + object[] array = new object[length]; + + if( fi != null ) + { + fi.SetValue( obj, array ); + } + + for( int i = 0; i < length; ++i ) + { + int val = reader.ReadInt32(); + + //m_fixups[ val ] = new Fixup( obj, fi ); + + if( fi != null ) + { + m_fixupList.Add( new Fixup( val, array, i ) ); + } + } + } + + void readRef( BinaryReader reader, object obj, FieldInfo fi ) + { + int val = reader.ReadInt32(); + + //m_fixups[ val ] = new Fixup( obj, fi ); + + m_fixupList.Add( new Fixup( val, obj, fi ) ); + } + + void readInt( BinaryReader reader, object obj, FieldInfo fi ) + { + int val = reader.ReadInt32(); + + if( fi == null ) + return; + + if( !fi.FieldType.IsEnum ) + { + fi.SetValue( obj, val ); + } + else + { + object enumVal = Enum.Parse( fi.FieldType, val.ToString() ); + fi.SetValue( obj, Convert.ChangeType( enumVal, fi.FieldType ) ); + } + + } + + void readSingle( BinaryReader reader, object obj, FieldInfo fi ) + { + float val = reader.ReadSingle(); + + if( fi == null ) + return; + + fi.SetValue( obj, val ); + } + + void readDouble( BinaryReader reader, object obj, FieldInfo fi ) + { + double val = reader.ReadDouble(); + + if( fi == null ) + return; + + fi.SetValue( obj, val ); + } + + void readChar( BinaryReader reader, object obj, FieldInfo fi ) + { + char val = reader.ReadChar(); + + if( fi == null ) + return; + + fi.SetValue( obj, val ); + } + + void readString( BinaryReader reader, object obj, FieldInfo fi ) + { + string val = reader.ReadString(); + + if( fi == null ) + return; + + fi.SetValue( obj, val ); + } + + void readBool( BinaryReader reader, object obj, FieldInfo fi ) + { + bool val = reader.ReadBoolean(); + + if( fi == null ) + return; + + fi.SetValue( obj, val ); + } + + #endregion Deserialize + + + } +} + + + + + + + + + + + + + + + + + + + diff --git a/ser/XmlFormatter.cs b/ser/XmlFormatter.cs index e1df418..7f0fa03 100644 --- a/ser/XmlFormatter.cs +++ b/ser/XmlFormatter.cs @@ -1,1094 +1,1094 @@ -using System; -using System.IO; -using System.Xml; -using System.Runtime.Serialization; -//using System.Web.Configuration; -using System.Collections; -using System.Collections.Generic; - - -using System.Reflection; -//using System.Collections; -//using System.Diagnostics; -//using System.Globalization; -//using System.ComponentModel; - - -namespace lib -{ - //Old, use 2 now. - class XmlFormatter: IFormatter - { - StreamingContext m_context; - //SerializationMode m_mode; - //KnownTypeCollection known_types; - //IDataContractSurrogate m_surrogate; - //int m_maxItems; - - public XmlFormatter() - { - } - - /* - public XmlFormatter( SerializationMode mode ) - { - m_mode = mode; - } - - public XmlFormatter( StreamingContext context ) - { - m_context = context; - } - - public XmlFormatter( SerializationMode mode, - StreamingContext context ) - { - m_mode = mode; - m_context = context; - } - */ - - //public XmlFormatter (SerializationMode mode, - // StreamingContext context, KnownTypeCollection knownTypes) - //{ - //} - - SerializationBinder IFormatter.Binder - { - get { throw new NotImplementedException(); } - set { throw new NotImplementedException(); } - } - - ISurrogateSelector IFormatter.SurrogateSelector - { - get { throw new NotImplementedException(); } - set { throw new NotImplementedException(); } - } - - public StreamingContext Context - { - get { return m_context; } - set { m_context = value; } - } - - - /* - public KnownTypeCollection KnownTypes { - get { return known_types; } - } - - public int MaxItemsInObjectGraph { - get { return m_maxItems; } - set { m_maxItems= value; } - } - */ - - - object IFormatter.Deserialize( Stream stream ) - { - return Deserialize( stream, null ); - } - - public object Deserialize( Stream stream, Type type ) - { - XmlTextReader reader = new XmlTextReader( stream ); - - return Deserialize( reader, type ); - } - - public object Deserialize( XmlReader reader, Type type ) - { - return Deserialize( reader, type, false ); - } - - public object Deserialize( XmlReader reader, Type type, bool readContentOnly ) - { - reader.Read(); - - XmlDocument doc = new XmlDocument(); - - doc.Load( reader ); - - return Deserialize( doc.DocumentElement ); - } - - ConstructorInfo getNoParamCons( ConstructorInfo[] ciArr ) - { - foreach( ConstructorInfo ci in ciArr ) - { - if( ci.GetParameters().Length == 0 ) - { - return ci; - } - } - - return null; - } - - private static FormatterConverter s_conv = new FormatterConverter(); - - private Dictionary m_alreadySerialized = new Dictionary(); - - public object Deserialize( XmlElement elem ) - { - string strType = elem.GetAttribute( "t" ); - - return Deserialize( elem, strType ); - } - - public object Deserialize( XmlElement elem, string strType ) - { - Type type = Type.GetType( strType ); - - MemberInfo[] miArr = FormatterServices.GetSerializableMembers( type ); - - object obj = Activator.CreateInstance( type ); - - - /* - object obj = FormatterServices.GetUninitializedObject( type ); - - - ConstructorInfo[] ciArr = obj.GetType().GetConstructors(); - - ConstructorInfo ci = getNoParamCons( ciArr ); - - if( ci == null ) - return null; - - obj = ci.Invoke( null ); - */ - - for( int i = 0; i < miArr.Length; ++i ) - { - FieldInfo fi = (FieldInfo)miArr[ i ]; - - XmlNodeList nodeList = elem.GetElementsByTagName( fi.Name ); - - if( nodeList.Count == 1 ) - { - Type t = fi.FieldType; - - TypeCode tc = Type.GetTypeCode( t ); - - XmlElement child = (XmlElement)nodeList[ 0 ]; - - object childObj = null; - - if( tc != TypeCode.Object || fi.FieldType.FullName == "System.String" ) - { - childObj = s_conv.Convert( child.GetAttribute( "v" ), fi.FieldType ); - } - else - { - if( !t.IsArray ) - { - string refStr = child.GetAttribute( "ref" ); - int refInt = Convert.ToInt32( refStr ); - - if( child.HasAttribute( "t" ) ) - { - childObj = Deserialize( child ); - - m_alreadySerialized[refInt] = childObj; - } - else - { - childObj = m_alreadySerialized[refInt]; - } - } - else - { - //FormatterServices.GetUninitializedObject() - - int length = s_conv.ToInt32( child.GetAttribute( "c" ) ); - - string elemType = child.GetAttribute( "t" ); - - Array arr = Array.CreateInstance( t.GetElementType(), length ); - - XmlNodeList arrNodeList = child.ChildNodes; - - for( int iElems = 0; iElems < arr.Length; ++iElems ) - { - XmlElement arrElem = (XmlElement)arrNodeList.Item( iElems ); - - arr.SetValue( Deserialize( arrElem, elemType ), iElems ); - } - } - } - - fi.SetValue( obj, childObj ); - } - else - { - if( nodeList.Count == 0 ) - { - // Should be - - //object obj2 = fi.GetRawConstantValue(); - } - else //More than 1. - { - //log.error( "Too many fields named the same thing" ); - } - } - } - - //FieldInfo fi = (FieldInfo)miArr[0]; - - //ConstructorInfo ci = fi.FieldType.TypeInitializer; - - //ci.Invoke( null ); - - return obj; - } - - - /* - public T Deserialize (Stream stream) - { - return (T) Deserialize (XmlReader.Create (stream), typeof (T)); - } - - public T Deserialize (XmlReader reader) - { - return (T) Deserialize (reader, typeof (T), false); - } - - public T Deserialize (XmlReader reader, bool readContentOnly) - { - return (T) Deserialize (reader, typeof (T), readContentOnly); - } - */ - - public void Serialize( Stream stream, object graph ) - { - /* - XmlWriterSettings settings = new XmlWriterSettings(); - - settings.Indent = true; - - Serialize( XmlWriter.Create( stream, settings ), graph ); - */ - - XmlTextWriter writer = new XmlTextWriter( stream, null ); - - writer.Formatting = Formatting.Indented; - - Serialize( writer, graph ); - - writer.Close(); - } - - public void Serialize( XmlWriter writer, object graph ) - { - Serialize( writer, graph, null, true, false, true ); - } - - public void Serialize( XmlWriter writer, object graph, - Type rootType, bool preserveObjectReferences, - bool writeContentOnly, - bool ignoreUnknownSerializationData ) - { - Type t = graph.GetType(); - - //writer.WriteStartDocument(); - - if( Type.GetTypeCode( t ) == TypeCode.Object ) - { - writer.WriteStartElement( "root" ); - - Assembly assem = t.Assembly; - - string assemName = assem.GetName().Name; - - writer.WriteAttributeString( "t", graph.GetType().FullName + ", " + assemName ); - - FieldInfo[] fiArr = t.GetFields( BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.DeclaredOnly ); - - foreach( FieldInfo fi in fiArr ) - { - Serialize( writer, fi.Name, fi.GetValue( graph ) ); - - /* - if( fi.FieldType.IsClass ) - { - Serialize( writer, fi.GetValue( graph ), rootType, preserveObjectReferences, writeContentOnly, ignoreUnknownSerializationData ); - } - else - { - SerializePod( writer, fi.GetValue( graph ) ); - } - */ - } - - writer.WriteEndElement(); - } - - //writer.WriteEndDocument(); - } - - private ObjectIDGenerator m_idGenerator = new ObjectIDGenerator(); - private Dictionary m_alreadyDeserialzied = new Dictionary(); - - public void Serialize( XmlWriter writer, string name, object obj ) - { - writer.WriteStartElement( name ); - - if( obj != null ) - { - Type t = obj.GetType(); - - if( Type.GetTypeCode( t ) == TypeCode.Object ) - { - bool first = false; - if( !m_alreadyDeserialzied.ContainsKey( m_idGenerator.GetId( obj, out first ) ) ) - { - m_alreadyDeserialzied[m_idGenerator.GetId( obj, out first )] = obj; - - Assembly assem = t.Assembly; - - string assemName = assem.GetName().Name; - - if( !t.IsArray ) - { - writer.WriteAttributeString( "t", t.FullName + ", " + assemName ); - - writer.WriteAttributeString( "ref", m_idGenerator.GetId( obj, out first ).ToString() ); - - FieldInfo[] fiArr = t.GetFields( BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public ); - - foreach( FieldInfo fi in fiArr ) - { - Serialize( writer, fi.Name, fi.GetValue( obj ) ); - } - } - else - { - Array arr = (Array)obj; - - Type aType = t.GetElementType(); - - string aTypeString = aType.FullName; - - writer.WriteAttributeString( "t", aTypeString + ", " + assemName ); - - writer.WriteAttributeString( "c", arr.Length.ToString() ); - - for( int i = 0; i < arr.Length; ++i ) - { - Serialize( writer, "val", arr.GetValue( i ) ); - } - - //writer.WriteStartElement( "values" ); - - - - //writer.WriteEndElement(); - - } - } - else - { - writer.WriteAttributeString( "ref", m_idGenerator.GetId( obj, out first ).ToString() ); - } - } - else - { - writer.WriteAttributeString( "t", t.FullName ); - - writer.WriteAttributeString( "v", obj.ToString() ); - } - } - else - { - writer.WriteAttributeString( "null", "" ); - } - - writer.WriteEndElement(); - } - - } -} - - - - - - - - - - - - - - - - - - -/* -/// -/// -/// -public class XmlFormatter : IFormatter -{ - public enum ETypes - { - Array, - Int32, - Ref, - Object, - EndObject, - Single, - Double, - Char, - String, - Boolean, - EndStream, - } - - - public XmlFormatter() - { - // - // TODO: Add constructor logic here - // - } - - - #region Useless - public ISurrogateSelector SurrogateSelector - { - get - { - return null; - } - - set - { - } - } - - public SerializationBinder Binder - { - get - { - return null; - } - - set - { - } - } - - public StreamingContext Context - { - get - { - return new StreamingContext(); - } - - set - { - } - } - #endregion Useless - - Queue m_objectsToBeDeserialized = new Queue(); - Hashtable m_alreadyDeserialzied = new Hashtable(); - //int m_GUID = 0; - - #region Serialize - public void Serialize( System.IO.Stream stream, object obj ) - { - //Default is 4k - //BufferedStream bufStream = new BufferedStream( stream ); - - TextWriter writer = new StreamWriter( stream ); - - writeObject( writer, obj ); - - while( m_objectsToBeDeserialized.Count != 0 ) - { - object objToDes = m_objectsToBeDeserialized.Dequeue(); - - writeObject( writer, objToDes ); - } - - writer.Write( (char)ETypes.EndStream ); - } - - void writeRefAndSched( TextWriter writer, object obj ) - { - //if( m_alreadyDeserialzied[ obj.GetType().GetArrayRank( - - if( obj == null ) - { - writer.Write( 0 ); - return; - } - - - //Now write the address. - //Bad bad. Need to do this correctly. - int objRef = obj.GetHashCode(); - writer.Write( objRef ); - - if( m_alreadyDeserialzied[ obj ] == null ) - { - m_alreadyDeserialzied[ obj ] = obj; - m_objectsToBeDeserialized.Enqueue( obj ); - } - } - - void dispatchWrite( TextWriter writer, object parentObj, FieldInfo fi ) - { - string typeName = fi.FieldType.Name; - - string name = fi.Name; - - if( fi.IsNotSerialized ) - { - return; - } - - if( fi.FieldType.IsArray ) - { - writer.Write( (char)ETypes.Array ); - writer.Write( name.GetHashCode() ); - - writeArray( writer, (Array)fi.GetValue( parentObj ) ); - } - else if( ( fi.FieldType.IsClass || fi.FieldType.IsInterface ) && typeName != "String" ) - { - writer.Write( (char)ETypes.Ref ); - writer.Write( name.GetHashCode() ); - - writeRefAndSched( writer, fi.GetValue( parentObj ) ); - } - else if( fi.FieldType.IsEnum ) - { - writer.Write( (char)ETypes.Int32 ); - writer.Write( name.GetHashCode() ); - - writer.Write( Convert.ToInt32( fi.GetValue( parentObj ) ) ); - } - else - { - switch( typeName ) - { - case "Int32": - writer.Write( (char)ETypes.Int32 ); - writer.Write( name.GetHashCode() ); - - writer.Write( Convert.ToInt32( fi.GetValue( parentObj ) ) ); - break; - case "Single": - writer.Write( (char)ETypes.Single ); - writer.Write( name.GetHashCode() ); - - writer.Write( Convert.ToSingle( fi.GetValue( parentObj ) ) ); - break; - case "Double": - writer.Write( (char)ETypes.Double ); - writer.Write( name.GetHashCode() ); - - writer.Write( Convert.ToDouble( fi.GetValue( parentObj ) ) ); - break; - case "Char": - writer.Write( (char)ETypes.Char ); - writer.Write( name.GetHashCode() ); - - writer.Write( Convert.ToChar( fi.GetValue( parentObj ) ) ); - break; - case "String": - writer.Write( (char)ETypes.String ); - writer.Write( name.GetHashCode() ); - - writer.Write( Convert.ToString( fi.GetValue( parentObj ) ) ); - break; - case "Boolean": - writer.Write( (char)ETypes.Boolean ); - writer.Write( name.GetHashCode() ); - - writer.Write( Convert.ToBoolean( fi.GetValue( parentObj ) ) ); - break; - default: - Console.WriteLine( "VersionFormatter does not understand type " + typeName ); - break; - } - } - } - - void writeArray( TextWriter writer, Array array ) - { - if( array == null ) - { - writer.Write( (int)-1 ); - return; - } - - writer.Write( array.Length ); - - foreach( object obj in array ) - { - writeRefAndSched( writer, obj ); - } - } - - void getAllFields( object obj, ArrayList list ) - { - Type t = obj.GetType(); - - while( t != null ) - { - FieldInfo[] fiArr = t.GetFields( BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.DeclaredOnly ); - list.AddRange( fiArr ); - - t = t.BaseType; - } - } - - - void writeObject( TextWriter writer, object obj ) - { - Type objType = obj.GetType(); - - writer.Write( (char)ETypes.Object ); - writer.Write( objType.FullName ); - - int objRef = obj.GetHashCode(); - writer.Write( objRef ); - - ArrayList list = new ArrayList(); - - getAllFields( obj, list ); - - foreach( FieldInfo fi in list ) - { - dispatchWrite( writer, obj, fi ); - } - - writer.Write( (char)ETypes.EndObject ); - } - - void write( TextWriter wr, TType val ) - { - //wr.Write( val ); - } - - /* - void writeInt( TextWriter writer, int val ) - { - writer.Write( val ); - } - - void writeSingle( TextWriter writer, float val ) - { - writer.Write( val ); - } - - void writeDouble( TextWriter writer, double val ) - { - writer.Write( val ); - } - - void writeChar( TextWriter writer, char val ) - { - writer.Write( val ); - } - - void writeString( TextWriter writer, string val ) - { - writer.Write( val ); - } - - void writeBool( TextWriter writer, bool val ) - { - writer.Write( val ); - } - * / - #endregion Serialize - - - #region Deserialize - - class Fixup - { - public Fixup( int guid, object obj, FieldInfo fi ) - { - m_guid= guid; - m_obj = obj; - m_fi = fi; - } - - XmlFormatter - - public Fixup( int guid, object obj, int index ) - { - m_guid = guid; - m_obj = obj; - m_index= index; - } - - public readonly int m_guid = 0; - public readonly object m_obj = null; - - public readonly FieldInfo m_fi = null; - public readonly int m_index= -1; - - } - - Hashtable m_mapGUIDToObject = new Hashtable(); - ArrayList m_fixupList = new ArrayList(); - - ArrayList m_desObjects = new ArrayList(); - - public object Deserialize( System.IO.Stream stream ) - { - StreamReader reader = new StreamReader( stream ); - - object objRoot = null; - - //Read in the first object. - { - ETypes type = (ETypes)reader.ReadChar(); - - Debug.Assert( type == ETypes.Object ); - - objRoot = readObject( reader ); - - m_desObjects.Add( objRoot ); - } - - bool readObjects = true; - - while( readObjects ) - { - ETypes type = (ETypes)reader.ReadChar(); - - Debug.Assert( type == ETypes.Object || type == ETypes.EndStream ); - - if( type == ETypes.Object ) - { - object obj = readObject( reader ); - - m_desObjects.Add( obj ); - } - else - { - Debug.Assert( type == ETypes.EndStream ); - - readObjects = false; - } - } - - foreach( Fixup fu in m_fixupList ) - { - //Fixup fix = m_fixups[ - - object obj = m_mapGUIDToObject[ fu.m_guid ]; - - if( obj != null ) - { - if( fu.m_fi != null ) - { - fu.m_fi.SetValue( fu.m_obj, obj ); - } - else - { - Debug.Assert( fu.m_index >= 0 ); - - object []array = (object [])fu.m_obj; - - array[ fu.m_index ] = obj; - } - } - else - { - Console.WriteLine( "Obj to ref is null." ); - } - } - - foreach( object obj in m_desObjects ) - { - if( typeof( IDeserializationCallback ).IsAssignableFrom( obj.GetType() ) ) - { - IDeserializationCallback desCB = (IDeserializationCallback)obj; - - if( desCB != null ) - { - desCB.OnDeserialization( this ); - } - } - } - - return objRoot; - } - - - - bool dispatchRead( StreamReader reader, object obj, Hashtable ht ) - { - - //Read the type - ETypes type = (ETypes)reader.ReadChar(); - - if( type == ETypes.EndObject ) - { - return false; - } - - int nameHash = reader.ReadInt32(); - - FieldInfo fi = (FieldInfo)ht[ nameHash ]; - - if( fi == null ) - { - Console.WriteLine( "Field no longer exists" ); - } - - try - { - switch( type ) - { - case ETypes.Array: - readArray( reader, obj, fi ); - break; - case ETypes.Int32: - readInt( reader, obj, fi ); - break; - case ETypes.Single: - readSingle( reader, obj, fi ); - break; - case ETypes.Double: - readDouble( reader, obj, fi ); - break; - case ETypes.Char: - readChar( reader, obj, fi ); - break; - case ETypes.Boolean: - readBool( reader, obj, fi ); - break; - case ETypes.String: - readString( reader, obj, fi ); - break; - case ETypes.Ref: - readRef( reader, obj, fi ); - break; - case ETypes.Object: - readObject( reader ); - break; - default: - Debug.Fail( "Unknown type on read." ); - break; - } - } - catch( Exception ex ) - { - Console.WriteLine( "Exception: " + ex.Message ); - Console.WriteLine( "Stack: " + ex.StackTrace ); - } - - - return true; - } - - object createObject( string objTypeName ) - { - Assembly[] ass = AppDomain.CurrentDomain.GetAssemblies(); - - foreach( Assembly a in ass ) - { - Type t = a.GetType( objTypeName ); - - if( t != null ) - { - object obj = FormatterServices.GetUninitializedObject( t ); - - if( obj != null ) - { - return obj; - } - } - } - - return null; - } - - - object readObject( StreamReader reader ) - { - //ETypes type = (ETypes)reader.ReadChar(); - - //Debug.Assert( type == ETypes.Object, "Expecting type Object" ); - - string objTypeName = reader.ReadString(); - int objGUID = reader.ReadInt32(); - - try - { - object obj = createObject( objTypeName ); - - m_mapGUIDToObject[ objGUID ] = obj; - - ArrayList list = new ArrayList(); - Hashtable ht = new Hashtable(); - - if( obj != null ) - { - getAllFields( obj, list ); - - foreach( FieldInfo fi in list ) - { - ht[ fi.Name.GetHashCode() ] = fi; - } - } - - while( dispatchRead( reader, obj, ht ) ) - { - } - - return obj; - } - catch( Exception ex ) - { - Console.WriteLine( "Exception: " + ex.Message ); - } - - return null; - } - - void readArray( StreamReader reader, object obj, FieldInfo fi ) - { - int length = reader.ReadInt32(); - - if( length < 0 ) - { - if( fi == null ) return; - - fi.SetValue( obj, null ); - - return; - } - - object[] array = new object[length]; - - if( fi != null ) - { - fi.SetValue( obj, array ); - } - - for( int i=0; i m_alreadySerialized = new Dictionary(); + + public object Deserialize( XmlElement elem ) + { + string strType = elem.GetAttribute( "t" ); + + return Deserialize( elem, strType ); + } + + public object Deserialize( XmlElement elem, string strType ) + { + Type type = Type.GetType( strType ); + + MemberInfo[] miArr = FormatterServices.GetSerializableMembers( type ); + + object obj = Activator.CreateInstance( type ); + + + /* + object obj = FormatterServices.GetUninitializedObject( type ); + + + ConstructorInfo[] ciArr = obj.GetType().GetConstructors(); + + ConstructorInfo ci = getNoParamCons( ciArr ); + + if( ci == null ) + return null; + + obj = ci.Invoke( null ); + */ + + for( int i = 0; i < miArr.Length; ++i ) + { + FieldInfo fi = (FieldInfo)miArr[ i ]; + + XmlNodeList nodeList = elem.GetElementsByTagName( fi.Name ); + + if( nodeList.Count == 1 ) + { + Type t = fi.FieldType; + + TypeCode tc = Type.GetTypeCode( t ); + + XmlElement child = (XmlElement)nodeList[ 0 ]; + + object childObj = null; + + if( tc != TypeCode.Object || fi.FieldType.FullName == "System.String" ) + { + childObj = s_conv.Convert( child.GetAttribute( "v" ), fi.FieldType ); + } + else + { + if( !t.IsArray ) + { + string refStr = child.GetAttribute( "ref" ); + int refInt = Convert.ToInt32( refStr ); + + if( child.HasAttribute( "t" ) ) + { + childObj = Deserialize( child ); + + m_alreadySerialized[refInt] = childObj; + } + else + { + childObj = m_alreadySerialized[refInt]; + } + } + else + { + //FormatterServices.GetUninitializedObject() + + int length = s_conv.ToInt32( child.GetAttribute( "c" ) ); + + string elemType = child.GetAttribute( "t" ); + + Array arr = Array.CreateInstance( t.GetElementType(), length ); + + XmlNodeList arrNodeList = child.ChildNodes; + + for( int iElems = 0; iElems < arr.Length; ++iElems ) + { + XmlElement arrElem = (XmlElement)arrNodeList.Item( iElems ); + + arr.SetValue( Deserialize( arrElem, elemType ), iElems ); + } + } + } + + fi.SetValue( obj, childObj ); + } + else + { + if( nodeList.Count == 0 ) + { + // Should be + + //object obj2 = fi.GetRawConstantValue(); + } + else //More than 1. + { + //log.error( "Too many fields named the same thing" ); + } + } + } + + //FieldInfo fi = (FieldInfo)miArr[0]; + + //ConstructorInfo ci = fi.FieldType.TypeInitializer; + + //ci.Invoke( null ); + + return obj; + } + + + /* + public T Deserialize (Stream stream) + { + return (T) Deserialize (XmlReader.Create (stream), typeof (T)); + } + + public T Deserialize (XmlReader reader) + { + return (T) Deserialize (reader, typeof (T), false); + } + + public T Deserialize (XmlReader reader, bool readContentOnly) + { + return (T) Deserialize (reader, typeof (T), readContentOnly); + } + */ + + public void Serialize( Stream stream, object graph ) + { + /* + XmlWriterSettings settings = new XmlWriterSettings(); + + settings.Indent = true; + + Serialize( XmlWriter.Create( stream, settings ), graph ); + */ + + XmlTextWriter writer = new XmlTextWriter( stream, null ); + + writer.Formatting = Formatting.Indented; + + Serialize( writer, graph ); + + writer.Close(); + } + + public void Serialize( XmlWriter writer, object graph ) + { + Serialize( writer, graph, null, true, false, true ); + } + + public void Serialize( XmlWriter writer, object graph, + Type rootType, bool preserveObjectReferences, + bool writeContentOnly, + bool ignoreUnknownSerializationData ) + { + Type t = graph.GetType(); + + //writer.WriteStartDocument(); + + if( Type.GetTypeCode( t ) == TypeCode.Object ) + { + writer.WriteStartElement( "root" ); + + Assembly assem = t.Assembly; + + string assemName = assem.GetName().Name; + + writer.WriteAttributeString( "t", graph.GetType().FullName + ", " + assemName ); + + FieldInfo[] fiArr = t.GetFields( BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.DeclaredOnly ); + + foreach( FieldInfo fi in fiArr ) + { + Serialize( writer, fi.Name, fi.GetValue( graph ) ); + + /* + if( fi.FieldType.IsClass ) + { + Serialize( writer, fi.GetValue( graph ), rootType, preserveObjectReferences, writeContentOnly, ignoreUnknownSerializationData ); + } + else + { + SerializePod( writer, fi.GetValue( graph ) ); + } + */ + } + + writer.WriteEndElement(); + } + + //writer.WriteEndDocument(); + } + + private ObjectIDGenerator m_idGenerator = new ObjectIDGenerator(); + private Dictionary m_alreadyDeserialzied = new Dictionary(); + + public void Serialize( XmlWriter writer, string name, object obj ) + { + writer.WriteStartElement( name ); + + if( obj != null ) + { + Type t = obj.GetType(); + + if( Type.GetTypeCode( t ) == TypeCode.Object ) + { + bool first = false; + if( !m_alreadyDeserialzied.ContainsKey( m_idGenerator.GetId( obj, out first ) ) ) + { + m_alreadyDeserialzied[m_idGenerator.GetId( obj, out first )] = obj; + + Assembly assem = t.Assembly; + + string assemName = assem.GetName().Name; + + if( !t.IsArray ) + { + writer.WriteAttributeString( "t", t.FullName + ", " + assemName ); + + writer.WriteAttributeString( "ref", m_idGenerator.GetId( obj, out first ).ToString() ); + + FieldInfo[] fiArr = t.GetFields( BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public ); + + foreach( FieldInfo fi in fiArr ) + { + Serialize( writer, fi.Name, fi.GetValue( obj ) ); + } + } + else + { + Array arr = (Array)obj; + + Type aType = t.GetElementType(); + + string aTypeString = aType.FullName; + + writer.WriteAttributeString( "t", aTypeString + ", " + assemName ); + + writer.WriteAttributeString( "c", arr.Length.ToString() ); + + for( int i = 0; i < arr.Length; ++i ) + { + Serialize( writer, "val", arr.GetValue( i ) ); + } + + //writer.WriteStartElement( "values" ); + + + + //writer.WriteEndElement(); + + } + } + else + { + writer.WriteAttributeString( "ref", m_idGenerator.GetId( obj, out first ).ToString() ); + } + } + else + { + writer.WriteAttributeString( "t", t.FullName ); + + writer.WriteAttributeString( "v", obj.ToString() ); + } + } + else + { + writer.WriteAttributeString( "null", "" ); + } + + writer.WriteEndElement(); + } + + } +} + + + + + + + + + + + + + + + + + + +/* +/// +/// +/// +public class XmlFormatter : IFormatter +{ + public enum ETypes + { + Array, + Int32, + Ref, + Object, + EndObject, + Single, + Double, + Char, + String, + Boolean, + EndStream, + } + + + public XmlFormatter() + { + // + // TODO: Add constructor logic here + // + } + + + #region Useless + public ISurrogateSelector SurrogateSelector + { + get + { + return null; + } + + set + { + } + } + + public SerializationBinder Binder + { + get + { + return null; + } + + set + { + } + } + + public StreamingContext Context + { + get + { + return new StreamingContext(); + } + + set + { + } + } + #endregion Useless + + Queue m_objectsToBeDeserialized = new Queue(); + Hashtable m_alreadyDeserialzied = new Hashtable(); + //int m_GUID = 0; + + #region Serialize + public void Serialize( System.IO.Stream stream, object obj ) + { + //Default is 4k + //BufferedStream bufStream = new BufferedStream( stream ); + + TextWriter writer = new StreamWriter( stream ); + + writeObject( writer, obj ); + + while( m_objectsToBeDeserialized.Count != 0 ) + { + object objToDes = m_objectsToBeDeserialized.Dequeue(); + + writeObject( writer, objToDes ); + } + + writer.Write( (char)ETypes.EndStream ); + } + + void writeRefAndSched( TextWriter writer, object obj ) + { + //if( m_alreadyDeserialzied[ obj.GetType().GetArrayRank( + + if( obj == null ) + { + writer.Write( 0 ); + return; + } + + + //Now write the address. + //Bad bad. Need to do this correctly. + int objRef = obj.GetHashCode(); + writer.Write( objRef ); + + if( m_alreadyDeserialzied[ obj ] == null ) + { + m_alreadyDeserialzied[ obj ] = obj; + m_objectsToBeDeserialized.Enqueue( obj ); + } + } + + void dispatchWrite( TextWriter writer, object parentObj, FieldInfo fi ) + { + string typeName = fi.FieldType.Name; + + string name = fi.Name; + + if( fi.IsNotSerialized ) + { + return; + } + + if( fi.FieldType.IsArray ) + { + writer.Write( (char)ETypes.Array ); + writer.Write( name.GetHashCode() ); + + writeArray( writer, (Array)fi.GetValue( parentObj ) ); + } + else if( ( fi.FieldType.IsClass || fi.FieldType.IsInterface ) && typeName != "String" ) + { + writer.Write( (char)ETypes.Ref ); + writer.Write( name.GetHashCode() ); + + writeRefAndSched( writer, fi.GetValue( parentObj ) ); + } + else if( fi.FieldType.IsEnum ) + { + writer.Write( (char)ETypes.Int32 ); + writer.Write( name.GetHashCode() ); + + writer.Write( Convert.ToInt32( fi.GetValue( parentObj ) ) ); + } + else + { + switch( typeName ) + { + case "Int32": + writer.Write( (char)ETypes.Int32 ); + writer.Write( name.GetHashCode() ); + + writer.Write( Convert.ToInt32( fi.GetValue( parentObj ) ) ); + break; + case "Single": + writer.Write( (char)ETypes.Single ); + writer.Write( name.GetHashCode() ); + + writer.Write( Convert.ToSingle( fi.GetValue( parentObj ) ) ); + break; + case "Double": + writer.Write( (char)ETypes.Double ); + writer.Write( name.GetHashCode() ); + + writer.Write( Convert.ToDouble( fi.GetValue( parentObj ) ) ); + break; + case "Char": + writer.Write( (char)ETypes.Char ); + writer.Write( name.GetHashCode() ); + + writer.Write( Convert.ToChar( fi.GetValue( parentObj ) ) ); + break; + case "String": + writer.Write( (char)ETypes.String ); + writer.Write( name.GetHashCode() ); + + writer.Write( Convert.ToString( fi.GetValue( parentObj ) ) ); + break; + case "Boolean": + writer.Write( (char)ETypes.Boolean ); + writer.Write( name.GetHashCode() ); + + writer.Write( Convert.ToBoolean( fi.GetValue( parentObj ) ) ); + break; + default: + Console.WriteLine( "VersionFormatter does not understand type " + typeName ); + break; + } + } + } + + void writeArray( TextWriter writer, Array array ) + { + if( array == null ) + { + writer.Write( (int)-1 ); + return; + } + + writer.Write( array.Length ); + + foreach( object obj in array ) + { + writeRefAndSched( writer, obj ); + } + } + + void getAllFields( object obj, ArrayList list ) + { + Type t = obj.GetType(); + + while( t != null ) + { + FieldInfo[] fiArr = t.GetFields( BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.DeclaredOnly ); + list.AddRange( fiArr ); + + t = t.BaseType; + } + } + + + void writeObject( TextWriter writer, object obj ) + { + Type objType = obj.GetType(); + + writer.Write( (char)ETypes.Object ); + writer.Write( objType.FullName ); + + int objRef = obj.GetHashCode(); + writer.Write( objRef ); + + ArrayList list = new ArrayList(); + + getAllFields( obj, list ); + + foreach( FieldInfo fi in list ) + { + dispatchWrite( writer, obj, fi ); + } + + writer.Write( (char)ETypes.EndObject ); + } + + void write( TextWriter wr, TType val ) + { + //wr.Write( val ); + } + + /* + void writeInt( TextWriter writer, int val ) + { + writer.Write( val ); + } + + void writeSingle( TextWriter writer, float val ) + { + writer.Write( val ); + } + + void writeDouble( TextWriter writer, double val ) + { + writer.Write( val ); + } + + void writeChar( TextWriter writer, char val ) + { + writer.Write( val ); + } + + void writeString( TextWriter writer, string val ) + { + writer.Write( val ); + } + + void writeBool( TextWriter writer, bool val ) + { + writer.Write( val ); + } + * / + #endregion Serialize + + + #region Deserialize + + class Fixup + { + public Fixup( int guid, object obj, FieldInfo fi ) + { + m_guid= guid; + m_obj = obj; + m_fi = fi; + } + + XmlFormatter + + public Fixup( int guid, object obj, int index ) + { + m_guid = guid; + m_obj = obj; + m_index= index; + } + + public readonly int m_guid = 0; + public readonly object m_obj = null; + + public readonly FieldInfo m_fi = null; + public readonly int m_index= -1; + + } + + Hashtable m_mapGUIDToObject = new Hashtable(); + ArrayList m_fixupList = new ArrayList(); + + ArrayList m_desObjects = new ArrayList(); + + public object Deserialize( System.IO.Stream stream ) + { + StreamReader reader = new StreamReader( stream ); + + object objRoot = null; + + //Read in the first object. + { + ETypes type = (ETypes)reader.ReadChar(); + + Debug.Assert( type == ETypes.Object ); + + objRoot = readObject( reader ); + + m_desObjects.Add( objRoot ); + } + + bool readObjects = true; + + while( readObjects ) + { + ETypes type = (ETypes)reader.ReadChar(); + + Debug.Assert( type == ETypes.Object || type == ETypes.EndStream ); + + if( type == ETypes.Object ) + { + object obj = readObject( reader ); + + m_desObjects.Add( obj ); + } + else + { + Debug.Assert( type == ETypes.EndStream ); + + readObjects = false; + } + } + + foreach( Fixup fu in m_fixupList ) + { + //Fixup fix = m_fixups[ + + object obj = m_mapGUIDToObject[ fu.m_guid ]; + + if( obj != null ) + { + if( fu.m_fi != null ) + { + fu.m_fi.SetValue( fu.m_obj, obj ); + } + else + { + Debug.Assert( fu.m_index >= 0 ); + + object []array = (object [])fu.m_obj; + + array[ fu.m_index ] = obj; + } + } + else + { + Console.WriteLine( "Obj to ref is null." ); + } + } + + foreach( object obj in m_desObjects ) + { + if( typeof( IDeserializationCallback ).IsAssignableFrom( obj.GetType() ) ) + { + IDeserializationCallback desCB = (IDeserializationCallback)obj; + + if( desCB != null ) + { + desCB.OnDeserialization( this ); + } + } + } + + return objRoot; + } + + + + bool dispatchRead( StreamReader reader, object obj, Hashtable ht ) + { + + //Read the type + ETypes type = (ETypes)reader.ReadChar(); + + if( type == ETypes.EndObject ) + { + return false; + } + + int nameHash = reader.ReadInt32(); + + FieldInfo fi = (FieldInfo)ht[ nameHash ]; + + if( fi == null ) + { + Console.WriteLine( "Field no longer exists" ); + } + + try + { + switch( type ) + { + case ETypes.Array: + readArray( reader, obj, fi ); + break; + case ETypes.Int32: + readInt( reader, obj, fi ); + break; + case ETypes.Single: + readSingle( reader, obj, fi ); + break; + case ETypes.Double: + readDouble( reader, obj, fi ); + break; + case ETypes.Char: + readChar( reader, obj, fi ); + break; + case ETypes.Boolean: + readBool( reader, obj, fi ); + break; + case ETypes.String: + readString( reader, obj, fi ); + break; + case ETypes.Ref: + readRef( reader, obj, fi ); + break; + case ETypes.Object: + readObject( reader ); + break; + default: + Debug.Fail( "Unknown type on read." ); + break; + } + } + catch( Exception ex ) + { + Console.WriteLine( "Exception: " + ex.Message ); + Console.WriteLine( "Stack: " + ex.StackTrace ); + } + + + return true; + } + + object createObject( string objTypeName ) + { + Assembly[] ass = AppDomain.CurrentDomain.GetAssemblies(); + + foreach( Assembly a in ass ) + { + Type t = a.GetType( objTypeName ); + + if( t != null ) + { + object obj = FormatterServices.GetUninitializedObject( t ); + + if( obj != null ) + { + return obj; + } + } + } + + return null; + } + + + object readObject( StreamReader reader ) + { + //ETypes type = (ETypes)reader.ReadChar(); + + //Debug.Assert( type == ETypes.Object, "Expecting type Object" ); + + string objTypeName = reader.ReadString(); + int objGUID = reader.ReadInt32(); + + try + { + object obj = createObject( objTypeName ); + + m_mapGUIDToObject[ objGUID ] = obj; + + ArrayList list = new ArrayList(); + Hashtable ht = new Hashtable(); + + if( obj != null ) + { + getAllFields( obj, list ); + + foreach( FieldInfo fi in list ) + { + ht[ fi.Name.GetHashCode() ] = fi; + } + } + + while( dispatchRead( reader, obj, ht ) ) + { + } + + return obj; + } + catch( Exception ex ) + { + Console.WriteLine( "Exception: " + ex.Message ); + } + + return null; + } + + void readArray( StreamReader reader, object obj, FieldInfo fi ) + { + int length = reader.ReadInt32(); + + if( length < 0 ) + { + if( fi == null ) return; + + fi.SetValue( obj, null ); + + return; + } + + object[] array = new object[length]; + + if( fi != null ) + { + fi.SetValue( obj, array ); + } + + for( int i=0; i - /// MicroTimer class - /// - public class MicroTimer - { - public delegate void MicroTimerElapsedEventHandler( - object sender, - MicroTimerEventArgs timerEventArgs ); - public event MicroTimerElapsedEventHandler MicroTimerElapsed; - - System.Threading.Thread _threadTimer = null; - long _ignoreEventIfLateBy = long.MaxValue; - long _timerIntervalInMicroSec = 0; - bool _stopTimer = true; - - public MicroTimer() - { - } - - public MicroTimer( long timerIntervalInMicroseconds ) - { - Interval = timerIntervalInMicroseconds; - } - - public long Interval - { - get - { - return System.Threading.Interlocked.Read( - ref _timerIntervalInMicroSec ); - } - set - { - System.Threading.Interlocked.Exchange( - ref _timerIntervalInMicroSec, value ); - } - } - - public long IgnoreEventIfLateBy - { - get - { - return System.Threading.Interlocked.Read( - ref _ignoreEventIfLateBy ); - } - set - { - System.Threading.Interlocked.Exchange( - ref _ignoreEventIfLateBy, value <= 0 ? long.MaxValue : value ); - } - } - - public bool Enabled - { - set - { - if( value ) - { - Start(); - } - else - { - Stop(); - } - } - get - { - return ( _threadTimer != null && _threadTimer.IsAlive ); - } - } - - public void Start() - { - if( Enabled || Interval <= 0 ) - { - return; - } - - _stopTimer = false; - - System.Threading.ThreadStart threadStart = delegate() - { - NotificationTimer(ref _timerIntervalInMicroSec, - ref _ignoreEventIfLateBy, - ref _stopTimer); - }; - - _threadTimer = new System.Threading.Thread( threadStart ); - _threadTimer.Priority = System.Threading.ThreadPriority.Highest; - _threadTimer.Start(); - } - - public void Stop() - { - _stopTimer = true; - - if( _threadTimer != null && _threadTimer.ManagedThreadId == - System.Threading.Thread.CurrentThread.ManagedThreadId ) - { - return; - } - - while( Enabled ) - { - System.Threading.Thread.SpinWait( 10 ); - } - } - - void NotificationTimer( ref long timerIntervalInMicroSec, - ref long ignoreEventIfLateBy, - ref bool stopTimer ) - { - int timerCount = 0; - long nextNotification = 0; - - MicroStopwatch microStopwatch = new MicroStopwatch(); - microStopwatch.Start(); - - while( !stopTimer ) - { - long callbackFunctionExecutionTime = - microStopwatch.ElapsedMicroseconds - nextNotification; - - long timerIntervalInMicroSecCurrent = - System.Threading.Interlocked.Read(ref timerIntervalInMicroSec); - long ignoreEventIfLateByCurrent = - System.Threading.Interlocked.Read(ref ignoreEventIfLateBy); - - nextNotification += timerIntervalInMicroSecCurrent; - timerCount++; - long elapsedMicroseconds = 0; - - while( ( elapsedMicroseconds = microStopwatch.ElapsedMicroseconds ) - < nextNotification ) - { - System.Threading.Thread.SpinWait( 10 ); - } - - long timerLateBy = elapsedMicroseconds - nextNotification; - - if( timerLateBy >= ignoreEventIfLateByCurrent ) - { - continue; - } - - MicroTimerEventArgs microTimerEventArgs = - new MicroTimerEventArgs(timerCount, - elapsedMicroseconds, - timerLateBy, - callbackFunctionExecutionTime); - MicroTimerElapsed( this, microTimerEventArgs ); - } - - microStopwatch.Stop(); - } - } - - /// - /// MicroTimer Event Argument class - /// - public class MicroTimerEventArgs: EventArgs - { - // Simple counter, number times timed event (callback function) executed - public int TimerCount { get; private set; } - - // Time when timed event was called since timer started - public long ElapsedMicroseconds { get; private set; } - - // How late the timer was compared to when it should have been called - public long TimerLateBy { get; private set; } - - // Time it took to execute previous call to callback function (OnTimedEvent) - public long CallbackFunctionExecutionTime { get; private set; } - - public MicroTimerEventArgs( int timerCount, - long elapsedMicroseconds, - long timerLateBy, - long callbackFunctionExecutionTime ) - { - TimerCount = timerCount; - ElapsedMicroseconds = elapsedMicroseconds; - TimerLateBy = timerLateBy; - CallbackFunctionExecutionTime = callbackFunctionExecutionTime; - } - } - - - public class Timer - { - MicroStopwatch m_watch; - private long startTime; - private long stopTime; - private long freq; - private long freq_millis; - - public Timer() - { - m_watch = new MicroStopwatch(); - //startTime = m_watch.ElapsedMicroseconds; - //stopTime = m_watch.ElapsedMicroseconds; - freq = 1000 * 1000; - freq_millis = freq / 1000; - - Start(); - } - - // Start the timer - - public Timer Start() - { - m_watch.Start(); - startTime = m_watch.ElapsedMicroseconds; - stopTime = m_watch.ElapsedMicroseconds; - return this; - } - - // Stop the timer - - public Timer Stop() - { - m_watch.Stop(); - stopTime = m_watch.ElapsedMicroseconds; - return this; - } - - public double Seconds - { - get - { - long current = m_watch.ElapsedMicroseconds; - return (double)( current - startTime ) / freq; - } - } - - public long Current - { - get - { - long current = m_watch.ElapsedMicroseconds; - return ( current - startTime ) / freq_millis; - } - } - - public double Duration - { - get - { - return (double)( stopTime - startTime ) / (double)freq; - } - } - - public long DurationMS - { - get { return ( stopTime - startTime ) / freq_millis; } - } - } - - - public class TimerWin - { - [DllImport( "Kernel32.dll" )] - private static extern bool QueryPerformanceCounter( - out long lpPerformanceCount ); - - [DllImport( "Kernel32.dll" )] - private static extern bool QueryPerformanceFrequency( - out long lpFrequency ); - - private long startTime; - private long stopTime; - private long freq; - private long freq_millis; - - // Constructor - - public TimerWin() - { - startTime = 0; - stopTime = 0; - - if( QueryPerformanceFrequency( out freq ) == false ) - { - // high-performance counter not supported - throw new Win32Exception(); - } - - freq_millis = freq / 1000; - - } - - // Start the timer - - public void Start() - { - // lets do the waiting threads there work - - //Thread.Sleep(0); - - QueryPerformanceCounter( out startTime ); - } - - // Stop the timer - - public void Stop() - { - QueryPerformanceCounter( out stopTime ); - } - - public double Seconds - { - get - { - long current; - - QueryPerformanceCounter( out current ); - - return (double)( current - startTime ) / freq; - } - } - - public long Current - { - get - { - long current; - - QueryPerformanceCounter( out current ); - - return ( current - startTime ) / freq_millis; - } - } - - public double Duration - { - get - { - return (double)( stopTime - startTime ) / (double)freq; - } - } - - public long DurationMS - { - get { return ( stopTime - startTime ) / freq_millis; } - } - } -} +using System; +using System.Runtime.InteropServices; +using System.ComponentModel; +using System.Threading; + +namespace lib +{ + + public class MicroStopwatch: System.Diagnostics.Stopwatch + { + readonly double _microSecPerTick + = 1000000D / System.Diagnostics.Stopwatch.Frequency; + + public MicroStopwatch() + { + if( !System.Diagnostics.Stopwatch.IsHighResolution ) + { + throw new Exception( "On this system the high-resolution " + + "performance counter is not available" ); + } + } + + public long ElapsedMicroseconds + { + get + { + return (long)( ElapsedTicks * _microSecPerTick ); + } + } + } + + /// + /// MicroTimer class + /// + public class MicroTimer + { + public delegate void MicroTimerElapsedEventHandler( + object sender, + MicroTimerEventArgs timerEventArgs ); + public event MicroTimerElapsedEventHandler MicroTimerElapsed; + + System.Threading.Thread _threadTimer = null; + long _ignoreEventIfLateBy = long.MaxValue; + long _timerIntervalInMicroSec = 0; + bool _stopTimer = true; + + public MicroTimer() + { + } + + public MicroTimer( long timerIntervalInMicroseconds ) + { + Interval = timerIntervalInMicroseconds; + } + + public long Interval + { + get + { + return System.Threading.Interlocked.Read( + ref _timerIntervalInMicroSec ); + } + set + { + System.Threading.Interlocked.Exchange( + ref _timerIntervalInMicroSec, value ); + } + } + + public long IgnoreEventIfLateBy + { + get + { + return System.Threading.Interlocked.Read( + ref _ignoreEventIfLateBy ); + } + set + { + System.Threading.Interlocked.Exchange( + ref _ignoreEventIfLateBy, value <= 0 ? long.MaxValue : value ); + } + } + + public bool Enabled + { + set + { + if( value ) + { + Start(); + } + else + { + Stop(); + } + } + get + { + return ( _threadTimer != null && _threadTimer.IsAlive ); + } + } + + public void Start() + { + if( Enabled || Interval <= 0 ) + { + return; + } + + _stopTimer = false; + + System.Threading.ThreadStart threadStart = delegate() + { + NotificationTimer(ref _timerIntervalInMicroSec, + ref _ignoreEventIfLateBy, + ref _stopTimer); + }; + + _threadTimer = new System.Threading.Thread( threadStart ); + _threadTimer.Priority = System.Threading.ThreadPriority.Highest; + _threadTimer.Start(); + } + + public void Stop() + { + _stopTimer = true; + + if( _threadTimer != null && _threadTimer.ManagedThreadId == + System.Threading.Thread.CurrentThread.ManagedThreadId ) + { + return; + } + + while( Enabled ) + { + System.Threading.Thread.SpinWait( 10 ); + } + } + + void NotificationTimer( ref long timerIntervalInMicroSec, + ref long ignoreEventIfLateBy, + ref bool stopTimer ) + { + int timerCount = 0; + long nextNotification = 0; + + MicroStopwatch microStopwatch = new MicroStopwatch(); + microStopwatch.Start(); + + while( !stopTimer ) + { + long callbackFunctionExecutionTime = + microStopwatch.ElapsedMicroseconds - nextNotification; + + long timerIntervalInMicroSecCurrent = + System.Threading.Interlocked.Read(ref timerIntervalInMicroSec); + long ignoreEventIfLateByCurrent = + System.Threading.Interlocked.Read(ref ignoreEventIfLateBy); + + nextNotification += timerIntervalInMicroSecCurrent; + timerCount++; + long elapsedMicroseconds = 0; + + while( ( elapsedMicroseconds = microStopwatch.ElapsedMicroseconds ) + < nextNotification ) + { + System.Threading.Thread.SpinWait( 10 ); + } + + long timerLateBy = elapsedMicroseconds - nextNotification; + + if( timerLateBy >= ignoreEventIfLateByCurrent ) + { + continue; + } + + MicroTimerEventArgs microTimerEventArgs = + new MicroTimerEventArgs(timerCount, + elapsedMicroseconds, + timerLateBy, + callbackFunctionExecutionTime); + MicroTimerElapsed( this, microTimerEventArgs ); + } + + microStopwatch.Stop(); + } + } + + /// + /// MicroTimer Event Argument class + /// + public class MicroTimerEventArgs: EventArgs + { + // Simple counter, number times timed event (callback function) executed + public int TimerCount { get; private set; } + + // Time when timed event was called since timer started + public long ElapsedMicroseconds { get; private set; } + + // How late the timer was compared to when it should have been called + public long TimerLateBy { get; private set; } + + // Time it took to execute previous call to callback function (OnTimedEvent) + public long CallbackFunctionExecutionTime { get; private set; } + + public MicroTimerEventArgs( int timerCount, + long elapsedMicroseconds, + long timerLateBy, + long callbackFunctionExecutionTime ) + { + TimerCount = timerCount; + ElapsedMicroseconds = elapsedMicroseconds; + TimerLateBy = timerLateBy; + CallbackFunctionExecutionTime = callbackFunctionExecutionTime; + } + } + + + public class Timer + { + MicroStopwatch m_watch; + private long startTime; + private long stopTime; + private long freq; + private long freq_millis; + + public Timer() + { + m_watch = new MicroStopwatch(); + //startTime = m_watch.ElapsedMicroseconds; + //stopTime = m_watch.ElapsedMicroseconds; + freq = 1000 * 1000; + freq_millis = freq / 1000; + + Start(); + } + + // Start the timer + + public Timer Start() + { + m_watch.Start(); + startTime = m_watch.ElapsedMicroseconds; + stopTime = m_watch.ElapsedMicroseconds; + return this; + } + + // Stop the timer + + public Timer Stop() + { + m_watch.Stop(); + stopTime = m_watch.ElapsedMicroseconds; + return this; + } + + public double Seconds + { + get + { + long current = m_watch.ElapsedMicroseconds; + return (double)( current - startTime ) / freq; + } + } + + public long Current + { + get + { + long current = m_watch.ElapsedMicroseconds; + return ( current - startTime ) / freq_millis; + } + } + + public double Duration + { + get + { + return (double)( stopTime - startTime ) / (double)freq; + } + } + + public long DurationMS + { + get { return ( stopTime - startTime ) / freq_millis; } + } + } + + + public class TimerWin + { + [DllImport( "Kernel32.dll" )] + private static extern bool QueryPerformanceCounter( + out long lpPerformanceCount ); + + [DllImport( "Kernel32.dll" )] + private static extern bool QueryPerformanceFrequency( + out long lpFrequency ); + + private long startTime; + private long stopTime; + private long freq; + private long freq_millis; + + // Constructor + + public TimerWin() + { + startTime = 0; + stopTime = 0; + + if( QueryPerformanceFrequency( out freq ) == false ) + { + // high-performance counter not supported + throw new Win32Exception(); + } + + freq_millis = freq / 1000; + + } + + // Start the timer + + public void Start() + { + // lets do the waiting threads there work + + //Thread.Sleep(0); + + QueryPerformanceCounter( out startTime ); + } + + // Stop the timer + + public void Stop() + { + QueryPerformanceCounter( out stopTime ); + } + + public double Seconds + { + get + { + long current; + + QueryPerformanceCounter( out current ); + + return (double)( current - startTime ) / freq; + } + } + + public long Current + { + get + { + long current; + + QueryPerformanceCounter( out current ); + + return ( current - startTime ) / freq_millis; + } + } + + public double Duration + { + get + { + return (double)( stopTime - startTime ) / (double)freq; + } + } + + public long DurationMS + { + get { return ( stopTime - startTime ) / freq_millis; } + } + } +}