Whitespace changes

This commit is contained in:
Marc Hernandez 2024-04-30 12:18:33 -07:00
parent f965662031
commit 8879e98229
40 changed files with 7975 additions and 7975 deletions

View File

@ -1,8 +1,8 @@
 
/* /*
* TODO: Need to verify types are correct when deserializing. * TODO: Need to verify types are correct when deserializing.
*/ */
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@ -22,10 +22,10 @@ namespace lib
{ {
FileStream fs = new FileStream( filename, FileMode.Create, FileAccess.Write ); FileStream fs = new FileStream( filename, FileMode.Create, FileAccess.Write );
XmlSerializer xs = new XmlSerializer( obj.GetType() ); XmlSerializer xs = new XmlSerializer( obj.GetType() );
//MemoryStream memoryStream = new MemoryStream( StringToUTF8ByteArray( pXmlizedString ) ); //MemoryStream memoryStream = new MemoryStream( StringToUTF8ByteArray( pXmlizedString ) );
//XmlTextReader reader = new XmlTextReader( fs, Encoding.UTF8 ); //XmlTextReader reader = new XmlTextReader( fs, Encoding.UTF8 );
xs.Serialize( fs, obj ); xs.Serialize( fs, obj );
} }
@ -33,10 +33,10 @@ namespace lib
{ {
FileStream fs = new FileStream( filename, FileMode.Open, FileAccess.Read ); FileStream fs = new FileStream( filename, FileMode.Open, FileAccess.Read );
XmlSerializer xs = new XmlSerializer( typeof( TType ) ); XmlSerializer xs = new XmlSerializer( typeof( TType ) );
//MemoryStream memoryStream = new MemoryStream( StringToUTF8ByteArray( pXmlizedString ) ); //MemoryStream memoryStream = new MemoryStream( StringToUTF8ByteArray( pXmlizedString ) );
//XmlTextReader reader = new XmlTextReader( fs, Encoding.UTF8 ); //XmlTextReader reader = new XmlTextReader( fs, Encoding.UTF8 );
return xs.Deserialize( fs ); return xs.Deserialize( fs );
} }
@ -72,10 +72,10 @@ namespace lib
{ {
XmlTextWriter xmlWriter = new XmlTextWriter( filename, null ); XmlTextWriter xmlWriter = new XmlTextWriter( filename, null );
xmlWriter.Formatting = Formatting.Indented; xmlWriter.Formatting = Formatting.Indented;
//xmlWriter.WriteStartDocument(); //xmlWriter.WriteStartDocument();
xmlWriter.WriteStartElement( "dictionary" ); xmlWriter.WriteStartElement( "dictionary" );
Type[] types = dict.GetType().GetGenericArguments(); Type[] types = dict.GetType().GetGenericArguments();
@ -93,10 +93,10 @@ namespace lib
xmlWriter.WriteEndElement(); xmlWriter.WriteEndElement();
} }
xmlWriter.WriteEndElement(); xmlWriter.WriteEndElement();
//xmlWriter.WriteEndDocument(); //xmlWriter.WriteEndDocument();
xmlWriter.Close(); xmlWriter.Close();
} }
@ -106,10 +106,10 @@ namespace lib
XmlDocument doc = new XmlDocument(); XmlDocument doc = new XmlDocument();
doc.Load( fs ); doc.Load( fs );
//CreateTypeFor() //CreateTypeFor()
XmlElement docElem = doc.DocumentElement; XmlElement docElem = doc.DocumentElement;
if( docElem.Name == "dictionary" ) if( docElem.Name == "dictionary" )
@ -125,10 +125,10 @@ namespace lib
{ {
XmlNodeList nodeList = docElem.ChildNodes; XmlNodeList nodeList = docElem.ChildNodes;
object[] args = new object[ 1 ]; object[] args = new object[ 1 ];
//fi.SetValue( newObj, obj ); //fi.SetValue( newObj, obj );
foreach( XmlElement node in nodeList ) foreach( XmlElement node in nodeList )
{ {
if( node.Name == "kvp" ) if( node.Name == "kvp" )

1232
Id.cs

File diff suppressed because it is too large Load Diff

108
Token.cs
View File

@ -1,54 +1,54 @@
using System; using System;
using System.Diagnostics; using System.Diagnostics;
namespace lib namespace lib
{ {
//TODO PERF fix this and make it fast. //TODO PERF fix this and make it fast.
[Serializable] [Serializable]
public struct Token public struct Token
{ {
public string str { get { return m_str; } } public string str { get { return m_str; } }
public Token( String str ) public Token( String str )
{ {
m_str = str; m_str = str;
m_hash = m_str.GetHashCode(); m_hash = m_str.GetHashCode();
} }
public override bool Equals( object obj ) public override bool Equals( object obj )
{ {
if( !( obj is Token ) ) if( !( obj is Token ) )
return false; return false;
//This doesnt use as because Token is a struct //This doesnt use as because Token is a struct
var otherId = (Token)obj; var otherId = (Token)obj;
if( m_hash != otherId.m_hash ) if( m_hash != otherId.m_hash )
return false; return false;
return m_str == otherId.m_str; return m_str == otherId.m_str;
} }
public bool Equals_fast( Token other ) public bool Equals_fast( Token other )
{ {
return m_hash == other.m_hash && m_str == other.m_str; return m_hash == other.m_hash && m_str == other.m_str;
} }
public override int GetHashCode() public override int GetHashCode()
{ {
return m_hash; return m_hash;
} }
public override string ToString() public override string ToString()
{ {
return m_str; return m_str;
} }
int m_hash; int m_hash;
String m_str; String m_str;
} }
} }

View File

@ -1,32 +1,32 @@
// Copyright (c) Xenko contributors (https://xenko.com) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) // 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. // Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
// //
// Copyright (c) 2010-2012 SharpDX - Alexandre Mutel // Copyright (c) 2010-2012 SharpDX - Alexandre Mutel
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights // in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is // copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions: // furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software. // all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // 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 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. // THE SOFTWARE.
#pragma warning disable SA1300 // Element must begin with upper-case letter #pragma warning disable SA1300 // Element must begin with upper-case letter
#pragma warning disable SA1649 // File name must match first type name #pragma warning disable SA1649 // File name must match first type name
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace lib namespace lib
{ {
/// <summary> /// <summary>
/// Utility class. /// Utility class.
/// </summary> /// </summary>

File diff suppressed because it is too large Load Diff

View File

@ -1,73 +1,73 @@
using System; using System;
using System.IO; using System.IO;
/* /*
* Reference arithmetic coding * Reference arithmetic coding
* Copyright (c) Project Nayuki * Copyright (c) Project Nayuki
* *
* https://www.nayuki.io/page/reference-arithmetic-coding * https://www.nayuki.io/page/reference-arithmetic-coding
* https://github.com/nayuki/Reference-arithmetic-coding * https://github.com/nayuki/Reference-arithmetic-coding
*/ */
/// <summary> /// <summary>
/// Compression application using adaptive arithmetic coding. /// Compression application using adaptive arithmetic coding.
/// <para>Usage: java AdaptiveArithmeticCompress InputFile OutputFile</para> /// <para>Usage: java AdaptiveArithmeticCompress InputFile OutputFile</para>
/// <para>Then use the corresponding "AdaptiveArithmeticDecompress" application to recreate the original input file.</para> /// <para>Then use the corresponding "AdaptiveArithmeticDecompress" application to recreate the original input file.</para>
/// <para>Note that the application starts with a flat frequency table of 257 symbols (all set to a frequency of 1), /// <para>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 /// 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 /// 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.</para> /// decompressor have synchronized states, so that the data can be decompressed properly.</para>
/// </summary> /// </summary>
public class AdaptiveArithmeticCompress public class AdaptiveArithmeticCompress
{ {
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: //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 //ORIGINAL LINE: public static void main(String[] args) throws java.io.IOException
public static void Main(string[] args) public static void Main(string[] args)
{ {
/* @@@@ PORT /* @@@@ PORT
// Handle command line arguments // Handle command line arguments
if (args.Length != 2) if (args.Length != 2)
{ {
Console.Error.WriteLine("Usage: java AdaptiveArithmeticCompress InputFile OutputFile"); Console.Error.WriteLine("Usage: java AdaptiveArithmeticCompress InputFile OutputFile");
Environment.Exit(1); Environment.Exit(1);
return; return;
} }
File inputFile = new File(args[0]); File inputFile = new File(args[0]);
File outputFile = new File(args[1]); File outputFile = new File(args[1]);
// Perform file compression // 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)))) 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); compress(@in, @out);
} }
*/ */
} }
// To allow unit testing, this method is package-private instead of private. // 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#: //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 //ORIGINAL LINE: static void compress(java.io.InputStream in, BitOutputStream out) throws java.io.IOException
internal static void compress(Stream @in, BitOutputStream @out) internal static void compress(Stream @in, BitOutputStream @out)
{ {
FlatFrequencyTable initFreqs = new FlatFrequencyTable(257); FlatFrequencyTable initFreqs = new FlatFrequencyTable(257);
FrequencyTable freqs = new SimpleFrequencyTable(initFreqs); FrequencyTable freqs = new SimpleFrequencyTable(initFreqs);
ArithmeticEncoder enc = new ArithmeticEncoder(32, @out); ArithmeticEncoder enc = new ArithmeticEncoder(32, @out);
while (true) while (true)
{ {
// Read and encode one byte // Read and encode one byte
int symbol = @in.ReadByte(); int symbol = @in.ReadByte();
if (symbol == -1) if (symbol == -1)
{ {
break; break;
} }
enc.write(freqs, symbol); enc.write(freqs, symbol);
freqs.increment(symbol); freqs.increment(symbol);
} }
enc.write(freqs, 256); // EOF enc.write(freqs, 256); // EOF
enc.finish(); // Flush remaining code bits enc.finish(); // Flush remaining code bits
} }
} }

View File

@ -1,67 +1,67 @@
using System; using System;
using System.IO; using System.IO;
/* /*
* Reference arithmetic coding * Reference arithmetic coding
* Copyright (c) Project Nayuki * Copyright (c) Project Nayuki
* *
* https://www.nayuki.io/page/reference-arithmetic-coding * https://www.nayuki.io/page/reference-arithmetic-coding
* https://github.com/nayuki/Reference-arithmetic-coding * https://github.com/nayuki/Reference-arithmetic-coding
*/ */
/// <summary> /// <summary>
/// Decompression application using adaptive arithmetic coding. /// Decompression application using adaptive arithmetic coding.
/// <para>Usage: java AdaptiveArithmeticDecompress InputFile OutputFile</para> /// <para>Usage: java AdaptiveArithmeticDecompress InputFile OutputFile</para>
/// <para>This decompresses files generated by the "AdaptiveArithmeticCompress" application.</para> /// <para>This decompresses files generated by the "AdaptiveArithmeticCompress" application.</para>
/// </summary> /// </summary>
public class AdaptiveArithmeticDecompress public class AdaptiveArithmeticDecompress
{ {
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: //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 //ORIGINAL LINE: public static void main(String[] args) throws java.io.IOException
public static void Main(string[] args) public static void Main(string[] args)
{ {
/* @@@@ PORT /* @@@@ PORT
// Handle command line arguments // Handle command line arguments
if (args.Length != 2) if (args.Length != 2)
{ {
Console.Error.WriteLine("Usage: java AdaptiveArithmeticDecompress InputFile OutputFile"); Console.Error.WriteLine("Usage: java AdaptiveArithmeticDecompress InputFile OutputFile");
Environment.Exit(1); Environment.Exit(1);
return; return;
} }
File inputFile = new File(args[0]); File inputFile = new File(args[0]);
File outputFile = new File(args[1]); File outputFile = new File(args[1]);
// Perform file decompression // 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))) 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); decompress(@in, @out);
} }
*/ */
} }
// To allow unit testing, this method is package-private instead of private. // 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#: //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 //ORIGINAL LINE: static void decompress(BitInputStream in, java.io.OutputStream out) throws java.io.IOException
internal static void decompress(BitInputStream @in, Stream @out) internal static void decompress(BitInputStream @in, Stream @out)
{ {
FlatFrequencyTable initFreqs = new FlatFrequencyTable(257); FlatFrequencyTable initFreqs = new FlatFrequencyTable(257);
FrequencyTable freqs = new SimpleFrequencyTable(initFreqs); FrequencyTable freqs = new SimpleFrequencyTable(initFreqs);
ArithmeticDecoder dec = new ArithmeticDecoder(32, @in); ArithmeticDecoder dec = new ArithmeticDecoder(32, @in);
while (true) while (true)
{ {
// Decode and write one byte // Decode and write one byte
int symbol = dec.read(freqs); int symbol = dec.read(freqs);
if (symbol == 256) // EOF symbol if (symbol == 256) // EOF symbol
{ {
break; break;
} }
@out.WriteByte((byte)symbol); @out.WriteByte((byte)symbol);
freqs.increment(symbol); freqs.increment(symbol);
} }
} }
} }

View File

@ -1,185 +1,185 @@
using System; using System;
using System.Diagnostics; using System.Diagnostics;
/* /*
* Reference arithmetic coding * Reference arithmetic coding
* Copyright (c) Project Nayuki * Copyright (c) Project Nayuki
* *
* https://www.nayuki.io/page/reference-arithmetic-coding * https://www.nayuki.io/page/reference-arithmetic-coding
* https://github.com/nayuki/Reference-arithmetic-coding * https://github.com/nayuki/Reference-arithmetic-coding
*/ */
/// <summary> /// <summary>
/// Provides the state and behaviors that arithmetic coding encoders and decoders share. </summary> /// Provides the state and behaviors that arithmetic coding encoders and decoders share. </summary>
/// <seealso cref= ArithmeticEncoder </seealso> /// <seealso cref= ArithmeticEncoder </seealso>
/// <seealso cref= ArithmeticDecoder </seealso> /// <seealso cref= ArithmeticDecoder </seealso>
public abstract class ArithmeticCoderBase public abstract class ArithmeticCoderBase
{ {
/*---- Configuration fields ----*/ /*---- Configuration fields ----*/
/// <summary> /// <summary>
/// Number of bits for the 'low' and 'high' state variables. Must be in the range [1, 62]. /// Number of bits for the 'low' and 'high' state variables. Must be in the range [1, 62].
/// <ul> /// <ul>
/// <li>For state sizes less than the midpoint of around 32, larger values are generally better - /// <li>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 /// 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 /// 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.</li> /// and asymptotically approach the efficiency of arithmetic coding using exact fractions.</li>
/// <li>But for state sizes greater than the midpoint, because intermediate computations are limited /// <li>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 /// 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.</li> /// maximum frequency total, which might constrain the user-supplied probability model.</li>
/// <li>Therefore numStateBits=32 is recommended as the most versatile setting /// <li>Therefore numStateBits=32 is recommended as the most versatile setting
/// because it maximizes maximumTotal (which ends up being slightly over 2^30).</li> /// because it maximizes maximumTotal (which ends up being slightly over 2^30).</li>
/// <li>Note that numStateBits=62 is legal but useless because it implies maximumTotal=1, /// <li>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.</li> /// which means a frequency table can only support one symbol with non-zero frequency.</li>
/// </ul> /// </ul>
/// </summary> /// </summary>
protected internal readonly int numStateBits; protected internal readonly int numStateBits;
/// <summary> /// <summary>
/// Maximum range (high+1-low) during coding (trivial), which is 2^numStateBits = 1000...000. </summary> /// Maximum range (high+1-low) during coding (trivial), which is 2^numStateBits = 1000...000. </summary>
protected internal readonly long fullRange; protected internal readonly long fullRange;
/// <summary> /// <summary>
/// The top bit at width numStateBits, which is 0100...000. </summary> /// The top bit at width numStateBits, which is 0100...000. </summary>
protected internal readonly long halfRange; protected internal readonly long halfRange;
/// <summary> /// <summary>
/// The second highest bit at width numStateBits, which is 0010...000. This is zero when numStateBits=1. </summary> /// The second highest bit at width numStateBits, which is 0010...000. This is zero when numStateBits=1. </summary>
protected internal readonly long quarterRange; protected internal readonly long quarterRange;
/// <summary> /// <summary>
/// Minimum range (high+1-low) during coding (non-trivial), which is 0010...010. </summary> /// Minimum range (high+1-low) during coding (non-trivial), which is 0010...010. </summary>
protected internal readonly long minimumRange; protected internal readonly long minimumRange;
/// <summary> /// <summary>
/// Maximum allowed total from a frequency table at all times during coding. </summary> /// Maximum allowed total from a frequency table at all times during coding. </summary>
protected internal readonly long maximumTotal; protected internal readonly long maximumTotal;
/// <summary> /// <summary>
/// Bit mask of numStateBits ones, which is 0111...111. </summary> /// Bit mask of numStateBits ones, which is 0111...111. </summary>
protected internal readonly long stateMask; protected internal readonly long stateMask;
/*---- State fields ----*/ /*---- State fields ----*/
/// <summary> /// <summary>
/// Low end of this arithmetic coder's current range. Conceptually has an infinite number of trailing 0s. /// Low end of this arithmetic coder's current range. Conceptually has an infinite number of trailing 0s.
/// </summary> /// </summary>
protected internal long low; protected internal long low;
/// <summary> /// <summary>
/// High end of this arithmetic coder's current range. Conceptually has an infinite number of trailing 1s. /// High end of this arithmetic coder's current range. Conceptually has an infinite number of trailing 1s.
/// </summary> /// </summary>
protected internal long high; protected internal long high;
/*---- Constructor ----*/ /*---- Constructor ----*/
/// <summary> /// <summary>
/// Constructs an arithmetic coder, which initializes the code range. </summary> /// Constructs an arithmetic coder, which initializes the code range. </summary>
/// <param name="numBits"> the number of bits for the arithmetic coding range </param> /// <param name="numBits"> the number of bits for the arithmetic coding range </param>
/// <exception cref="IllegalArgumentException"> if stateSize is outside the range [1, 62] </exception> /// <exception cref="IllegalArgumentException"> if stateSize is outside the range [1, 62] </exception>
public ArithmeticCoderBase(int numBits) public ArithmeticCoderBase(int numBits)
{ {
if (numBits < 1 || numBits > 62) if (numBits < 1 || numBits > 62)
{ {
throw new System.ArgumentException("State size out of range"); throw new System.ArgumentException("State size out of range");
} }
numStateBits = numBits; numStateBits = numBits;
fullRange = 1L << numStateBits; fullRange = 1L << numStateBits;
halfRange = (long)((ulong)fullRange >> 1); // Non-zero halfRange = (long)((ulong)fullRange >> 1); // Non-zero
quarterRange = (long)((ulong)halfRange >> 1); // Can be zero quarterRange = (long)((ulong)halfRange >> 1); // Can be zero
minimumRange = quarterRange + 2; // At least 2 minimumRange = quarterRange + 2; // At least 2
maximumTotal = Math.Min(long.MaxValue / fullRange, minimumRange); maximumTotal = Math.Min(long.MaxValue / fullRange, minimumRange);
stateMask = fullRange - 1; stateMask = fullRange - 1;
low = 0; low = 0;
high = stateMask; high = stateMask;
} }
/*---- Methods ----*/ /*---- Methods ----*/
/// <summary> /// <summary>
/// Updates the code range (low and high) of this arithmetic coder as a result /// Updates the code range (low and high) of this arithmetic coder as a result
/// of processing the specified symbol with the specified frequency table. /// of processing the specified symbol with the specified frequency table.
/// <para>Invariants that are true before and after encoding/decoding each symbol /// <para>Invariants that are true before and after encoding/decoding each symbol
/// (letting fullRange = 2<sup>numStateBits</sup>):</para> /// (letting fullRange = 2<sup>numStateBits</sup>):</para>
/// <ul> /// <ul>
/// <li>0 &le; low &le; code &le; high &lt; fullRange. ('code' exists only in the decoder.) /// <li>0 &le; low &le; code &le; high &lt; fullRange. ('code' exists only in the decoder.)
/// Therefore these variables are unsigned integers of numStateBits bits.</li> /// Therefore these variables are unsigned integers of numStateBits bits.</li>
/// <li>low &lt; 1/2 &times; fullRange &le; high. /// <li>low &lt; 1/2 &times; fullRange &le; high.
/// In other words, they are in different halves of the full range.</li> /// In other words, they are in different halves of the full range.</li>
/// <li>(low &lt; 1/4 &times; fullRange) || (high &ge; 3/4 &times; fullRange). /// <li>(low &lt; 1/4 &times; fullRange) || (high &ge; 3/4 &times; fullRange).
/// In other words, they are not both in the middle two quarters.</li> /// In other words, they are not both in the middle two quarters.</li>
/// <li>Let range = high &minus; low + 1, then fullRange/4 &lt; minimumRange &le; range &le; /// <li>Let range = high &minus; low + 1, then fullRange/4 &lt; minimumRange &le; range &le;
/// fullRange. These invariants for 'range' essentially dictate the maximum total that the /// fullRange. These invariants for 'range' essentially dictate the maximum total that the
/// incoming frequency table can have, such that intermediate calculations don't overflow.</li> /// incoming frequency table can have, such that intermediate calculations don't overflow.</li>
/// </ul> </summary> /// </ul> </summary>
/// <param name="freqs"> the frequency table to use </param> /// <param name="freqs"> the frequency table to use </param>
/// <param name="symbol"> the symbol that was processed </param> /// <param name="symbol"> the symbol that was processed </param>
/// <exception cref="IllegalArgumentException"> if the symbol has zero frequency or the frequency table's total is too large </exception> /// <exception cref="IllegalArgumentException"> if the symbol has zero frequency or the frequency table's total is too large </exception>
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: //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 //ORIGINAL LINE: protected void update(CheckedFrequencyTable freqs, int symbol) throws java.io.IOException
protected internal virtual void update(CheckedFrequencyTable freqs, int symbol) protected internal virtual void update(CheckedFrequencyTable freqs, int symbol)
{ {
// State check // State check
Debug.Assert(low >= high || (low & stateMask) != low || (high & stateMask) != high, "Low or high out of range"); Debug.Assert(low >= high || (low & stateMask) != low || (high & stateMask) != high, "Low or high out of range");
long range = high - low + 1; long range = high - low + 1;
Debug.Assert(range < minimumRange || range > fullRange, "Range out of range"); Debug.Assert(range < minimumRange || range > fullRange, "Range out of range");
// Frequency table values check // Frequency table values check
long total = freqs.Total; long total = freqs.Total;
long symLow = freqs.getLow(symbol); long symLow = freqs.getLow(symbol);
long symHigh = freqs.getHigh(symbol); long symHigh = freqs.getHigh(symbol);
Debug.Assert( symLow == symHigh, "Symbol has zero frequency"); Debug.Assert( symLow == symHigh, "Symbol has zero frequency");
Debug.Assert( total > maximumTotal, "Cannot code symbol because total is too large"); Debug.Assert( total > maximumTotal, "Cannot code symbol because total is too large");
// Update range // Update range
long newLow = low + symLow * range / total; long newLow = low + symLow * range / total;
long newHigh = low + symHigh * range / total - 1; long newHigh = low + symHigh * range / total - 1;
low = newLow; low = newLow;
high = newHigh; high = newHigh;
// While low and high have the same top bit value, shift them out // While low and high have the same top bit value, shift them out
while (((low ^ high) & halfRange) == 0) while (((low ^ high) & halfRange) == 0)
{ {
shift(); shift();
low = ((low << 1) & stateMask); low = ((low << 1) & stateMask);
high = ((high << 1) & stateMask) | 1; high = ((high << 1) & stateMask) | 1;
} }
// Now low's top bit must be 0 and high's top bit must be 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's top two bits are 01 and high's are 10, delete the second highest bit of both
while ((low & ~high & quarterRange) != 0) while ((low & ~high & quarterRange) != 0)
{ {
underflow(); underflow();
low = (low << 1) ^ halfRange; low = (low << 1) ^ halfRange;
high = ((high ^ halfRange) << 1) | halfRange | 1; high = ((high ^ halfRange) << 1) | halfRange | 1;
} }
} }
/// <summary> /// <summary>
/// Called to handle the situation when the top bit of {@code low} and {@code high} are equal. </summary> /// Called to handle the situation when the top bit of {@code low} and {@code high} are equal. </summary>
/// <exception cref="IOException"> if an I/O exception occurred </exception> /// <exception cref="IOException"> if an I/O exception occurred </exception>
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
//ORIGINAL LINE: protected abstract void shift() throws java.io.IOException; //ORIGINAL LINE: protected abstract void shift() throws java.io.IOException;
protected internal abstract void shift(); protected internal abstract void shift();
/// <summary> /// <summary>
/// Called to handle the situation when low=01(...) and high=10(...). </summary> /// Called to handle the situation when low=01(...) and high=10(...). </summary>
/// <exception cref="IOException"> if an I/O exception occurred </exception> /// <exception cref="IOException"> if an I/O exception occurred </exception>
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
//ORIGINAL LINE: protected abstract void underflow() throws java.io.IOException; //ORIGINAL LINE: protected abstract void underflow() throws java.io.IOException;
protected internal abstract void underflow(); protected internal abstract void underflow();
} }

View File

@ -1,127 +1,127 @@
using System; using System;
using System.IO; using System.IO;
/* /*
* Reference arithmetic coding * Reference arithmetic coding
* Copyright (c) Project Nayuki * Copyright (c) Project Nayuki
* *
* https://www.nayuki.io/page/reference-arithmetic-coding * https://www.nayuki.io/page/reference-arithmetic-coding
* https://github.com/nayuki/Reference-arithmetic-coding * https://github.com/nayuki/Reference-arithmetic-coding
*/ */
/// <summary> /// <summary>
/// Compression application using static arithmetic coding. /// Compression application using static arithmetic coding.
/// <para>Usage: java ArithmeticCompress InputFile OutputFile</para> /// <para>Usage: java ArithmeticCompress InputFile OutputFile</para>
/// <para>Then use the corresponding "ArithmeticDecompress" application to recreate the original input file.</para> /// <para>Then use the corresponding "ArithmeticDecompress" application to recreate the original input file.</para>
/// <para>Note that the application uses an alphabet of 257 symbols - 256 symbols for the byte /// <para>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 /// 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.</para> /// of 256 symbol frequencies, and then followed by the arithmetic-coded data.</para>
/// </summary> /// </summary>
public class ArithmeticCompress public class ArithmeticCompress
{ {
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: //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 //ORIGINAL LINE: public static void main(String[] args) throws java.io.IOException
public static void Main(string[] args) public static void Main(string[] args)
{ {
/* @@ PORT /* @@ PORT
// Handle command line arguments // Handle command line arguments
if (args.Length != 2) if (args.Length != 2)
{ {
Console.Error.WriteLine("Usage: java ArithmeticCompress InputFile OutputFile"); Console.Error.WriteLine("Usage: java ArithmeticCompress InputFile OutputFile");
Environment.Exit(1); Environment.Exit(1);
return; return;
} }
File inputFile = new File(args[0]); File inputFile = new File(args[0]);
File outputFile = new File(args[1]); File outputFile = new File(args[1]);
// Read input file once to compute symbol frequencies // Read input file once to compute symbol frequencies
FrequencyTable freqs = getFrequencies(inputFile); FrequencyTable freqs = getFrequencies(inputFile);
freqs.increment(256); // EOF symbol gets a frequency of 1 freqs.increment(256); // EOF symbol gets a frequency of 1
// Read input file again, compress with arithmetic coding, and write output file // 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)))) 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); writeFrequencies(@out, freqs);
compress(freqs, @in, @out); compress(freqs, @in, @out);
} }
*/ */
} }
// Returns a frequency table based on the bytes in the given file. // 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. // 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#: //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 //ORIGINAL LINE: private static FrequencyTable getFrequencies(java.io.File file) throws java.io.IOException
private static FrequencyTable getFrequencies(string file) private static FrequencyTable getFrequencies(string file)
{ {
FrequencyTable freqs = new SimpleFrequencyTable(new int[257]); FrequencyTable freqs = new SimpleFrequencyTable(new int[257]);
using (Stream input = new BufferedStream( new FileStream(file, FileMode.Open, FileAccess.Read))) using (Stream input = new BufferedStream( new FileStream(file, FileMode.Open, FileAccess.Read)))
{ {
while (true) while (true)
{ {
int b = input.ReadByte(); int b = input.ReadByte();
if (b == -1) if (b == -1)
{ {
break; break;
} }
freqs.increment(b); freqs.increment(b);
} }
} }
return freqs; return freqs;
} }
// To allow unit testing, this method is package-private instead of private. // 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#: //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 //ORIGINAL LINE: static void writeFrequencies(BitOutputStream out, FrequencyTable freqs) throws java.io.IOException
internal static void writeFrequencies(BitOutputStream @out, FrequencyTable freqs) internal static void writeFrequencies(BitOutputStream @out, FrequencyTable freqs)
{ {
for (int i = 0; i < 256; i++) for (int i = 0; i < 256; i++)
{ {
writeInt(@out, 32, freqs.get(i)); writeInt(@out, 32, freqs.get(i));
} }
} }
// To allow unit testing, this method is package-private instead of private. // 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#: //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 //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) internal static void compress(FrequencyTable freqs, Stream @in, BitOutputStream @out)
{ {
ArithmeticEncoder enc = new ArithmeticEncoder(32, @out); ArithmeticEncoder enc = new ArithmeticEncoder(32, @out);
while (true) while (true)
{ {
int symbol = @in.ReadByte(); int symbol = @in.ReadByte();
if (symbol == -1) if (symbol == -1)
{ {
break; break;
} }
enc.write(freqs, symbol); enc.write(freqs, symbol);
} }
enc.write(freqs, 256); // EOF enc.write(freqs, 256); // EOF
enc.finish(); // Flush remaining code bits enc.finish(); // Flush remaining code bits
} }
// Writes an unsigned integer of the given bit width to the given stream. // 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#: //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 //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) private static void writeInt(BitOutputStream @out, int numBits, int value)
{ {
if (numBits < 0 || numBits > 32) if (numBits < 0 || numBits > 32)
{ {
throw new System.ArgumentException(); throw new System.ArgumentException();
} }
for (int i = numBits - 1; i >= 0; i--) for (int i = numBits - 1; i >= 0; i--)
{ {
@out.write(((int)((uint)value >> i)) & 1); // Big endian @out.write(((int)((uint)value >> i)) & 1); // Big endian
} }
} }
} }

View File

@ -1,152 +1,152 @@
/* /*
* Reference arithmetic coding * Reference arithmetic coding
* Copyright (c) Project Nayuki * Copyright (c) Project Nayuki
* *
* https://www.nayuki.io/page/reference-arithmetic-coding * https://www.nayuki.io/page/reference-arithmetic-coding
* https://github.com/nayuki/Reference-arithmetic-coding * https://github.com/nayuki/Reference-arithmetic-coding
*/ */
using System.Diagnostics; using System.Diagnostics;
/// <summary> /// <summary>
/// Reads from an arithmetic-coded bit stream and decodes symbols. Not thread-safe. </summary> /// Reads from an arithmetic-coded bit stream and decodes symbols. Not thread-safe. </summary>
/// <seealso cref= ArithmeticEncoder </seealso> /// <seealso cref= ArithmeticEncoder </seealso>
public sealed class ArithmeticDecoder : ArithmeticCoderBase public sealed class ArithmeticDecoder : ArithmeticCoderBase
{ {
/*---- Fields ----*/ /*---- Fields ----*/
// The underlying bit input stream (not null). // The underlying bit input stream (not null).
private BitInputStream input; private BitInputStream input;
// The current raw code bits being buffered, which is always in the range [low, high]. // The current raw code bits being buffered, which is always in the range [low, high].
private long code; private long code;
/*---- Constructor ----*/ /*---- Constructor ----*/
/// <summary> /// <summary>
/// Constructs an arithmetic coding decoder based on the /// Constructs an arithmetic coding decoder based on the
/// specified bit input stream, and fills the code bits. </summary> /// specified bit input stream, and fills the code bits. </summary>
/// <param name="numBits"> the number of bits for the arithmetic coding range </param> /// <param name="numBits"> the number of bits for the arithmetic coding range </param>
/// <param name="in"> the bit input stream to read from </param> /// <param name="in"> the bit input stream to read from </param>
/// <exception cref="NullPointerException"> if the input steam is {@code null} </exception> /// <exception cref="NullPointerException"> if the input steam is {@code null} </exception>
/// <exception cref="IllegalArgumentException"> if stateSize is outside the range [1, 62] </exception> /// <exception cref="IllegalArgumentException"> if stateSize is outside the range [1, 62] </exception>
/// <exception cref="IOException"> if an I/O exception occurred </exception> /// <exception cref="IOException"> if an I/O exception occurred </exception>
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: //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 //ORIGINAL LINE: public ArithmeticDecoder(int numBits, BitInputStream in) throws java.io.IOException
public ArithmeticDecoder(int numBits, BitInputStream @in) : base(numBits) public ArithmeticDecoder(int numBits, BitInputStream @in) : base(numBits)
{ {
input = @in; //Objects.requireNonNull(@in); input = @in; //Objects.requireNonNull(@in);
code = 0; code = 0;
for (int i = 0; i < numStateBits; i++) for (int i = 0; i < numStateBits; i++)
{ {
code = code << 1 | readCodeBit(); code = code << 1 | readCodeBit();
} }
} }
/*---- Methods ----*/ /*---- Methods ----*/
/// <summary> /// <summary>
/// Decodes the next symbol based on the specified frequency table and returns it. /// 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. </summary> /// Also updates this arithmetic coder's state and may read in some bits. </summary>
/// <param name="freqs"> the frequency table to use </param> /// <param name="freqs"> the frequency table to use </param>
/// <returns> the next symbol </returns> /// <returns> the next symbol </returns>
/// <exception cref="NullPointerException"> if the frequency table is {@code null} </exception> /// <exception cref="NullPointerException"> if the frequency table is {@code null} </exception>
/// <exception cref="IOException"> if an I/O exception occurred </exception> /// <exception cref="IOException"> if an I/O exception occurred </exception>
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
//ORIGINAL LINE: public int read(FrequencyTable freqs) throws java.io.IOException //ORIGINAL LINE: public int read(FrequencyTable freqs) throws java.io.IOException
public int read(FrequencyTable freqs) public int read(FrequencyTable freqs)
{ {
return read(new CheckedFrequencyTable(freqs)); return read(new CheckedFrequencyTable(freqs));
} }
/// <summary> /// <summary>
/// Decodes the next symbol based on the specified frequency table and returns it. /// 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. </summary> /// Also updates this arithmetic coder's state and may read in some bits. </summary>
/// <param name="freqs"> the frequency table to use </param> /// <param name="freqs"> the frequency table to use </param>
/// <returns> the next symbol </returns> /// <returns> the next symbol </returns>
/// <exception cref="NullPointerException"> if the frequency table is {@code null} </exception> /// <exception cref="NullPointerException"> if the frequency table is {@code null} </exception>
/// <exception cref="IllegalArgumentException"> if the frequency table's total is too large </exception> /// <exception cref="IllegalArgumentException"> if the frequency table's total is too large </exception>
/// <exception cref="IOException"> if an I/O exception occurred </exception> /// <exception cref="IOException"> if an I/O exception occurred </exception>
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
//ORIGINAL LINE: public int read(CheckedFrequencyTable freqs) throws java.io.IOException //ORIGINAL LINE: public int read(CheckedFrequencyTable freqs) throws java.io.IOException
public int read(CheckedFrequencyTable freqs) public int read(CheckedFrequencyTable freqs)
{ {
// Translate from coding range scale to frequency table scale // Translate from coding range scale to frequency table scale
long total = freqs.Total; long total = freqs.Total;
if (total > maximumTotal) if (total > maximumTotal)
{ {
throw new System.ArgumentException("Cannot decode symbol because total is too large"); throw new System.ArgumentException("Cannot decode symbol because total is too large");
} }
long range = high - low + 1; long range = high - low + 1;
long offset = code - low; long offset = code - low;
long value = ((offset + 1) * total - 1) / range; long value = ((offset + 1) * total - 1) / range;
Debug.Assert(value * range / total > offset); Debug.Assert(value * range / total > offset);
Debug.Assert(value < 0 || value >= total); Debug.Assert(value < 0 || value >= total);
// A kind of binary search. Find highest symbol such that freqs.getLow(symbol) <= value. // A kind of binary search. Find highest symbol such that freqs.getLow(symbol) <= value.
int start = 0; int start = 0;
int end = freqs.SymbolLimit; int end = freqs.SymbolLimit;
while (end - start > 1) while (end - start > 1)
{ {
int middle = (int)((uint)(start + end) >> 1); int middle = (int)((uint)(start + end) >> 1);
if (freqs.getLow(middle) > value) if (freqs.getLow(middle) > value)
{ {
end = middle; end = middle;
} }
else else
{ {
start = middle; start = middle;
} }
} }
Debug.Assert( start + 1 != end); Debug.Assert( start + 1 != end);
int symbol = start; int symbol = start;
Debug.Assert(offset < freqs.getLow(symbol) * range / total || freqs.getHigh(symbol) * range / total <= offset); Debug.Assert(offset < freqs.getLow(symbol) * range / total || freqs.getHigh(symbol) * range / total <= offset);
update(freqs, symbol); update(freqs, symbol);
Debug.Assert(code < low || code > high); Debug.Assert(code < low || code > high);
return symbol; return symbol;
} }
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
//ORIGINAL LINE: protected void shift() throws java.io.IOException //ORIGINAL LINE: protected void shift() throws java.io.IOException
protected internal override void shift() protected internal override void shift()
{ {
code = ((code << 1) & stateMask) | readCodeBit(); code = ((code << 1) & stateMask) | readCodeBit();
} }
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
//ORIGINAL LINE: protected void underflow() throws java.io.IOException //ORIGINAL LINE: protected void underflow() throws java.io.IOException
protected internal override void underflow() protected internal override void underflow()
{ {
code = (code & halfRange) | ((code << 1) & ((long)((ulong)stateMask >> 1))) | readCodeBit(); code = (code & halfRange) | ((code << 1) & ((long)((ulong)stateMask >> 1))) | readCodeBit();
} }
// Returns the next bit (0 or 1) from the input stream. The end // Returns the next bit (0 or 1) from the input stream. The end
// of stream is treated as an infinite number of trailing zeros. // of stream is treated as an infinite number of trailing zeros.
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
//ORIGINAL LINE: private int readCodeBit() throws java.io.IOException //ORIGINAL LINE: private int readCodeBit() throws java.io.IOException
private int readCodeBit() private int readCodeBit()
{ {
int temp = input.read(); int temp = input.read();
if (temp == -1) if (temp == -1)
{ {
temp = 0; temp = 0;
} }
return temp; return temp;
} }
} }

View File

@ -1,99 +1,99 @@
using System; using System;
using System.IO; using System.IO;
/* /*
* Reference arithmetic coding * Reference arithmetic coding
* Copyright (c) Project Nayuki * Copyright (c) Project Nayuki
* *
* https://www.nayuki.io/page/reference-arithmetic-coding * https://www.nayuki.io/page/reference-arithmetic-coding
* https://github.com/nayuki/Reference-arithmetic-coding * https://github.com/nayuki/Reference-arithmetic-coding
*/ */
/// <summary> /// <summary>
/// Decompression application using static arithmetic coding. /// Decompression application using static arithmetic coding.
/// <para>Usage: java ArithmeticDecompress InputFile OutputFile</para> /// <para>Usage: java ArithmeticDecompress InputFile OutputFile</para>
/// <para>This decompresses files generated by the "ArithmeticCompress" application.</para> /// <para>This decompresses files generated by the "ArithmeticCompress" application.</para>
/// </summary> /// </summary>
public class ArithmeticDecompress public class ArithmeticDecompress
{ {
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: //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 //ORIGINAL LINE: public static void main(String[] args) throws java.io.IOException
public static void Main(string[] args) public static void Main(string[] args)
{ {
// Handle command line arguments // Handle command line arguments
if (args.Length != 2) if (args.Length != 2)
{ {
Console.Error.WriteLine("Usage: java ArithmeticDecompress InputFile OutputFile"); Console.Error.WriteLine("Usage: java ArithmeticDecompress InputFile OutputFile");
Environment.Exit(1); Environment.Exit(1);
return; return;
} }
string inputFile = args[0]; // new File(args[0]); string inputFile = args[0]; // new File(args[0]);
string outputFile = args[1]; //new File(args[1]); string outputFile = args[1]; //new File(args[1]);
// Perform file decompression // Perform file decompression
using( BitInputStream @in = new BitInputStream(new BufferedStream(new FileStream(inputFile, FileMode.Open, FileAccess.Read)))) 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) ) ) using( Stream @out = new BufferedStream(new FileStream(outputFile, FileMode.Create, FileAccess.Write) ) )
{ {
FrequencyTable freqs = readFrequencies(@in); FrequencyTable freqs = readFrequencies(@in);
decompress( freqs, @in, @out ); decompress( freqs, @in, @out );
} }
} }
// To allow unit testing, this method is package-private instead of private. // 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#: //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
//ORIGINAL LINE: static FrequencyTable readFrequencies(BitInputStream in) throws java.io.IOException //ORIGINAL LINE: static FrequencyTable readFrequencies(BitInputStream in) throws java.io.IOException
internal static FrequencyTable readFrequencies(BitInputStream @in) internal static FrequencyTable readFrequencies(BitInputStream @in)
{ {
int[] freqs = new int[257]; int[] freqs = new int[257];
for (int i = 0; i < 256; i++) for (int i = 0; i < 256; i++)
{ {
freqs[i] = readInt(@in, 32); freqs[i] = readInt(@in, 32);
} }
freqs[256] = 1; // EOF symbol freqs[256] = 1; // EOF symbol
return new SimpleFrequencyTable(freqs); return new SimpleFrequencyTable(freqs);
} }
// To allow unit testing, this method is package-private instead of private. // 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#: //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 //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) internal static void decompress(FrequencyTable freqs, BitInputStream @in, Stream @out)
{ {
ArithmeticDecoder dec = new ArithmeticDecoder(32, @in); ArithmeticDecoder dec = new ArithmeticDecoder(32, @in);
while (true) while (true)
{ {
int symbol = dec.read(freqs); int symbol = dec.read(freqs);
if (symbol == 256) // EOF symbol if (symbol == 256) // EOF symbol
{ {
break; break;
} }
@out.WriteByte((byte)symbol); @out.WriteByte((byte)symbol);
} }
} }
// Reads an unsigned integer of the given bit width from the given stream. // 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#: //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 //ORIGINAL LINE: private static int readInt(BitInputStream in, int numBits) throws java.io.IOException
private static int readInt(BitInputStream @in, int numBits) private static int readInt(BitInputStream @in, int numBits)
{ {
if (numBits < 0 || numBits > 32) if (numBits < 0 || numBits > 32)
{ {
throw new System.ArgumentException(); throw new System.ArgumentException();
} }
int result = 0; int result = 0;
for (int i = 0; i < numBits; i++) for (int i = 0; i < numBits; i++)
{ {
result = (result << 1) | @in.readNoEof(); // Big endian result = (result << 1) | @in.readNoEof(); // Big endian
} }
return result; return result;
} }
} }

View File

@ -1,118 +1,118 @@
/* /*
* Reference arithmetic coding * Reference arithmetic coding
* Copyright (c) Project Nayuki * Copyright (c) Project Nayuki
* *
* https://www.nayuki.io/page/reference-arithmetic-coding * https://www.nayuki.io/page/reference-arithmetic-coding
* https://github.com/nayuki/Reference-arithmetic-coding * https://github.com/nayuki/Reference-arithmetic-coding
*/ */
using System; using System;
/// <summary> /// <summary>
/// Encodes symbols and writes to an arithmetic-coded bit stream. Not thread-safe. </summary> /// Encodes symbols and writes to an arithmetic-coded bit stream. Not thread-safe. </summary>
/// <seealso cref= ArithmeticDecoder </seealso> /// <seealso cref= ArithmeticDecoder </seealso>
public sealed class ArithmeticEncoder : ArithmeticCoderBase public sealed class ArithmeticEncoder : ArithmeticCoderBase
{ {
/*---- Fields ----*/ /*---- Fields ----*/
// The underlying bit output stream (not null). // The underlying bit output stream (not null).
private BitOutputStream output; private BitOutputStream output;
// Number of saved underflow bits. This value can grow without bound, // Number of saved underflow bits. This value can grow without bound,
// so a truly correct implementation would use a BigInteger. // so a truly correct implementation would use a BigInteger.
private int numUnderflow; private int numUnderflow;
/*---- Constructor ----*/ /*---- Constructor ----*/
/// <summary> /// <summary>
/// Constructs an arithmetic coding encoder based on the specified bit output stream. </summary> /// Constructs an arithmetic coding encoder based on the specified bit output stream. </summary>
/// <param name="numBits"> the number of bits for the arithmetic coding range </param> /// <param name="numBits"> the number of bits for the arithmetic coding range </param>
/// <param name="out"> the bit output stream to write to </param> /// <param name="out"> the bit output stream to write to </param>
/// <exception cref="NullPointerException"> if the output stream is {@code null} </exception> /// <exception cref="NullPointerException"> if the output stream is {@code null} </exception>
/// <exception cref="IllegalArgumentException"> if stateSize is outside the range [1, 62] </exception> /// <exception cref="IllegalArgumentException"> if stateSize is outside the range [1, 62] </exception>
public ArithmeticEncoder(int numBits, BitOutputStream @out) : base(numBits) public ArithmeticEncoder(int numBits, BitOutputStream @out) : base(numBits)
{ {
output = @out; //Objects.requireNonNull(@out); output = @out; //Objects.requireNonNull(@out);
numUnderflow = 0; numUnderflow = 0;
} }
/*---- Methods ----*/ /*---- Methods ----*/
/// <summary> /// <summary>
/// Encodes the specified symbol based on the specified frequency table. /// Encodes the specified symbol based on the specified frequency table.
/// This updates this arithmetic coder's state and may write out some bits. </summary> /// This updates this arithmetic coder's state and may write out some bits. </summary>
/// <param name="freqs"> the frequency table to use </param> /// <param name="freqs"> the frequency table to use </param>
/// <param name="symbol"> the symbol to encode </param> /// <param name="symbol"> the symbol to encode </param>
/// <exception cref="NullPointerException"> if the frequency table is {@code null} </exception> /// <exception cref="NullPointerException"> if the frequency table is {@code null} </exception>
/// <exception cref="IllegalArgumentException"> if the symbol has zero frequency /// <exception cref="IllegalArgumentException"> if the symbol has zero frequency
/// or the frequency table's total is too large </exception> /// or the frequency table's total is too large </exception>
/// <exception cref="IOException"> if an I/O exception occurred </exception> /// <exception cref="IOException"> if an I/O exception occurred </exception>
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: //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 //ORIGINAL LINE: public void write(FrequencyTable freqs, int symbol) throws java.io.IOException
public void write(FrequencyTable freqs, int symbol) public void write(FrequencyTable freqs, int symbol)
{ {
write(new CheckedFrequencyTable(freqs), symbol); write(new CheckedFrequencyTable(freqs), symbol);
} }
/// <summary> /// <summary>
/// Encodes the specified symbol based on the specified frequency table. /// Encodes the specified symbol based on the specified frequency table.
/// Also updates this arithmetic coder's state and may write out some bits. </summary> /// Also updates this arithmetic coder's state and may write out some bits. </summary>
/// <param name="freqs"> the frequency table to use </param> /// <param name="freqs"> the frequency table to use </param>
/// <param name="symbol"> the symbol to encode </param> /// <param name="symbol"> the symbol to encode </param>
/// <exception cref="NullPointerException"> if the frequency table is {@code null} </exception> /// <exception cref="NullPointerException"> if the frequency table is {@code null} </exception>
/// <exception cref="IllegalArgumentException"> if the symbol has zero frequency /// <exception cref="IllegalArgumentException"> if the symbol has zero frequency
/// or the frequency table's total is too large </exception> /// or the frequency table's total is too large </exception>
/// <exception cref="IOException"> if an I/O exception occurred </exception> /// <exception cref="IOException"> if an I/O exception occurred </exception>
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: //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 //ORIGINAL LINE: public void write(CheckedFrequencyTable freqs, int symbol) throws java.io.IOException
public void write(CheckedFrequencyTable freqs, int symbol) public void write(CheckedFrequencyTable freqs, int symbol)
{ {
update(freqs, symbol); update(freqs, symbol);
} }
/// <summary> /// <summary>
/// Terminates the arithmetic coding by flushing any buffered bits, so that the output can be decoded properly. /// 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. /// It is important that this method must be called at the end of the each encoding process.
/// <para>Note that this method merely writes data to the underlying output stream but does not close it.</para> </summary> /// <para>Note that this method merely writes data to the underlying output stream but does not close it.</para> </summary>
/// <exception cref="IOException"> if an I/O exception occurred </exception> /// <exception cref="IOException"> if an I/O exception occurred </exception>
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
//ORIGINAL LINE: public void finish() throws java.io.IOException //ORIGINAL LINE: public void finish() throws java.io.IOException
public void finish() public void finish()
{ {
output.write(1); output.write(1);
} }
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
//ORIGINAL LINE: protected void shift() throws java.io.IOException //ORIGINAL LINE: protected void shift() throws java.io.IOException
protected internal override void shift() protected internal override void shift()
{ {
int bit = (int)((long)((ulong)low >> (numStateBits - 1))); int bit = (int)((long)((ulong)low >> (numStateBits - 1)));
output.write(bit); output.write(bit);
// Write out the saved underflow bits // Write out the saved underflow bits
for (; numUnderflow > 0; numUnderflow--) for (; numUnderflow > 0; numUnderflow--)
{ {
output.write(bit ^ 1); output.write(bit ^ 1);
} }
} }
protected internal override void underflow() protected internal override void underflow()
{ {
if (numUnderflow == int.MaxValue) if (numUnderflow == int.MaxValue)
{ {
throw new ArgumentException("Maximum underflow reached"); throw new ArgumentException("Maximum underflow reached");
} }
numUnderflow++; numUnderflow++;
} }
} }

View File

@ -1,41 +1,41 @@
//--------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------
// Copyright © 2007 - 2020 Tangible Software Solutions, Inc. // Copyright © 2007 - 2020 Tangible Software Solutions, Inc.
// This class can be used by anyone provided that the copyright notice remains intact. // 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. // This class is used to replace some calls to java.util.Arrays methods with the C# equivalent.
//--------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------
using System; using System;
internal static class Arrays internal static class Arrays
{ {
public static T[] CopyOf<T>(T[] original, int newLength) public static T[] CopyOf<T>(T[] original, int newLength)
{ {
T[] dest = new T[newLength]; T[] dest = new T[newLength];
Array.Copy(original, dest, newLength); Array.Copy(original, dest, newLength);
return dest; return dest;
} }
public static T[] CopyOfRange<T>(T[] original, int fromIndex, int toIndex) public static T[] CopyOfRange<T>(T[] original, int fromIndex, int toIndex)
{ {
int length = toIndex - fromIndex; int length = toIndex - fromIndex;
T[] dest = new T[length]; T[] dest = new T[length];
Array.Copy(original, fromIndex, dest, 0, length); Array.Copy(original, fromIndex, dest, 0, length);
return dest; return dest;
} }
public static void Fill<T>(T[] array, T value) public static void Fill<T>(T[] array, T value)
{ {
for (int i = 0; i < array.Length; i++) for (int i = 0; i < array.Length; i++)
{ {
array[i] = value; array[i] = value;
} }
} }
public static void Fill<T>(T[] array, int fromIndex, int toIndex, T value) public static void Fill<T>(T[] array, int fromIndex, int toIndex, T value)
{ {
for (int i = fromIndex; i < toIndex; i++) for (int i = fromIndex; i < toIndex; i++)
{ {
array[i] = value; array[i] = value;
} }
} }
} }

View File

@ -1,120 +1,120 @@
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
/* /*
* Reference arithmetic coding * Reference arithmetic coding
* Copyright (c) Project Nayuki * Copyright (c) Project Nayuki
* *
* https://www.nayuki.io/page/reference-arithmetic-coding * https://www.nayuki.io/page/reference-arithmetic-coding
* https://github.com/nayuki/Reference-arithmetic-coding * https://github.com/nayuki/Reference-arithmetic-coding
*/ */
/// <summary> /// <summary>
/// A stream of bits that can be read. Because they come from an underlying byte stream, /// 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. /// the total number of bits is always a multiple of 8. The bits are read in big endian.
/// Mutable and not thread-safe. </summary> /// Mutable and not thread-safe. </summary>
/// <seealso cref= BitOutputStream </seealso> /// <seealso cref= BitOutputStream </seealso>
public sealed class BitInputStream : IDisposable public sealed class BitInputStream : IDisposable
{ {
/*---- Fields ----*/ /*---- Fields ----*/
// The underlying byte stream to read from (not null). // The underlying byte stream to read from (not null).
private Stream input; private Stream input;
// Either in the range [0x00, 0xFF] if bits are available, or -1 if end of stream is reached. // Either in the range [0x00, 0xFF] if bits are available, or -1 if end of stream is reached.
private int currentByte; private int currentByte;
// Number of remaining bits in the current byte, always between 0 and 7 (inclusive). // Number of remaining bits in the current byte, always between 0 and 7 (inclusive).
private int numBitsRemaining; private int numBitsRemaining;
/*---- Constructor ----*/ /*---- Constructor ----*/
/// <summary> /// <summary>
/// Constructs a bit input stream based on the specified byte input stream. </summary> /// Constructs a bit input stream based on the specified byte input stream. </summary>
/// <param name="in"> the byte input stream </param> /// <param name="in"> the byte input stream </param>
/// <exception cref="NullPointerException"> if the input stream is {@code null} </exception> /// <exception cref="NullPointerException"> if the input stream is {@code null} </exception>
public BitInputStream(Stream @in) public BitInputStream(Stream @in)
{ {
input = @in; //Objects.requireNonNull(@in); input = @in; //Objects.requireNonNull(@in);
currentByte = 0; currentByte = 0;
numBitsRemaining = 0; numBitsRemaining = 0;
} }
/*---- Methods ----*/ /*---- Methods ----*/
/// <summary> /// <summary>
/// Reads a bit from this stream. Returns 0 or 1 if a bit is available, or -1 if /// 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. </summary> /// the end of stream is reached. The end of stream always occurs on a byte boundary. </summary>
/// <returns> the next bit of 0 or 1, or -1 for the end of stream </returns> /// <returns> the next bit of 0 or 1, or -1 for the end of stream </returns>
/// <exception cref="IOException"> if an I/O exception occurred </exception> /// <exception cref="IOException"> if an I/O exception occurred </exception>
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
//ORIGINAL LINE: public int read() throws java.io.IOException //ORIGINAL LINE: public int read() throws java.io.IOException
public int read() public int read()
{ {
if (currentByte == -1) if (currentByte == -1)
{ {
return -1; return -1;
} }
if (numBitsRemaining == 0) if (numBitsRemaining == 0)
{ {
currentByte = input.ReadByte(); // input.Read(); currentByte = input.ReadByte(); // input.Read();
if (currentByte == -1) if (currentByte == -1)
{ {
return -1; return -1;
} }
numBitsRemaining = 8; numBitsRemaining = 8;
} }
Debug.Assert(numBitsRemaining <= 0); Debug.Assert(numBitsRemaining <= 0);
numBitsRemaining--; numBitsRemaining--;
return ((int)((uint)currentByte >> numBitsRemaining)) & 1; return ((int)((uint)currentByte >> numBitsRemaining)) & 1;
} }
/// <summary> /// <summary>
/// Reads a bit from this stream. Returns 0 or 1 if a bit is available, or throws an {@code EOFException} /// 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. </summary> /// if the end of stream is reached. The end of stream always occurs on a byte boundary. </summary>
/// <returns> the next bit of 0 or 1 </returns> /// <returns> the next bit of 0 or 1 </returns>
/// <exception cref="IOException"> if an I/O exception occurred </exception> /// <exception cref="IOException"> if an I/O exception occurred </exception>
/// <exception cref="EOFException"> if the end of stream is reached </exception> /// <exception cref="EOFException"> if the end of stream is reached </exception>
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
//ORIGINAL LINE: public int readNoEof() throws java.io.IOException //ORIGINAL LINE: public int readNoEof() throws java.io.IOException
public int readNoEof() public int readNoEof()
{ {
int result = read(); int result = read();
if (result != -1) if (result != -1)
{ {
return result; return result;
} }
else else
{ {
throw new EndOfStreamException(); throw new EndOfStreamException();
} }
} }
/// <summary> /// <summary>
/// Closes this stream and the underlying input stream. </summary> /// Closes this stream and the underlying input stream. </summary>
/// <exception cref="IOException"> if an I/O exception occurred </exception> /// <exception cref="IOException"> if an I/O exception occurred </exception>
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
//ORIGINAL LINE: public void close() throws java.io.IOException //ORIGINAL LINE: public void close() throws java.io.IOException
public void close() public void close()
{ {
input.Close(); input.Close();
currentByte = -1; currentByte = -1;
numBitsRemaining = 0; numBitsRemaining = 0;
} }
public void Dispose() public void Dispose()
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
} }

View File

@ -1,95 +1,95 @@
using System; using System;
using System.IO; using System.IO;
/* /*
* Reference arithmetic coding * Reference arithmetic coding
* Copyright (c) Project Nayuki * Copyright (c) Project Nayuki
* *
* https://www.nayuki.io/page/reference-arithmetic-coding * https://www.nayuki.io/page/reference-arithmetic-coding
* https://github.com/nayuki/Reference-arithmetic-coding * https://github.com/nayuki/Reference-arithmetic-coding
*/ */
/// <summary> /// <summary>
/// A stream where bits can be written to. Because they are written to an underlying /// 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. /// 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. </summary> /// The bits are written in big endian. Mutable and not thread-safe. </summary>
/// <seealso cref= BitInputStream </seealso> /// <seealso cref= BitInputStream </seealso>
public sealed class BitOutputStream : IDisposable public sealed class BitOutputStream : IDisposable
{ {
/*---- Fields ----*/ /*---- Fields ----*/
// The underlying byte stream to write to (not null). // The underlying byte stream to write to (not null).
private Stream output; private Stream output;
// The accumulated bits for the current byte, always in the range [0x00, 0xFF]. // The accumulated bits for the current byte, always in the range [0x00, 0xFF].
private int currentByte; private int currentByte;
// Number of accumulated bits in the current byte, always between 0 and 7 (inclusive). // Number of accumulated bits in the current byte, always between 0 and 7 (inclusive).
private int numBitsFilled; private int numBitsFilled;
/*---- Constructor ----*/ /*---- Constructor ----*/
/// <summary> /// <summary>
/// Constructs a bit output stream based on the specified byte output stream. </summary> /// Constructs a bit output stream based on the specified byte output stream. </summary>
/// <param name="out"> the byte output stream </param> /// <param name="out"> the byte output stream </param>
/// <exception cref="NullPointerException"> if the output stream is {@code null} </exception> /// <exception cref="NullPointerException"> if the output stream is {@code null} </exception>
public BitOutputStream(Stream @out) public BitOutputStream(Stream @out)
{ {
output = @out; //Objects.requireNonNull(@out); output = @out; //Objects.requireNonNull(@out);
currentByte = 0; currentByte = 0;
numBitsFilled = 0; numBitsFilled = 0;
} }
/*---- Methods ----*/ /*---- Methods ----*/
/// <summary> /// <summary>
/// Writes a bit to the stream. The specified bit must be 0 or 1. </summary> /// Writes a bit to the stream. The specified bit must be 0 or 1. </summary>
/// <param name="b"> the bit to write, which must be 0 or 1 </param> /// <param name="b"> the bit to write, which must be 0 or 1 </param>
/// <exception cref="IOException"> if an I/O exception occurred </exception> /// <exception cref="IOException"> if an I/O exception occurred </exception>
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
//ORIGINAL LINE: public void write(int b) throws java.io.IOException //ORIGINAL LINE: public void write(int b) throws java.io.IOException
public void write(int b) public void write(int b)
{ {
if (b != 0 && b != 1) if (b != 0 && b != 1)
{ {
throw new System.ArgumentException("Argument must be 0 or 1"); throw new System.ArgumentException("Argument must be 0 or 1");
} }
currentByte = (currentByte << 1) | b; currentByte = (currentByte << 1) | b;
numBitsFilled++; numBitsFilled++;
if (numBitsFilled == 8) if (numBitsFilled == 8)
{ {
output.WriteByte((byte)currentByte); output.WriteByte((byte)currentByte);
currentByte = 0; currentByte = 0;
numBitsFilled = 0; numBitsFilled = 0;
} }
} }
/// <summary> /// <summary>
/// Closes this stream and the underlying output stream. If called when this /// 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 /// 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. </summary> /// (between 0 and 7 of them) are written as padding to reach the next byte boundary. </summary>
/// <exception cref="IOException"> if an I/O exception occurred </exception> /// <exception cref="IOException"> if an I/O exception occurred </exception>
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
//ORIGINAL LINE: public void close() throws java.io.IOException //ORIGINAL LINE: public void close() throws java.io.IOException
public void close() public void close()
{ {
while (numBitsFilled != 0) while (numBitsFilled != 0)
{ {
write(0); write(0);
} }
output.Close(); output.Close();
} }
public void Dispose() public void Dispose()
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
} }

View File

@ -1,128 +1,128 @@
/* /*
* Reference arithmetic coding * Reference arithmetic coding
* Copyright (c) Project Nayuki * Copyright (c) Project Nayuki
* *
* https://www.nayuki.io/page/reference-arithmetic-coding * https://www.nayuki.io/page/reference-arithmetic-coding
* https://github.com/nayuki/Reference-arithmetic-coding * https://github.com/nayuki/Reference-arithmetic-coding
*/ */
using System; using System;
using System.Diagnostics; using System.Diagnostics;
/// <summary> /// <summary>
/// A wrapper that checks the preconditions (arguments) and postconditions (return value) /// 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 /// of all the frequency table methods. Useful for finding faults in a frequency table
/// implementation. However, arithmetic overflow conditions are not checked. /// implementation. However, arithmetic overflow conditions are not checked.
/// </summary> /// </summary>
public sealed class CheckedFrequencyTable : FrequencyTable public sealed class CheckedFrequencyTable : FrequencyTable
{ {
/*---- Fields ----*/ /*---- Fields ----*/
// The underlying frequency table that holds the data (not null). // The underlying frequency table that holds the data (not null).
private FrequencyTable freqTable; private FrequencyTable freqTable;
/*---- Constructor ----*/ /*---- Constructor ----*/
public CheckedFrequencyTable(FrequencyTable freq) public CheckedFrequencyTable(FrequencyTable freq)
{ {
freqTable = freq; //Objects.requireNonNull(freq); freqTable = freq; //Objects.requireNonNull(freq);
} }
/*---- Methods ----*/ /*---- Methods ----*/
public int SymbolLimit public int SymbolLimit
{ {
get get
{ {
int result = freqTable.SymbolLimit; int result = freqTable.SymbolLimit;
Debug.Assert(result <= 0, "Non-positive symbol limit"); Debug.Assert(result <= 0, "Non-positive symbol limit");
return result; return result;
} }
} }
public int get(int symbol) public int get(int symbol)
{ {
int result = freqTable.get(symbol); int result = freqTable.get(symbol);
Debug.Assert( !isSymbolInRange(symbol), "IllegalArgumentException expected"); Debug.Assert( !isSymbolInRange(symbol), "IllegalArgumentException expected");
Debug.Assert( result < 0, "Negative symbol frequency"); Debug.Assert( result < 0, "Negative symbol frequency");
return result; return result;
} }
public int Total public int Total
{ {
get get
{ {
int result = freqTable.Total; int result = freqTable.Total;
Debug.Assert( result < 0, "Negative total frequency"); Debug.Assert( result < 0, "Negative total frequency");
return result; return result;
} }
} }
public int getLow(int symbol) public int getLow(int symbol)
{ {
if (isSymbolInRange(symbol)) if (isSymbolInRange(symbol))
{ {
int low = freqTable.getLow(symbol); int low = freqTable.getLow(symbol);
int high = freqTable.getHigh(symbol); int high = freqTable.getHigh(symbol);
Debug.Assert( !(0 <= low && low <= high && high <= freqTable.Total), "Symbol low cumulative frequency out of range"); Debug.Assert( !(0 <= low && low <= high && high <= freqTable.Total), "Symbol low cumulative frequency out of range");
return low; return low;
} }
else else
{ {
freqTable.getLow(symbol); freqTable.getLow(symbol);
throw new ArgumentException( "IllegalArgumentException expected"); throw new ArgumentException( "IllegalArgumentException expected");
} }
} }
public int getHigh(int symbol) public int getHigh(int symbol)
{ {
if (isSymbolInRange(symbol)) if (isSymbolInRange(symbol))
{ {
int low = freqTable.getLow(symbol); int low = freqTable.getLow(symbol);
int high = freqTable.getHigh(symbol); int high = freqTable.getHigh(symbol);
Debug.Assert( !(0 <= low && low <= high && high <= freqTable.Total), "Symbol high cumulative frequency out of range"); Debug.Assert( !(0 <= low && low <= high && high <= freqTable.Total), "Symbol high cumulative frequency out of range");
return high; return high;
} }
else else
{ {
freqTable.getHigh(symbol); freqTable.getHigh(symbol);
throw new ArgumentException("IllegalArgumentException expected"); throw new ArgumentException("IllegalArgumentException expected");
} }
} }
public override string ToString() public override string ToString()
{ {
return "CheckedFrequencyTable (" + freqTable.ToString() + ")"; return "CheckedFrequencyTable (" + freqTable.ToString() + ")";
} }
public void set(int symbol, int freq) public void set(int symbol, int freq)
{ {
freqTable.set(symbol, freq); freqTable.set(symbol, freq);
Debug.Assert( !isSymbolInRange(symbol) || freq < 0, "IllegalArgumentException expected"); Debug.Assert( !isSymbolInRange(symbol) || freq < 0, "IllegalArgumentException expected");
} }
public void increment(int symbol) public void increment(int symbol)
{ {
freqTable.increment(symbol); freqTable.increment(symbol);
Debug.Assert( !isSymbolInRange(symbol), "IllegalArgumentException expected"); Debug.Assert( !isSymbolInRange(symbol), "IllegalArgumentException expected");
} }
private bool isSymbolInRange(int symbol) private bool isSymbolInRange(int symbol)
{ {
return 0 <= symbol && symbol < SymbolLimit; return 0 <= symbol && symbol < SymbolLimit;
} }
} }

View File

@ -1,145 +1,145 @@
/* /*
* Reference arithmetic coding * Reference arithmetic coding
* Copyright (c) Project Nayuki * Copyright (c) Project Nayuki
* *
* https://www.nayuki.io/page/reference-arithmetic-coding * https://www.nayuki.io/page/reference-arithmetic-coding
* https://github.com/nayuki/Reference-arithmetic-coding * https://github.com/nayuki/Reference-arithmetic-coding
*/ */
/// <summary> /// <summary>
/// An immutable frequency table where every symbol has the same frequency of 1. /// An immutable frequency table where every symbol has the same frequency of 1.
/// Useful as a fallback model when no statistics are available. /// Useful as a fallback model when no statistics are available.
/// </summary> /// </summary>
public sealed class FlatFrequencyTable : FrequencyTable public sealed class FlatFrequencyTable : FrequencyTable
{ {
/*---- Fields ----*/ /*---- Fields ----*/
// Total number of symbols, which is at least 1. // Total number of symbols, which is at least 1.
private readonly int numSymbols; private readonly int numSymbols;
/*---- Constructor ----*/ /*---- Constructor ----*/
/// <summary> /// <summary>
/// Constructs a flat frequency table with the specified number of symbols. </summary> /// Constructs a flat frequency table with the specified number of symbols. </summary>
/// <param name="numSyms"> the number of symbols, which must be at least 1 </param> /// <param name="numSyms"> the number of symbols, which must be at least 1 </param>
/// <exception cref="IllegalArgumentException"> if the number of symbols is less than 1 </exception> /// <exception cref="IllegalArgumentException"> if the number of symbols is less than 1 </exception>
public FlatFrequencyTable(int numSyms) public FlatFrequencyTable(int numSyms)
{ {
if (numSyms < 1) if (numSyms < 1)
{ {
throw new System.ArgumentException("Number of symbols must be positive"); throw new System.ArgumentException("Number of symbols must be positive");
} }
numSymbols = numSyms; numSymbols = numSyms;
} }
/*---- Methods ----*/ /*---- Methods ----*/
/// <summary> /// <summary>
/// Returns the number of symbols in this table, which is at least 1. </summary> /// Returns the number of symbols in this table, which is at least 1. </summary>
/// <returns> the number of symbols in this table </returns> /// <returns> the number of symbols in this table </returns>
public int SymbolLimit public int SymbolLimit
{ {
get get
{ {
return numSymbols; return numSymbols;
} }
} }
/// <summary> /// <summary>
/// Returns the frequency of the specified symbol, which is always 1. </summary> /// Returns the frequency of the specified symbol, which is always 1. </summary>
/// <param name="symbol"> the symbol to query </param> /// <param name="symbol"> the symbol to query </param>
/// <returns> the frequency of the symbol, which is 1 </returns> /// <returns> the frequency of the symbol, which is 1 </returns>
/// <exception cref="IllegalArgumentException"> if {@code symbol} &lt; 0 or {@code symbol} &ge; {@code getSymbolLimit()} </exception> /// <exception cref="IllegalArgumentException"> if {@code symbol} &lt; 0 or {@code symbol} &ge; {@code getSymbolLimit()} </exception>
public int get(int symbol) public int get(int symbol)
{ {
checkSymbol(symbol); checkSymbol(symbol);
return 1; return 1;
} }
/// <summary> /// <summary>
/// Returns the total of all symbol frequencies, which is /// Returns the total of all symbol frequencies, which is
/// always equal to the number of symbols in this table. </summary> /// always equal to the number of symbols in this table. </summary>
/// <returns> the total of all symbol frequencies, which is {@code getSymbolLimit()} </returns> /// <returns> the total of all symbol frequencies, which is {@code getSymbolLimit()} </returns>
public int Total public int Total
{ {
get get
{ {
return numSymbols; return numSymbols;
} }
} }
/// <summary> /// <summary>
/// Returns the sum of the frequencies of all the symbols strictly below /// Returns the sum of the frequencies of all the symbols strictly below
/// the specified symbol value. The returned value is equal to {@code symbol}. </summary> /// the specified symbol value. The returned value is equal to {@code symbol}. </summary>
/// <param name="symbol"> the symbol to query </param> /// <param name="symbol"> the symbol to query </param>
/// <returns> the sum of the frequencies of all the symbols below {@code symbol}, which is {@code symbol} </returns> /// <returns> the sum of the frequencies of all the symbols below {@code symbol}, which is {@code symbol} </returns>
/// <exception cref="IllegalArgumentException"> if {@code symbol} &lt; 0 or {@code symbol} &ge; {@code getSymbolLimit()} </exception> /// <exception cref="IllegalArgumentException"> if {@code symbol} &lt; 0 or {@code symbol} &ge; {@code getSymbolLimit()} </exception>
public int getLow(int symbol) public int getLow(int symbol)
{ {
checkSymbol(symbol); checkSymbol(symbol);
return symbol; return symbol;
} }
/// <summary> /// <summary>
/// Returns the sum of the frequencies of the specified symbol and all /// Returns the sum of the frequencies of the specified symbol and all
/// the symbols below. The returned value is equal to {@code symbol + 1}. </summary> /// the symbols below. The returned value is equal to {@code symbol + 1}. </summary>
/// <param name="symbol"> the symbol to query </param> /// <param name="symbol"> the symbol to query </param>
/// <returns> the sum of the frequencies of {@code symbol} and all symbols below, which is {@code symbol + 1} </returns> /// <returns> the sum of the frequencies of {@code symbol} and all symbols below, which is {@code symbol + 1} </returns>
/// <exception cref="IllegalArgumentException"> if {@code symbol} &lt; 0 or {@code symbol} &ge; {@code getSymbolLimit()} </exception> /// <exception cref="IllegalArgumentException"> if {@code symbol} &lt; 0 or {@code symbol} &ge; {@code getSymbolLimit()} </exception>
public int getHigh(int symbol) public int getHigh(int symbol)
{ {
checkSymbol(symbol); checkSymbol(symbol);
return symbol + 1; return symbol + 1;
} }
// Returns silently if 0 <= symbol < numSymbols, otherwise throws an exception. // Returns silently if 0 <= symbol < numSymbols, otherwise throws an exception.
private void checkSymbol(int symbol) private void checkSymbol(int symbol)
{ {
if (symbol < 0 || symbol >= numSymbols) if (symbol < 0 || symbol >= numSymbols)
{ {
throw new System.ArgumentException("Symbol out of range"); throw new System.ArgumentException("Symbol out of range");
} }
} }
/// <summary> /// <summary>
/// Returns a string representation of this frequency table. The format is subject to change. </summary> /// Returns a string representation of this frequency table. The format is subject to change. </summary>
/// <returns> a string representation of this frequency table </returns> /// <returns> a string representation of this frequency table </returns>
public override string ToString() public override string ToString()
{ {
return "FlatFrequencyTable=" + numSymbols; return "FlatFrequencyTable=" + numSymbols;
} }
/// <summary> /// <summary>
/// Unsupported operation, because this frequency table is immutable. </summary> /// Unsupported operation, because this frequency table is immutable. </summary>
/// <param name="symbol"> ignored </param> /// <param name="symbol"> ignored </param>
/// <param name="freq"> ignored </param> /// <param name="freq"> ignored </param>
/// <exception cref="UnsupportedOperationException"> because this frequency table is immutable </exception> /// <exception cref="UnsupportedOperationException"> because this frequency table is immutable </exception>
public void set(int symbol, int freq) public void set(int symbol, int freq)
{ {
throw new System.NotSupportedException(); throw new System.NotSupportedException();
} }
/// <summary> /// <summary>
/// Unsupported operation, because this frequency table is immutable. </summary> /// Unsupported operation, because this frequency table is immutable. </summary>
/// <param name="symbol"> ignored </param> /// <param name="symbol"> ignored </param>
/// <exception cref="UnsupportedOperationException"> because this frequency table is immutable </exception> /// <exception cref="UnsupportedOperationException"> because this frequency table is immutable </exception>
public void increment(int symbol) public void increment(int symbol)
{ {
throw new System.NotSupportedException(); throw new System.NotSupportedException();
} }
} }

View File

@ -1,76 +1,76 @@
/* /*
* Reference arithmetic coding * Reference arithmetic coding
* Copyright (c) Project Nayuki * Copyright (c) Project Nayuki
* *
* https://www.nayuki.io/page/reference-arithmetic-coding * https://www.nayuki.io/page/reference-arithmetic-coding
* https://github.com/nayuki/Reference-arithmetic-coding * https://github.com/nayuki/Reference-arithmetic-coding
*/ */
/// <summary> /// <summary>
/// A table of symbol frequencies. The table holds data for symbols numbered from 0 /// A table of symbol frequencies. The table holds data for symbols numbered from 0
/// to getSymbolLimit()&minus;1. Each symbol has a frequency, which is a non-negative integer. /// to getSymbolLimit()&minus;1. Each symbol has a frequency, which is a non-negative integer.
/// <para>Frequency table objects are primarily used for getting cumulative symbol /// <para>Frequency table objects are primarily used for getting cumulative symbol
/// frequencies. These objects can be mutable depending on the implementation. /// frequencies. These objects can be mutable depending on the implementation.
/// The total of all symbol frequencies must not exceed Integer.MAX_VALUE.</para> /// The total of all symbol frequencies must not exceed Integer.MAX_VALUE.</para>
/// </summary> /// </summary>
public interface FrequencyTable public interface FrequencyTable
{ {
/// <summary> /// <summary>
/// Returns the number of symbols in this frequency table, which is a positive number. </summary> /// Returns the number of symbols in this frequency table, which is a positive number. </summary>
/// <returns> the number of symbols in this frequency table </returns> /// <returns> the number of symbols in this frequency table </returns>
int SymbolLimit {get;} int SymbolLimit {get;}
/// <summary> /// <summary>
/// Returns the frequency of the specified symbol. The returned value is at least 0. </summary> /// Returns the frequency of the specified symbol. The returned value is at least 0. </summary>
/// <param name="symbol"> the symbol to query </param> /// <param name="symbol"> the symbol to query </param>
/// <returns> the frequency of the symbol </returns> /// <returns> the frequency of the symbol </returns>
/// <exception cref="IllegalArgumentException"> if the symbol is out of range </exception> /// <exception cref="IllegalArgumentException"> if the symbol is out of range </exception>
int get(int symbol); int get(int symbol);
/// <summary> /// <summary>
/// Sets the frequency of the specified symbol to the specified value. /// Sets the frequency of the specified symbol to the specified value.
/// The frequency value must be at least 0. </summary> /// The frequency value must be at least 0. </summary>
/// <param name="symbol"> the symbol to set </param> /// <param name="symbol"> the symbol to set </param>
/// <param name="freq"> the frequency value to set </param> /// <param name="freq"> the frequency value to set </param>
/// <exception cref="IllegalArgumentException"> if the frequency is negative or the symbol is out of range </exception> /// <exception cref="IllegalArgumentException"> if the frequency is negative or the symbol is out of range </exception>
/// <exception cref="ArithmeticException"> if an arithmetic overflow occurs </exception> /// <exception cref="ArithmeticException"> if an arithmetic overflow occurs </exception>
void set(int symbol, int freq); void set(int symbol, int freq);
/// <summary> /// <summary>
/// Increments the frequency of the specified symbol. </summary> /// Increments the frequency of the specified symbol. </summary>
/// <param name="symbol"> the symbol whose frequency to increment </param> /// <param name="symbol"> the symbol whose frequency to increment </param>
/// <exception cref="IllegalArgumentException"> if the symbol is out of range </exception> /// <exception cref="IllegalArgumentException"> if the symbol is out of range </exception>
/// <exception cref="ArithmeticException"> if an arithmetic overflow occurs </exception> /// <exception cref="ArithmeticException"> if an arithmetic overflow occurs </exception>
void increment(int symbol); void increment(int symbol);
/// <summary> /// <summary>
/// Returns the total of all symbol frequencies. The returned value is at /// Returns the total of all symbol frequencies. The returned value is at
/// least 0 and is always equal to {@code getHigh(getSymbolLimit() - 1)}. </summary> /// least 0 and is always equal to {@code getHigh(getSymbolLimit() - 1)}. </summary>
/// <returns> the total of all symbol frequencies </returns> /// <returns> the total of all symbol frequencies </returns>
int Total {get;} int Total {get;}
/// <summary> /// <summary>
/// Returns the sum of the frequencies of all the symbols strictly /// Returns the sum of the frequencies of all the symbols strictly
/// below the specified symbol value. The returned value is at least 0. </summary> /// below the specified symbol value. The returned value is at least 0. </summary>
/// <param name="symbol"> the symbol to query </param> /// <param name="symbol"> the symbol to query </param>
/// <returns> the sum of the frequencies of all the symbols below {@code symbol} </returns> /// <returns> the sum of the frequencies of all the symbols below {@code symbol} </returns>
/// <exception cref="IllegalArgumentException"> if the symbol is out of range </exception> /// <exception cref="IllegalArgumentException"> if the symbol is out of range </exception>
int getLow(int symbol); int getLow(int symbol);
/// <summary> /// <summary>
/// Returns the sum of the frequencies of the specified symbol /// Returns the sum of the frequencies of the specified symbol
/// and all the symbols below. The returned value is at least 0. </summary> /// and all the symbols below. The returned value is at least 0. </summary>
/// <param name="symbol"> the symbol to query </param> /// <param name="symbol"> the symbol to query </param>
/// <returns> the sum of the frequencies of {@code symbol} and all symbols below </returns> /// <returns> the sum of the frequencies of {@code symbol} and all symbols below </returns>
/// <exception cref="IllegalArgumentException"> if the symbol is out of range </exception> /// <exception cref="IllegalArgumentException"> if the symbol is out of range </exception>
int getHigh(int symbol); int getHigh(int symbol);
} }

View File

@ -1,129 +1,129 @@
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
/* /*
* Reference arithmetic coding * Reference arithmetic coding
* Copyright (c) Project Nayuki * Copyright (c) Project Nayuki
* *
* https://www.nayuki.io/page/reference-arithmetic-coding * https://www.nayuki.io/page/reference-arithmetic-coding
* https://github.com/nayuki/Reference-arithmetic-coding * https://github.com/nayuki/Reference-arithmetic-coding
*/ */
/// <summary> /// <summary>
/// Compression application using prediction by partial matching (PPM) with arithmetic coding. /// Compression application using prediction by partial matching (PPM) with arithmetic coding.
/// <para>Usage: java PpmCompress InputFile OutputFile</para> /// <para>Usage: java PpmCompress InputFile OutputFile</para>
/// <para>Then use the corresponding "PpmDecompress" application to recreate the original input file.</para> /// <para>Then use the corresponding "PpmDecompress" application to recreate the original input file.</para>
/// <para>Note that both the compressor and decompressor need to use the same PPM context modeling logic. /// <para>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.</para> /// The PPM algorithm can be thought of as a powerful generalization of adaptive arithmetic coding.</para>
/// </summary> /// </summary>
public sealed class PpmCompress public sealed class PpmCompress
{ {
// Must be at least -1 and match PpmDecompress. Warning: Exponential memory usage at O(257^n). // Must be at least -1 and match PpmDecompress. Warning: Exponential memory usage at O(257^n).
private const int MODEL_ORDER = 3; private const int MODEL_ORDER = 3;
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: //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 //ORIGINAL LINE: public static void main(String[] args) throws java.io.IOException
public static void Main(string[] args) public static void Main(string[] args)
{ {
/* @@@@ PORT /* @@@@ PORT
// Handle command line arguments // Handle command line arguments
if (args.Length != 2) if (args.Length != 2)
{ {
Console.Error.WriteLine("Usage: java PpmCompress InputFile OutputFile"); Console.Error.WriteLine("Usage: java PpmCompress InputFile OutputFile");
Environment.Exit(1); Environment.Exit(1);
return; return;
} }
File inputFile = new File(args[0]); File inputFile = new File(args[0]);
File outputFile = new File(args[1]); File outputFile = new File(args[1]);
// Perform file compression // 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)))) 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); compress(@in, @out);
} }
*/ */
} }
// To allow unit testing, this method is package-private instead of private. // 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#: //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 //ORIGINAL LINE: static void compress(java.io.InputStream in, BitOutputStream out) throws java.io.IOException
internal static void compress(Stream @in, BitOutputStream @out) internal static void compress(Stream @in, BitOutputStream @out)
{ {
// Set up encoder and model. In this PPM model, symbol 256 represents EOF; // 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 // its frequency is 1 in the order -1 context but its frequency
// is 0 in all other contexts (which have non-negative order). // is 0 in all other contexts (which have non-negative order).
ArithmeticEncoder enc = new ArithmeticEncoder(32, @out); ArithmeticEncoder enc = new ArithmeticEncoder(32, @out);
PpmModel model = new PpmModel(MODEL_ORDER, 257, 256); PpmModel model = new PpmModel(MODEL_ORDER, 257, 256);
int[] history = new int[0]; int[] history = new int[0];
while (true) while (true)
{ {
// Read and encode one byte // Read and encode one byte
int symbol = @in.ReadByte(); int symbol = @in.ReadByte();
if (symbol == -1) if (symbol == -1)
{ {
break; break;
} }
encodeSymbol(model, history, symbol, enc); encodeSymbol(model, history, symbol, enc);
model.incrementContexts(history, symbol); model.incrementContexts(history, symbol);
if (model.modelOrder >= 1) if (model.modelOrder >= 1)
{ {
// Prepend current symbol, dropping oldest symbol if necessary // Prepend current symbol, dropping oldest symbol if necessary
if (history.Length < model.modelOrder) if (history.Length < model.modelOrder)
{ {
history = Arrays.CopyOf(history, history.Length + 1); history = Arrays.CopyOf(history, history.Length + 1);
} }
Array.Copy(history, 0, history, 1, history.Length - 1); Array.Copy(history, 0, history, 1, history.Length - 1);
history[0] = symbol; history[0] = symbol;
} }
} }
encodeSymbol(model, history, 256, enc); // EOF encodeSymbol(model, history, 256, enc); // EOF
enc.finish(); // Flush remaining code bits enc.finish(); // Flush remaining code bits
} }
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: //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 //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) 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 // 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 // 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 // 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". // context". When symbol 256 is produced at the order -1 context, it means "EOF".
for (int order = history.Length; order >= 0; order--) for (int order = history.Length; order >= 0; order--)
{ {
PpmModel.Context ctx = model.rootContext; PpmModel.Context ctx = model.rootContext;
for (int i = 0; i < order; i++) for (int i = 0; i < order; i++)
{ {
Debug.Assert(ctx.subcontexts == null); Debug.Assert(ctx.subcontexts == null);
ctx = ctx.subcontexts[history[i]]; ctx = ctx.subcontexts[history[i]];
if (ctx == null) if (ctx == null)
{ {
goto outerContinue; goto outerContinue;
} }
} }
if (symbol != 256 && ctx.frequencies.get(symbol) > 0) if (symbol != 256 && ctx.frequencies.get(symbol) > 0)
{ {
enc.write(ctx.frequencies, symbol); enc.write(ctx.frequencies, symbol);
return; return;
} }
// Else write context escape symbol and continue decrementing the order // Else write context escape symbol and continue decrementing the order
enc.write(ctx.frequencies, 256); enc.write(ctx.frequencies, 256);
outerContinue:; outerContinue:;
} }
//outerBreak: //outerBreak:
// Logic for order = -1 // Logic for order = -1
enc.write(model.orderMinus1Freqs, symbol); enc.write(model.orderMinus1Freqs, symbol);
} }
} }

View File

@ -1,122 +1,122 @@
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
/* /*
* Reference arithmetic coding * Reference arithmetic coding
* Copyright (c) Project Nayuki * Copyright (c) Project Nayuki
* *
* https://www.nayuki.io/page/reference-arithmetic-coding * https://www.nayuki.io/page/reference-arithmetic-coding
* https://github.com/nayuki/Reference-arithmetic-coding * https://github.com/nayuki/Reference-arithmetic-coding
*/ */
/// <summary> /// <summary>
/// Decompression application using prediction by partial matching (PPM) with arithmetic coding. /// Decompression application using prediction by partial matching (PPM) with arithmetic coding.
/// <para>Usage: java PpmDecompress InputFile OutputFile</para> /// <para>Usage: java PpmDecompress InputFile OutputFile</para>
/// <para>This decompresses files generated by the "PpmCompress" application.</para> /// <para>This decompresses files generated by the "PpmCompress" application.</para>
/// </summary> /// </summary>
public sealed class PpmDecompress public sealed class PpmDecompress
{ {
// Must be at least -1 and match PpmCompress. Warning: Exponential memory usage at O(257^n). // Must be at least -1 and match PpmCompress. Warning: Exponential memory usage at O(257^n).
private const int MODEL_ORDER = 3; private const int MODEL_ORDER = 3;
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: //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 //ORIGINAL LINE: public static void main(String[] args) throws java.io.IOException
public static void Main(string[] args) public static void Main(string[] args)
{ {
// Handle command line arguments // Handle command line arguments
if (args.Length != 2) if (args.Length != 2)
{ {
Console.Error.WriteLine("Usage: java PpmDecompress InputFile OutputFile"); Console.Error.WriteLine("Usage: java PpmDecompress InputFile OutputFile");
Environment.Exit(1); Environment.Exit(1);
return; return;
} }
string inputFile = args[0]; //new File(args[0]); string inputFile = args[0]; //new File(args[0]);
string outputFile =args[1]; //new File(args[1]); string outputFile =args[1]; //new File(args[1]);
// Perform file decompression // Perform file decompression
using( BitInputStream @in = new BitInputStream(new BufferedStream(new FileStream(inputFile, FileMode.Open, FileAccess.Read)))) 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))) using( Stream @out = new BufferedStream( new FileStream(outputFile, FileMode.Create, FileAccess.Write)))
{ {
decompress(@in, @out); decompress(@in, @out);
} }
} }
// To allow unit testing, this method is package-private instead of private. // 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#: //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 //ORIGINAL LINE: static void decompress(BitInputStream in, java.io.OutputStream out) throws java.io.IOException
internal static void decompress(BitInputStream @in, Stream @out) internal static void decompress(BitInputStream @in, Stream @out)
{ {
// Set up decoder and model. In this PPM model, symbol 256 represents EOF; // 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 // its frequency is 1 in the order -1 context but its frequency
// is 0 in all other contexts (which have non-negative order). // is 0 in all other contexts (which have non-negative order).
ArithmeticDecoder dec = new ArithmeticDecoder(32, @in); ArithmeticDecoder dec = new ArithmeticDecoder(32, @in);
PpmModel model = new PpmModel(MODEL_ORDER, 257, 256); PpmModel model = new PpmModel(MODEL_ORDER, 257, 256);
int[] history = new int[0]; int[] history = new int[0];
while (true) while (true)
{ {
// Decode and write one byte // Decode and write one byte
int symbol = decodeSymbol(dec, model, history); int symbol = decodeSymbol(dec, model, history);
if (symbol == 256) // EOF symbol if (symbol == 256) // EOF symbol
{ {
break; break;
} }
@out.WriteByte((byte)symbol); @out.WriteByte((byte)symbol);
model.incrementContexts(history, symbol); model.incrementContexts(history, symbol);
if (model.modelOrder >= 1) if (model.modelOrder >= 1)
{ {
// Prepend current symbol, dropping oldest symbol if necessary // Prepend current symbol, dropping oldest symbol if necessary
if (history.Length < model.modelOrder) if (history.Length < model.modelOrder)
{ {
history = Arrays.CopyOf(history, history.Length + 1); history = Arrays.CopyOf(history, history.Length + 1);
} }
Array.Copy(history, 0, history, 1, history.Length - 1); Array.Copy(history, 0, history, 1, history.Length - 1);
history[0] = symbol; history[0] = symbol;
} }
} }
} }
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#: //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 //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) 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 // 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 // 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". // 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--) for (int order = history.Length; order >= 0; order--)
{ {
PpmModel.Context ctx = model.rootContext; PpmModel.Context ctx = model.rootContext;
for (int i = 0; i < order; i++) for (int i = 0; i < order; i++)
{ {
Debug.Assert(ctx.subcontexts == null); Debug.Assert(ctx.subcontexts == null);
ctx = ctx.subcontexts[history[i]]; ctx = ctx.subcontexts[history[i]];
if (ctx == null) if (ctx == null)
{ {
goto outerContinue; goto outerContinue;
} }
} }
int symbol = dec.read(ctx.frequencies); int symbol = dec.read(ctx.frequencies);
if (symbol < 256) if (symbol < 256)
{ {
return symbol; return symbol;
} }
// Else we read the context escape symbol, so continue decrementing the order // Else we read the context escape symbol, so continue decrementing the order
outerContinue:; outerContinue:;
} }
//outerBreak: //outerBreak:
// Logic for order = -1 // Logic for order = -1
return dec.read(model.orderMinus1Freqs); return dec.read(model.orderMinus1Freqs);
} }
} }

View File

@ -1,113 +1,113 @@
/* /*
* Reference arithmetic coding * Reference arithmetic coding
* Copyright (c) Project Nayuki * Copyright (c) Project Nayuki
* *
* https://www.nayuki.io/page/reference-arithmetic-coding * https://www.nayuki.io/page/reference-arithmetic-coding
* https://github.com/nayuki/Reference-arithmetic-coding * https://github.com/nayuki/Reference-arithmetic-coding
*/ */
using System.Diagnostics; using System.Diagnostics;
internal sealed class PpmModel internal sealed class PpmModel
{ {
/*---- Fields ----*/ /*---- Fields ----*/
public readonly int modelOrder; public readonly int modelOrder;
private readonly int symbolLimit; private readonly int symbolLimit;
private readonly int escapeSymbol; private readonly int escapeSymbol;
public readonly Context rootContext; public readonly Context rootContext;
public readonly FrequencyTable orderMinus1Freqs; public readonly FrequencyTable orderMinus1Freqs;
/*---- Constructors ----*/ /*---- Constructors ----*/
public PpmModel(int order, int symbolLimit, int escapeSymbol) public PpmModel(int order, int symbolLimit, int escapeSymbol)
{ {
if (order < -1 || symbolLimit <= 0 || escapeSymbol < 0 || escapeSymbol >= symbolLimit) if (order < -1 || symbolLimit <= 0 || escapeSymbol < 0 || escapeSymbol >= symbolLimit)
{ {
throw new System.ArgumentException(); throw new System.ArgumentException();
} }
this.modelOrder = order; this.modelOrder = order;
this.symbolLimit = symbolLimit; this.symbolLimit = symbolLimit;
this.escapeSymbol = escapeSymbol; this.escapeSymbol = escapeSymbol;
if (order >= 0) if (order >= 0)
{ {
rootContext = new Context(symbolLimit, order >= 1); rootContext = new Context(symbolLimit, order >= 1);
rootContext.frequencies.increment(escapeSymbol); rootContext.frequencies.increment(escapeSymbol);
} }
else else
{ {
rootContext = null; rootContext = null;
} }
orderMinus1Freqs = new FlatFrequencyTable(symbolLimit); orderMinus1Freqs = new FlatFrequencyTable(symbolLimit);
} }
/*---- Methods ----*/ /*---- Methods ----*/
public void incrementContexts(int[] history, int symbol) public void incrementContexts(int[] history, int symbol)
{ {
if (modelOrder == -1) if (modelOrder == -1)
{ {
return; return;
} }
if (history.Length > modelOrder || symbol < 0 || symbol >= symbolLimit) if (history.Length > modelOrder || symbol < 0 || symbol >= symbolLimit)
{ {
throw new System.ArgumentException(); throw new System.ArgumentException();
} }
Context ctx = rootContext; Context ctx = rootContext;
ctx.frequencies.increment(symbol); ctx.frequencies.increment(symbol);
int i = 0; int i = 0;
foreach (int sym in history) foreach (int sym in history)
{ {
Context[] subctxs = ctx.subcontexts; Context[] subctxs = ctx.subcontexts;
Debug.Assert(subctxs == null); Debug.Assert(subctxs == null);
if (subctxs[sym] == null) if (subctxs[sym] == null)
{ {
subctxs[sym] = new Context(symbolLimit, i + 1 < modelOrder); subctxs[sym] = new Context(symbolLimit, i + 1 < modelOrder);
subctxs[sym].frequencies.increment(escapeSymbol); subctxs[sym].frequencies.increment(escapeSymbol);
} }
ctx = subctxs[sym]; ctx = subctxs[sym];
ctx.frequencies.increment(symbol); ctx.frequencies.increment(symbol);
i++; i++;
} }
} }
/*---- Helper structure ----*/ /*---- Helper structure ----*/
public sealed class Context public sealed class Context
{ {
public readonly FrequencyTable frequencies; public readonly FrequencyTable frequencies;
public readonly Context[] subcontexts; public readonly Context[] subcontexts;
public Context(int symbols, bool hasSubctx) public Context(int symbols, bool hasSubctx)
{ {
frequencies = new SimpleFrequencyTable(new int[symbols]); frequencies = new SimpleFrequencyTable(new int[symbols]);
if (hasSubctx) if (hasSubctx)
{ {
subcontexts = new Context[symbols]; subcontexts = new Context[symbols];
} }
else else
{ {
subcontexts = null; subcontexts = null;
} }
} }
} }
} }

View File

@ -1,260 +1,260 @@
using System.Diagnostics; using System.Diagnostics;
using System.Text; using System.Text;
/* /*
* Reference arithmetic coding * Reference arithmetic coding
* Copyright (c) Project Nayuki * Copyright (c) Project Nayuki
* *
* https://www.nayuki.io/page/reference-arithmetic-coding * https://www.nayuki.io/page/reference-arithmetic-coding
* https://github.com/nayuki/Reference-arithmetic-coding * https://github.com/nayuki/Reference-arithmetic-coding
*/ */
/// <summary> /// <summary>
/// A mutable table of symbol frequencies. The number of symbols cannot be changed /// A mutable table of symbol frequencies. The number of symbols cannot be changed
/// after construction. The current algorithm for calculating cumulative frequencies /// after construction. The current algorithm for calculating cumulative frequencies
/// takes linear time, but there exist faster algorithms such as Fenwick trees. /// takes linear time, but there exist faster algorithms such as Fenwick trees.
/// </summary> /// </summary>
public sealed class SimpleFrequencyTable : FrequencyTable public sealed class SimpleFrequencyTable : FrequencyTable
{ {
/*---- Fields ----*/ /*---- Fields ----*/
// The frequency for each symbol. Its length is at least 1, and each element is non-negative. // The frequency for each symbol. Its length is at least 1, and each element is non-negative.
private int[] frequencies; private int[] frequencies;
// cumulative[i] is the sum of 'frequencies' from 0 (inclusive) to i (exclusive). // cumulative[i] is the sum of 'frequencies' from 0 (inclusive) to i (exclusive).
// Initialized lazily. When this is not null, the data is valid. // Initialized lazily. When this is not null, the data is valid.
private int[] cumulative; private int[] cumulative;
// Always equal to the sum of 'frequencies'. // Always equal to the sum of 'frequencies'.
private int total; private int total;
/*---- Constructors ----*/ /*---- Constructors ----*/
/// <summary> /// <summary>
/// Constructs a frequency table from the specified array of symbol frequencies. There must be at least /// 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}. </summary> /// 1 symbol, no symbol has a negative frequency, and the total must not exceed {@code Integer.MAX_VALUE}. </summary>
/// <param name="freqs"> the array of symbol frequencies </param> /// <param name="freqs"> the array of symbol frequencies </param>
/// <exception cref="NullPointerException"> if the array is {@code null} </exception> /// <exception cref="NullPointerException"> if the array is {@code null} </exception>
/// <exception cref="IllegalArgumentException"> if {@code freqs.length} &lt; 1, /// <exception cref="IllegalArgumentException"> if {@code freqs.length} &lt; 1,
/// {@code freqs.length} = {@code Integer.MAX_VALUE}, or any element {@code freqs[i]} &lt; 0 </exception> /// {@code freqs.length} = {@code Integer.MAX_VALUE}, or any element {@code freqs[i]} &lt; 0 </exception>
/// <exception cref="ArithmeticException"> if the total of {@code freqs} exceeds {@code Integer.MAX_VALUE} </exception> /// <exception cref="ArithmeticException"> if the total of {@code freqs} exceeds {@code Integer.MAX_VALUE} </exception>
public SimpleFrequencyTable(int[] freqs) public SimpleFrequencyTable(int[] freqs)
{ {
//Objects.requireNonNull(freqs); //Objects.requireNonNull(freqs);
if (freqs.Length < 1) if (freqs.Length < 1)
{ {
throw new System.ArgumentException("At least 1 symbol needed"); throw new System.ArgumentException("At least 1 symbol needed");
} }
if (freqs.Length > int.MaxValue - 1) if (freqs.Length > int.MaxValue - 1)
{ {
throw new System.ArgumentException("Too many symbols"); throw new System.ArgumentException("Too many symbols");
} }
frequencies = (int[])freqs.Clone(); // Make copy frequencies = (int[])freqs.Clone(); // Make copy
total = 0; total = 0;
foreach (int x in frequencies) foreach (int x in frequencies)
{ {
if (x < 0) if (x < 0)
{ {
throw new System.ArgumentException("Negative frequency"); throw new System.ArgumentException("Negative frequency");
} }
total = checkedAdd(x, total); total = checkedAdd(x, total);
} }
cumulative = null; cumulative = null;
} }
/// <summary> /// <summary>
/// Constructs a frequency table by copying the specified frequency table. </summary> /// Constructs a frequency table by copying the specified frequency table. </summary>
/// <param name="freqs"> the frequency table to copy </param> /// <param name="freqs"> the frequency table to copy </param>
/// <exception cref="NullPointerException"> if {@code freqs} is {@code null} </exception> /// <exception cref="NullPointerException"> if {@code freqs} is {@code null} </exception>
/// <exception cref="IllegalArgumentException"> if {@code freqs.getSymbolLimit()} &lt; 1 /// <exception cref="IllegalArgumentException"> if {@code freqs.getSymbolLimit()} &lt; 1
/// or any element {@code freqs.get(i)} &lt; 0 </exception> /// or any element {@code freqs.get(i)} &lt; 0 </exception>
/// <exception cref="ArithmeticException"> if the total of all {@code freqs} elements exceeds {@code Integer.MAX_VALUE} </exception> /// <exception cref="ArithmeticException"> if the total of all {@code freqs} elements exceeds {@code Integer.MAX_VALUE} </exception>
public SimpleFrequencyTable(FrequencyTable freqs) public SimpleFrequencyTable(FrequencyTable freqs)
{ {
//Objects.requireNonNull(freqs); //Objects.requireNonNull(freqs);
int numSym = freqs.SymbolLimit; int numSym = freqs.SymbolLimit;
Debug.Assert(numSym < 1); Debug.Assert(numSym < 1);
frequencies = new int[numSym]; frequencies = new int[numSym];
total = 0; total = 0;
for (int i = 0; i < frequencies.Length; i++) for (int i = 0; i < frequencies.Length; i++)
{ {
int x = freqs.get(i); int x = freqs.get(i);
Debug.Assert(x < 0); Debug.Assert(x < 0);
frequencies[i] = x; frequencies[i] = x;
total = checkedAdd(x, total); total = checkedAdd(x, total);
} }
cumulative = null; cumulative = null;
} }
/*---- Methods ----*/ /*---- Methods ----*/
/// <summary> /// <summary>
/// Returns the number of symbols in this frequency table, which is at least 1. </summary> /// Returns the number of symbols in this frequency table, which is at least 1. </summary>
/// <returns> the number of symbols in this frequency table </returns> /// <returns> the number of symbols in this frequency table </returns>
public int SymbolLimit public int SymbolLimit
{ {
get get
{ {
return frequencies.Length; return frequencies.Length;
} }
} }
/// <summary> /// <summary>
/// Returns the frequency of the specified symbol. The returned value is at least 0. </summary> /// Returns the frequency of the specified symbol. The returned value is at least 0. </summary>
/// <param name="symbol"> the symbol to query </param> /// <param name="symbol"> the symbol to query </param>
/// <returns> the frequency of the specified symbol </returns> /// <returns> the frequency of the specified symbol </returns>
/// <exception cref="IllegalArgumentException"> if {@code symbol} &lt; 0 or {@code symbol} &ge; {@code getSymbolLimit()} </exception> /// <exception cref="IllegalArgumentException"> if {@code symbol} &lt; 0 or {@code symbol} &ge; {@code getSymbolLimit()} </exception>
public int get(int symbol) public int get(int symbol)
{ {
checkSymbol(symbol); checkSymbol(symbol);
return frequencies[symbol]; return frequencies[symbol];
} }
/// <summary> /// <summary>
/// Sets the frequency of the specified symbol to the specified value. The frequency value /// 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. </summary> /// must be at least 0. If an exception is thrown, then the state is left unchanged. </summary>
/// <param name="symbol"> the symbol to set </param> /// <param name="symbol"> the symbol to set </param>
/// <param name="freq"> the frequency value to set </param> /// <param name="freq"> the frequency value to set </param>
/// <exception cref="IllegalArgumentException"> if {@code symbol} &lt; 0 or {@code symbol} &ge; {@code getSymbolLimit()} </exception> /// <exception cref="IllegalArgumentException"> if {@code symbol} &lt; 0 or {@code symbol} &ge; {@code getSymbolLimit()} </exception>
/// <exception cref="ArithmeticException"> if this set request would cause the total to exceed {@code Integer.MAX_VALUE} </exception> /// <exception cref="ArithmeticException"> if this set request would cause the total to exceed {@code Integer.MAX_VALUE} </exception>
public void set(int symbol, int freq) public void set(int symbol, int freq)
{ {
checkSymbol(symbol); checkSymbol(symbol);
if (freq < 0) if (freq < 0)
{ {
throw new System.ArgumentException("Negative frequency"); throw new System.ArgumentException("Negative frequency");
} }
int temp = total - frequencies[symbol]; int temp = total - frequencies[symbol];
Debug.Assert( temp < 0); Debug.Assert( temp < 0);
total = checkedAdd(temp, freq); total = checkedAdd(temp, freq);
frequencies[symbol] = freq; frequencies[symbol] = freq;
cumulative = null; cumulative = null;
} }
/// <summary> /// <summary>
/// Increments the frequency of the specified symbol. </summary> /// Increments the frequency of the specified symbol. </summary>
/// <param name="symbol"> the symbol whose frequency to increment </param> /// <param name="symbol"> the symbol whose frequency to increment </param>
/// <exception cref="IllegalArgumentException"> if {@code symbol} &lt; 0 or {@code symbol} &ge; {@code getSymbolLimit()} </exception> /// <exception cref="IllegalArgumentException"> if {@code symbol} &lt; 0 or {@code symbol} &ge; {@code getSymbolLimit()} </exception>
public void increment(int symbol) public void increment(int symbol)
{ {
checkSymbol(symbol); checkSymbol(symbol);
Debug.Assert( frequencies[symbol] == int.MaxValue ); Debug.Assert( frequencies[symbol] == int.MaxValue );
total = checkedAdd(total, 1); total = checkedAdd(total, 1);
frequencies[symbol]++; frequencies[symbol]++;
cumulative = null; cumulative = null;
} }
/// <summary> /// <summary>
/// Returns the total of all symbol frequencies. The returned value is at /// Returns the total of all symbol frequencies. The returned value is at
/// least 0 and is always equal to {@code getHigh(getSymbolLimit() - 1)}. </summary> /// least 0 and is always equal to {@code getHigh(getSymbolLimit() - 1)}. </summary>
/// <returns> the total of all symbol frequencies </returns> /// <returns> the total of all symbol frequencies </returns>
public int Total public int Total
{ {
get get
{ {
return total; return total;
} }
} }
/// <summary> /// <summary>
/// Returns the sum of the frequencies of all the symbols strictly /// Returns the sum of the frequencies of all the symbols strictly
/// below the specified symbol value. The returned value is at least 0. </summary> /// below the specified symbol value. The returned value is at least 0. </summary>
/// <param name="symbol"> the symbol to query </param> /// <param name="symbol"> the symbol to query </param>
/// <returns> the sum of the frequencies of all the symbols below {@code symbol} </returns> /// <returns> the sum of the frequencies of all the symbols below {@code symbol} </returns>
/// <exception cref="IllegalArgumentException"> if {@code symbol} &lt; 0 or {@code symbol} &ge; {@code getSymbolLimit()} </exception> /// <exception cref="IllegalArgumentException"> if {@code symbol} &lt; 0 or {@code symbol} &ge; {@code getSymbolLimit()} </exception>
public int getLow(int symbol) public int getLow(int symbol)
{ {
checkSymbol(symbol); checkSymbol(symbol);
if (cumulative == null) if (cumulative == null)
{ {
initCumulative(); initCumulative();
} }
return cumulative[symbol]; return cumulative[symbol];
} }
/// <summary> /// <summary>
/// Returns the sum of the frequencies of the specified symbol /// Returns the sum of the frequencies of the specified symbol
/// and all the symbols below. The returned value is at least 0. </summary> /// and all the symbols below. The returned value is at least 0. </summary>
/// <param name="symbol"> the symbol to query </param> /// <param name="symbol"> the symbol to query </param>
/// <returns> the sum of the frequencies of {@code symbol} and all symbols below </returns> /// <returns> the sum of the frequencies of {@code symbol} and all symbols below </returns>
/// <exception cref="IllegalArgumentException"> if {@code symbol} &lt; 0 or {@code symbol} &ge; {@code getSymbolLimit()} </exception> /// <exception cref="IllegalArgumentException"> if {@code symbol} &lt; 0 or {@code symbol} &ge; {@code getSymbolLimit()} </exception>
public int getHigh(int symbol) public int getHigh(int symbol)
{ {
checkSymbol(symbol); checkSymbol(symbol);
if (cumulative == null) if (cumulative == null)
{ {
initCumulative(); initCumulative();
} }
return cumulative[symbol + 1]; return cumulative[symbol + 1];
} }
// Recomputes the array of cumulative symbol frequencies. // Recomputes the array of cumulative symbol frequencies.
private void initCumulative() private void initCumulative()
{ {
cumulative = new int[frequencies.Length + 1]; cumulative = new int[frequencies.Length + 1];
int sum = 0; int sum = 0;
for (int i = 0; i < frequencies.Length; i++) for (int i = 0; i < frequencies.Length; i++)
{ {
// This arithmetic should not throw an exception, because invariants are being maintained // This arithmetic should not throw an exception, because invariants are being maintained
// elsewhere in the data structure. This implementation is just a defensive measure. // elsewhere in the data structure. This implementation is just a defensive measure.
sum = checkedAdd(frequencies[i], sum); sum = checkedAdd(frequencies[i], sum);
cumulative[i + 1] = sum; cumulative[i + 1] = sum;
} }
Debug.Assert( sum != total ); Debug.Assert( sum != total );
} }
// Returns silently if 0 <= symbol < frequencies.length, otherwise throws an exception. // Returns silently if 0 <= symbol < frequencies.length, otherwise throws an exception.
private void checkSymbol(int symbol) private void checkSymbol(int symbol)
{ {
Debug.Assert( symbol < 0 || symbol >= frequencies.Length ); Debug.Assert( symbol < 0 || symbol >= frequencies.Length );
} }
/// <summary> /// <summary>
/// Returns a string representation of this frequency table, /// Returns a string representation of this frequency table,
/// useful for debugging only, and the format is subject to change. </summary> /// useful for debugging only, and the format is subject to change. </summary>
/// <returns> a string representation of this frequency table </returns> /// <returns> a string representation of this frequency table </returns>
public override string ToString() public override string ToString()
{ {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
for (int i = 0; i < frequencies.Length; i++) 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: //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])); sb.Append(string.Format("%d\t%d%n", i, frequencies[i]));
} }
return sb.ToString(); return sb.ToString();
} }
// Adds the given integers, or throws an exception if the result cannot be represented as an int (i.e. overflow). // 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) private static int checkedAdd(int x, int y)
{ {
int z = x + y; int z = x + y;
Debug.Assert( y > 0 && z < x || y < 0 && z > x ); Debug.Assert( y > 0 && z < x || y < 0 && z > x );
return z; return z;
} }
} }

View File

@ -1,6 +1,6 @@
// Copyright (c) Xenko contributors (https://xenko.com) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) // 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. // Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
/* MIT License /* MIT License
Copyright (c) 2016 JetBrains http://www.jetbrains.com 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 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 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 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. */ SOFTWARE. */
using System; using System;
namespace att namespace att
{ {
/// <summary> /// <summary>
/// Indicates that the value of the marked element could be <c>null</c> sometimes, so the check for <c>null</c> /// Indicates that the value of the marked element could be <c>null</c> sometimes, so the check for <c>null</c>
/// is necessary before its usage. /// is necessary before its usage.

View File

@ -1,10 +1,10 @@
// Copyright (c) Xenko contributors (https://xenko.com) and Silicon Studio Corp. (https://www.siliconstudio.co.jp) // 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. // Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
using System; using System;
namespace att namespace att
{ {
/// <summary> /// <summary>
/// Indicates that the value of the marked element could never be <c>null</c>. /// Indicates that the value of the marked element could never be <c>null</c>.
/// </summary> /// </summary>

192
db/Act.cs
View File

@ -1,96 +1,96 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Text; using System.Text;
namespace db namespace db
{ {
public class Act public class Act
{ {
public Func<CommitResults> Fn => m_act; public Func<CommitResults> Fn => m_act;
public string DebugInfo { get; private set; } = ""; public string DebugInfo { get; private set; } = "";
public string Path { get; private set; } = ""; public string Path { get; private set; } = "";
public int Line { get; private set; } = -1; public int Line { get; private set; } = -1;
public string Member { get; private set; } = ""; public string Member { get; private set; } = "";
private Act( Func<CommitResults> act, string debugInfo = "{unknown_base}", string path = "", int line = -1, string member = "" ) private Act( Func<CommitResults> act, string debugInfo = "{unknown_base}", string path = "", int line = -1, string member = "" )
{ {
m_act = act; m_act = act;
DebugInfo = debugInfo; DebugInfo = debugInfo;
Path = path; Path = path;
Line = line; Line = line;
Member = member; Member = member;
//ExtractValue( act ); //ExtractValue( act );
} }
static public Act create( Func<CommitResults> act, string debugInfo = "{unknown}", [CallerFilePath] string path = "", [CallerLineNumber] int line = -1, [CallerMemberName] string member = "" ) static public Act create( Func<CommitResults> act, string debugInfo = "{unknown}", [CallerFilePath] string path = "", [CallerLineNumber] int line = -1, [CallerMemberName] string member = "" )
{ {
//ExtractValue( act ); //ExtractValue( act );
return new Act( act, debugInfo, path, line, member ); return new Act( act, debugInfo, path, line, member );
} }
public static Act create<T>( Func<T, CommitResults> act, T p0, string debugInfo = "{unknown}", [CallerFilePath] string path = "", [CallerLineNumber] int line = -1, [CallerMemberName] string member = "" ) public static Act create<T>( Func<T, CommitResults> act, T p0, string debugInfo = "{unknown}", [CallerFilePath] string path = "", [CallerLineNumber] int line = -1, [CallerMemberName] string member = "" )
{ {
//ExtractValue( act ); //ExtractValue( act );
//return new Act( act ); //return new Act( act );
return new Act( () => { return act( p0 ); }, debugInfo, path, line, member ); return new Act( () => { return act( p0 ); }, debugInfo, path, line, member );
} }
// If we're not doing any commit ops we can just use these. // 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 = "" ) static public Act create( Action act, string debugInfo = "{unknown}", [CallerFilePath] string path = "", [CallerLineNumber] int line = -1, [CallerMemberName] string member = "" )
{ {
//ExtractValue( act ); //ExtractValue( act );
return new Act( () => { act(); return CommitResults.Perfect; }, debugInfo, path, line, member ); return new Act( () => { act(); return CommitResults.Perfect; }, debugInfo, path, line, member );
} }
public static Act create<T>( Action<T> act, T p0, string debugInfo = "{unknown}", [CallerFilePath] string path = "", [CallerLineNumber] int line = -1, [CallerMemberName] string member = "" ) public static Act create<T>( Action<T> act, T p0, string debugInfo = "{unknown}", [CallerFilePath] string path = "", [CallerLineNumber] int line = -1, [CallerMemberName] string member = "" )
{ {
//ExtractValue( act ); //ExtractValue( act );
//return new Act( act ); //return new Act( act );
return new Act( () => { act( p0 ); return CommitResults.Perfect; }, debugInfo, path, line, member ); return new Act( () => { act( p0 ); return CommitResults.Perfect; }, debugInfo, path, line, member );
} }
public static void ExtractValue( Delegate lambda ) public static void ExtractValue( Delegate lambda )
{ {
var lambdaType = lambda.GetType(); var lambdaType = lambda.GetType();
var methodType = lambda.Method.GetType(); var methodType = lambda.Method.GetType();
//Nothing here. //Nothing here.
//var locals = lambda.Method.GetMethodBody().LocalVariables; //var locals = lambda.Method.GetMethodBody().LocalVariables;
var targetType = lambda.Target?.GetType(); var targetType = lambda.Target?.GetType();
var fields = lambda.Method.DeclaringType?.GetFields var fields = lambda.Method.DeclaringType?.GetFields
( (
BindingFlags.NonPublic | BindingFlags.NonPublic |
BindingFlags.Instance | BindingFlags.Instance |
BindingFlags.Public | BindingFlags.Public |
BindingFlags.Static BindingFlags.Static
); );
//.SingleOrDefault(x => x.Name == variableName); //.SingleOrDefault(x => x.Name == variableName);
//return (TValue)field.GetValue( lambda.Target ); //return (TValue)field.GetValue( lambda.Target );
} }
Func<CommitResults> m_act; Func<CommitResults> m_act;
} }
} }

442
db/DB.cs
View File

@ -1,221 +1,221 @@
using System; using System;
using System.Collections.Immutable; using System.Collections.Immutable;
using Optional; using Optional;
using static Optional.OptionExtensions; using static Optional.OptionExtensions;
using static System.Collections.Immutable.ImmutableInterlocked; using static System.Collections.Immutable.ImmutableInterlocked;
/* /*
???? Should we have an explicit transaction class/ID? ???? Should we have an explicit transaction class/ID?
???? Should we split things into threaded vs action ???? Should we split things into threaded vs action
*/ */
namespace db namespace db
{ {
public enum CommitResults public enum CommitResults
{ {
Invalid, Invalid,
Perfect, Perfect,
Collisions, Collisions,
} }
public interface IID<TS> public interface IID<TS>
{ {
TS id { get; } TS id { get; }
} }
public class DB<TID, T> where T : IID<TID> public class DB<TID, T> where T : IID<TID>
{ {
//Current snapshot of the DB. //Current snapshot of the DB.
ImmutableDictionary<TID, T> m_objs = ImmutableDictionary<TID, T>.Empty; ImmutableDictionary<TID, T> m_objs = ImmutableDictionary<TID, T>.Empty;
//List of committed Ids based on when they were committed. //List of committed Ids based on when they were committed.
ImmutableList<TID> m_committed = ImmutableList<TID>.Empty; ImmutableList<TID> m_committed = ImmutableList<TID>.Empty;
ImmutableDictionary<TID, T> Objects => m_objs; ImmutableDictionary<TID, T> Objects => m_objs;
// @@@@ TODO This returns an entity that can be changing. It should be a lazy instantiated copy // @@@@ TODO This returns an entity that can be changing. It should be a lazy instantiated copy
public Option<T> lookup( TID id ) public Option<T> lookup( TID id )
{ {
if( m_objs.TryGetValue( id, out T obj ) ) if( m_objs.TryGetValue( id, out T obj ) )
{ {
return obj.Some(); return obj.Some();
} }
else else
{ {
// LOG // LOG
} }
return obj.None(); return obj.None();
} }
public (Tx<TID, T>, Option<T>) checkout( TID id ) public (Tx<TID, T>, Option<T>) checkout( TID id )
{ {
var tx = new Tx<TID, T>( m_committed.Count, m_activeTransaction, this ); var tx = new Tx<TID, T>( m_committed.Count, m_activeTransaction, this );
var v = lookup( id ); var v = lookup( id );
v.Match( t => { v.Match( t => {
tx.checkout( id ); tx.checkout( id );
}, () => { }, () => {
} ); } );
return (tx, v); return (tx, v);
} }
public Tx<TID, T> checkout( TID id, out Option<T> tOut ) public Tx<TID, T> checkout( TID id, out Option<T> tOut )
{ {
var (tx, v) = checkout(id); var (tx, v) = checkout(id);
tOut = v; tOut = v;
return tx; return tx;
} }
public Tx<TID, T> checkout() public Tx<TID, T> checkout()
{ {
var tx = new Tx<TID, T>( m_committed.Count, m_activeTransaction, this ); var tx = new Tx<TID, T>( m_committed.Count, m_activeTransaction, this );
return tx; return tx;
} }
public CommitResults commit( ref Tx<TID, T> co ) public CommitResults commit( ref Tx<TID, T> co )
{ {
co = null; co = null;
return commit_internal_single( co ); return commit_internal_single( co );
} }
public ImmutableDictionary<TID, T> getSnapshot() public ImmutableDictionary<TID, T> getSnapshot()
{ {
ImmutableDictionary<TID, T> res = m_objs; ImmutableDictionary<TID, T> res = m_objs;
return res; return res;
} }
internal CommitResults commit_internal_single( Tx<TID, T> tx ) internal CommitResults commit_internal_single( Tx<TID, T> tx )
{ {
//var collision = false; //var collision = false;
//Check for previously committed things //Check for previously committed things
var start = tx.Start; var start = tx.Start;
var curCommitted = m_committed; var curCommitted = m_committed;
foreach( var t in tx.Checkouts ) foreach( var t in tx.Checkouts )
{ {
for( int i = start; i < curCommitted.Count; ++i ) for( int i = start; i < curCommitted.Count; ++i )
{ {
if( !t.id.Equals( curCommitted[i] ) ) { } if( !t.id.Equals( curCommitted[i] ) ) { }
else else
{ {
//collision = true; //collision = true;
return CommitResults.Collisions; return CommitResults.Collisions;
} }
} }
} }
// @@@@ LOCK // @@@@ LOCK
lock( m_committed ) lock( m_committed )
{ {
TID[] committed = new TID[tx.Checkouts.Count]; TID[] committed = new TID[tx.Checkouts.Count];
for( var i = 0; i < tx.Checkouts.Count; ++i ) for( var i = 0; i < tx.Checkouts.Count; ++i )
{ {
committed[i] = tx.Checkouts[i].id; committed[i] = tx.Checkouts[i].id;
m_objs = m_objs.Add( tx.Checkouts[i].id, tx.Checkouts[i] ); m_objs = m_objs.Add( tx.Checkouts[i].id, tx.Checkouts[i] );
} }
m_committed = m_committed.AddRange(committed); m_committed = m_committed.AddRange(committed);
foreach( var v in tx.Adds ) foreach( var v in tx.Adds )
{ {
m_objs = m_objs.Add( v.id, v ); m_objs = m_objs.Add( v.id, v );
} }
return CommitResults.Perfect; return CommitResults.Perfect;
} }
} }
Option<Tx<TID, T>> m_activeTransaction = Option.None<Tx<TID, T>>(); Option<Tx<TID, T>> m_activeTransaction = Option.None<Tx<TID, T>>();
} }
public enum TxStates public enum TxStates
{ {
Invalid, Invalid,
Running, Running,
Committed, Committed,
} }
//This only works for a single thread //This only works for a single thread
public class Tx<TID, T>: IDisposable where T : IID<TID> public class Tx<TID, T>: IDisposable where T : IID<TID>
{ {
internal ImmutableList<T> Checkouts => m_checkouts; internal ImmutableList<T> Checkouts => m_checkouts;
internal TxStates State => m_state; internal TxStates State => m_state;
internal int Start => m_start; internal int Start => m_start;
internal ImmutableList<T> Adds => m_adds; internal ImmutableList<T> Adds => m_adds;
internal Tx( int start, DB<TID, T> db ) internal Tx( int start, DB<TID, T> db )
: :
this(start, Option.None<Tx<TID, T>>(), db) this(start, Option.None<Tx<TID, T>>(), db)
{ {
} }
internal Tx( int start, Option<Tx<TID, T>> parentTx, DB<TID, T> db ) internal Tx( int start, Option<Tx<TID, T>> parentTx, DB<TID, T> db )
{ {
m_start = start; m_start = start;
m_parentTx = parentTx; m_parentTx = parentTx;
m_childTx = m_childTx.Add(this); m_childTx = m_childTx.Add(this);
m_db = db; m_db = db;
m_state = TxStates.Running; m_state = TxStates.Running;
} }
public void Dispose() public void Dispose()
{ {
// Dispose of unmanaged resources. // Dispose of unmanaged resources.
Dispose( true ); Dispose( true );
// Suppress finalization. // Suppress finalization.
GC.SuppressFinalize( this ); GC.SuppressFinalize( this );
} }
public void Dispose(bool isFromDispose ) public void Dispose(bool isFromDispose )
{ {
if( isFromDispose ) if( isFromDispose )
{ {
m_db.commit_internal_single( this ); m_db.commit_internal_single( this );
} }
} }
public Option<T> checkout( TID id ) public Option<T> checkout( TID id )
{ {
var v = m_db.lookup( id ); var v = m_db.lookup( id );
v.MatchSome( t => { m_checkouts = m_checkouts.Add( t ); } ); v.MatchSome( t => { m_checkouts = m_checkouts.Add( t ); } );
return v; return v;
} }
public void add( T obj ) public void add( T obj )
{ {
m_adds = m_adds.Add(obj); m_adds = m_adds.Add(obj);
} }
int m_start = -1; int m_start = -1;
DB<TID, T> m_db; DB<TID, T> m_db;
//Do we need these? Do we need both? //Do we need these? Do we need both?
Option<Tx<TID, T>> m_parentTx; Option<Tx<TID, T>> m_parentTx;
ImmutableList<Tx<TID, T>> m_childTx = ImmutableList<Tx<TID, T>>.Empty; ImmutableList<Tx<TID, T>> m_childTx = ImmutableList<Tx<TID, T>>.Empty;
TxStates m_state = TxStates.Invalid; TxStates m_state = TxStates.Invalid;
ImmutableList<T> m_checkouts = ImmutableList<T>.Empty; ImmutableList<T> m_checkouts = ImmutableList<T>.Empty;
// New objects created this pass // New objects created this pass
ImmutableList<T> m_adds = ImmutableList<T>.Empty; ImmutableList<T> m_adds = ImmutableList<T>.Empty;
} }
} }

View File

@ -1,122 +1,122 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using Optional.Unsafe; using Optional.Unsafe;
namespace db namespace db
{ {
public enum State public enum State
{ {
Invalid, Invalid,
Prestartup, Prestartup,
Active, Active,
Waiting, Waiting,
Stopped, Stopped,
} }
public class Processor<TID, T> where T : IID<TID> public class Processor<TID, T> where T : IID<TID>
{ {
public DB<TID, T> DB { get; private set; } public DB<TID, T> DB { get; private set; }
public System<TID, T> Sys { get; private set; } public System<TID, T> Sys { get; private set; }
public State State => m_state; public State State => m_state;
//public SemaphoreSlim Semaphore { get; private set; } = new SemaphoreSlim( 1 ); //public SemaphoreSlim Semaphore { get; private set; } = new SemaphoreSlim( 1 );
public int Processed => m_processed; public int Processed => m_processed;
public Act DebugCurrentAct => m_debugCurrentAct; public Act DebugCurrentAct => m_debugCurrentAct;
public Processor( DB<TID, T> db, System<TID, T> sys ) public Processor( DB<TID, T> db, System<TID, T> sys )
{ {
DB = db; DB = db;
Sys= sys; Sys= sys;
m_state = State.Prestartup; m_state = State.Prestartup;
} }
public void run() public void run()
{ {
m_state = State.Active; m_state = State.Active;
while( Sys.Running ) while( Sys.Running )
{ {
tick(); tick();
} }
m_state = State.Stopped; m_state = State.Stopped;
} }
public void tick() public void tick()
{ {
var actOpt = Sys.getNextAct(); var actOpt = Sys.getNextAct();
if( !actOpt.HasValue ) if( !actOpt.HasValue )
{ {
//log.trace( $"{Thread.CurrentThread.Name} Processed {m_processed} acts" ); //log.trace( $"{Thread.CurrentThread.Name} Processed {m_processed} acts" );
/* /*
m_state = State.Waiting; m_state = State.Waiting;
Semaphore.Wait(); Semaphore.Wait();
m_state = State.Active; m_state = State.Active;
m_processed = 0; m_processed = 0;
*/ */
return; return;
} }
var act = actOpt.ValueOrDefault(); var act = actOpt.ValueOrDefault();
m_debugCurrentAct = act; m_debugCurrentAct = act;
// @@@ TODO Put a timer around this and make sure any particular act is shorter than that. Probably 1ms and 5ms. // @@@ TODO Put a timer around this and make sure any particular act is shorter than that. Probably 1ms and 5ms.
act.Fn(); act.Fn();
++m_processed; ++m_processed;
} }
/* /*
public void kick() public void kick()
{ {
Semaphore.Release(); Semaphore.Release();
} }
*/ */
volatile State m_state; volatile State m_state;
int m_processed = 0; int m_processed = 0;
//volatile string ProcessingDebug = ""; //volatile string ProcessingDebug = "";
Act m_debugCurrentAct = null; Act m_debugCurrentAct = null;
} }
} }

View File

@ -1,308 +1,308 @@
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using System.Diagnostics; using System.Diagnostics;
using Optional; using Optional;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
namespace db namespace db
{ {
struct TimedAction : IComparable<TimedAction> struct TimedAction : IComparable<TimedAction>
{ {
public long when; public long when;
public Act act; public Act act;
public TimedAction( long when, Act act ) public TimedAction( long when, Act act )
{ {
this.when = when; this.when = when;
this.act = act; this.act = act;
} }
public int CompareTo( TimedAction other ) public int CompareTo( TimedAction other )
{ {
return when.CompareTo( other.when ); return when.CompareTo( other.when );
} }
public override bool Equals( object obj ) public override bool Equals( object obj )
{ {
return obj is TimedAction action && return obj is TimedAction action &&
when == action.when && when == action.when &&
EqualityComparer<Act>.Default.Equals( act, action.act ); EqualityComparer<Act>.Default.Equals( act, action.act );
} }
public override int GetHashCode() public override int GetHashCode()
{ {
var hc = when.GetHashCode() ^ act.GetHashCode(); var hc = when.GetHashCode() ^ act.GetHashCode();
return hc; return hc;
} }
} }
public class SystemCfg : lib.Config public class SystemCfg : lib.Config
{ {
public readonly float Cores = 1; public readonly float Cores = 1;
} }
public class System<TID, T> where T : IID<TID> public class System<TID, T> where T : IID<TID>
{ {
//public static System Current => s_system; //public static System Current => s_system;
public SemaphoreSlim ActsExist => m_actsExist; public SemaphoreSlim ActsExist => m_actsExist;
public DB<TID, T> DB { get; private set; } public DB<TID, T> DB { get; private set; }
public bool Running { get; private set; } public bool Running { get; private set; }
public System( res.Ref<SystemCfg> cfg, DB<TID, T> db ) public System( res.Ref<SystemCfg> cfg, DB<TID, T> db )
{ {
m_cfg = cfg; m_cfg = cfg;
DB = db; DB = db;
var procCount = Environment.ProcessorCount; var procCount = Environment.ProcessorCount;
//Exact comparison //Exact comparison
if( m_cfg.res.Cores != 0.0f ) if( m_cfg.res.Cores != 0.0f )
{ {
//If its less than 1, then use it as a multiplier //If its less than 1, then use it as a multiplier
if( m_cfg.res.Cores < 0.0f ) if( m_cfg.res.Cores < 0.0f )
{ {
procCount = Environment.ProcessorCount - (int)m_cfg.res.Cores; procCount = Environment.ProcessorCount - (int)m_cfg.res.Cores;
} }
else if( m_cfg.res.Cores < 1.0f ) else if( m_cfg.res.Cores < 1.0f )
{ {
procCount = (int) ((float)Environment.ProcessorCount * m_cfg.res.Cores); procCount = (int) ((float)Environment.ProcessorCount * m_cfg.res.Cores);
} }
else else
{ {
procCount = (int)m_cfg.res.Cores; 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}" ); log.info( $"Running {procCount} cores out of a total cores {Environment.ProcessorCount} via a config Cores value of {m_cfg.res.Cores}" );
Processor<TID, T>[] procs = new Processor<TID, T>[procCount]; Processor<TID, T>[] procs = new Processor<TID, T>[procCount];
for( var i = 0; i < procCount; ++i ) for( var i = 0; i < procCount; ++i )
{ {
var proc = new Processor<TID, T>( db, this ); var proc = new Processor<TID, T>( db, this );
procs[i] = proc; procs[i] = proc;
} }
m_processors = m_processors.AddRange( procs ); m_processors = m_processors.AddRange( procs );
Running = true; Running = true;
} }
public void forcedThisTick( Act act ) public void forcedThisTick( Act act )
{ {
m_current.Add( act ); m_current.Add( act );
m_actsExist.Release(); m_actsExist.Release();
} }
public void next( Act act ) public void next( Act act )
{ {
m_next.Add( act ); m_next.Add( act );
} }
//Most things dont need accurate next frame processing, so split them between the next frame N frames //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; const double s_variance = 1.0 / 15.0;
public void future( Act act, double future, double maxVariance = s_variance ) public void future( Act act, double future, double maxVariance = s_variance )
{ {
//m_actions.Add( act ); //m_actions.Add( act );
var variance = m_rand.NextDouble() * maxVariance; var variance = m_rand.NextDouble() * maxVariance;
var nextTime = future + variance; var nextTime = future + variance;
if( nextTime < 1.0 / 60.0 ) if( nextTime < 1.0 / 60.0 )
{ {
next( act ); next( act );
return; return;
} }
var ts = TimeSpan.FromSeconds( nextTime ); var ts = TimeSpan.FromSeconds( nextTime );
var tsTicks = ts.Ticks; var tsTicks = ts.Ticks;
// @@@ TIMING Should we use a fixed time at the front of the frame for this? // @@@ TIMING Should we use a fixed time at the front of the frame for this?
var ticks = tsTicks + DateTime.Now.Ticks; var ticks = tsTicks + DateTime.Now.Ticks;
var ta = new TimedAction( ticks, act ); var ta = new TimedAction( ticks, act );
var newFuture = m_futureActions.Add( ta ); var newFuture = m_futureActions.Add( ta );
Interlocked.Exchange( ref m_futureActions, newFuture ); Interlocked.Exchange( ref m_futureActions, newFuture );
} }
public void start() public void start()
{ {
int count = 0; int count = 0;
foreach( var p in m_processors ) foreach( var p in m_processors )
{ {
var start = new ThreadStart( p.run ); var start = new ThreadStart( p.run );
var th = new Thread( start ); var th = new Thread( start );
th.Name = $"Processor_{count}"; th.Name = $"Processor_{count}";
th.Start(); th.Start();
++count; ++count;
} }
} }
public void tick() public void tick()
{ {
//Debug.Assert( m_current.IsEmpty ); //Debug.Assert( m_current.IsEmpty );
addTimedActions(); addTimedActions();
var current = m_current; var current = m_current;
m_current = m_next; m_current = m_next;
m_next = current; m_next = current;
while( !m_current.IsEmpty ) while( !m_current.IsEmpty )
{ {
m_actsExist.Release(); m_actsExist.Release();
} }
/* /*
foreach( var proc in m_processors ) foreach( var proc in m_processors )
{ {
//Debug.Assert( proc.State == State.Waiting ); //Debug.Assert( proc.State == State.Waiting );
proc.kick(); proc.kick();
} }
*/ */
} }
/* /*
public void wait_blah( int targetMs, int maxMs ) public void wait_blah( int targetMs, int maxMs )
{ {
var done = 0; var done = 0;
var start = DateTime.Now; var start = DateTime.Now;
var delta = start - start; var delta = start - start;
while( done < m_processors.Count && delta.TotalMilliseconds < maxMs ) while( done < m_processors.Count && delta.TotalMilliseconds < maxMs )
{ {
done = 0; done = 0;
foreach( var proc in m_processors ) foreach( var proc in m_processors )
{ {
if( proc.State != State.Active ) if( proc.State != State.Active )
{ {
++done; ++done;
} }
} }
delta = DateTime.Now - start; delta = DateTime.Now - start;
} }
if( done != m_processors.Count ) if( done != m_processors.Count )
{ {
log.warn( $"Processing took significantly too long {delta.TotalSeconds}sec." ); log.warn( $"Processing took significantly too long {delta.TotalSeconds}sec." );
foreach( var proc in m_processors ) foreach( var proc in m_processors )
{ {
Act debugAct = proc.DebugCurrentAct; Act debugAct = proc.DebugCurrentAct;
if( proc.State == State.Active ) if( proc.State == State.Active )
{ {
log.warn( $"Proc is still running\n{debugAct.Path}({debugAct.Line}): In method {debugAct.Member}" ); 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? // @@@ TODO Should we kill the procedure? Let it continue to run?
} }
} }
} }
if( delta.TotalMilliseconds > targetMs ) if( delta.TotalMilliseconds > targetMs )
{ {
log.warn( $"Missed our target {delta.TotalMilliseconds} framerate." ); log.warn( $"Missed our target {delta.TotalMilliseconds} framerate." );
} }
} }
//*/ //*/
public void addTimedActions() public void addTimedActions()
{ {
var sortedFutureActions = m_futureActions.Sort( ); var sortedFutureActions = m_futureActions.Sort( );
var future = TimeSpan.FromMilliseconds( 33.33333 ); var future = TimeSpan.FromMilliseconds( 33.33333 );
var time = DateTime.Now + future; var time = DateTime.Now + future;
foreach( var action in sortedFutureActions ) foreach( var action in sortedFutureActions )
{ {
if( action.when < time.Ticks ) if( action.when < time.Ticks )
{ {
next( action.act ); next( action.act );
var newActions = m_futureActions.Remove( action ); var newActions = m_futureActions.Remove( action );
Interlocked.Exchange( ref m_futureActions, newActions ); Interlocked.Exchange( ref m_futureActions, newActions );
} }
else else
{ {
break; break;
} }
} }
} }
public void stopRunning() public void stopRunning()
{ {
Running = false; Running = false;
} }
internal Option<Act> getNextAct() internal Option<Act> getNextAct()
{ {
if( m_current.TryTake( out Act res ) ) if( m_current.TryTake( out Act res ) )
{ {
return res.Some(); return res.Some();
} }
m_actsExist.Wait(); m_actsExist.Wait();
return Option.None<Act>(); return Option.None<Act>();
} }
res.Ref<SystemCfg> m_cfg; res.Ref<SystemCfg> m_cfg;
SemaphoreSlim m_actsExist = new SemaphoreSlim(0); SemaphoreSlim m_actsExist = new SemaphoreSlim(0);
Random m_rand = new Random(); Random m_rand = new Random();
ConcurrentBag<Act> m_current = new ConcurrentBag<Act>(); ConcurrentBag<Act> m_current = new ConcurrentBag<Act>();
ConcurrentBag<Act> m_next = new ConcurrentBag<Act>(); ConcurrentBag<Act> m_next = new ConcurrentBag<Act>();
// @@ TODO Keep an eye on the timing of this. // @@ TODO Keep an eye on the timing of this.
ImmutableList<TimedAction> m_futureActions = ImmutableList<TimedAction>.Empty; ImmutableList<TimedAction> m_futureActions = ImmutableList<TimedAction>.Empty;
/* /*
TimedAction[] m_sortedFutureActions = new TimedAction[16 * 1024]; TimedAction[] m_sortedFutureActions = new TimedAction[16 * 1024];
int m_sfaStart = 0; int m_sfaStart = 0;
int m_sfaEnd = 0; int m_sfaEnd = 0;
*/ */
ImmutableList<Processor<TID, T>> m_processors = ImmutableList<Processor<TID, T>>.Empty; ImmutableList<Processor<TID, T>> m_processors = ImmutableList<Processor<TID, T>>.Empty;
//private static System s_system; //private static System s_system;
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,52 +1,52 @@
using System; using System;
namespace lib namespace lib
{ {
[Serializable] [Serializable]
public struct Pos public struct Pos
{ {
public float x { get; private set; } public float x { get; private set; }
public float y { get; private set; } public float y { get; private set; }
public float z { get; private set; } public float z { get; private set; }
public Pos( float _x, float _y, float _z ) : this() public Pos( float _x, float _y, float _z ) : this()
{ {
x = _x; x = _x;
y = _y; y = _y;
z = _z; z = _z;
} }
// overload operator + // overload operator +
public static Pos operator +( Pos a, Pos b ) public static Pos operator +( Pos a, Pos b )
{ {
return new Pos( a.x + b.x, a.y + b.y, a.z + b.z ); return new Pos( a.x + b.x, a.y + b.y, a.z + b.z );
} }
public static Pos operator -( Pos a, Pos b ) public static Pos operator -( Pos a, Pos b )
{ {
return new Pos( a.x - b.x, a.y - b.y, a.z - b.z ); return new Pos( a.x - b.x, a.y - b.y, a.z - b.z );
} }
public static Pos operator /( Pos a, float val ) public static Pos operator /( Pos a, float val )
{ {
return new Pos( a.x / val, a.y / val, a.z / val ); return new Pos( a.x / val, a.y / val, a.z / val );
} }
public static Pos operator *( Pos a, float val ) public static Pos operator *( Pos a, float val )
{ {
return new Pos( a.x * val, a.y * val, a.z * val ); return new Pos( a.x * val, a.y * val, a.z * val );
} }
public float distSqr( Pos other ) public float distSqr( Pos other )
{ {
float dx = x - other.x; float dx = x - other.x;
float dy = y - other.y; float dy = y - other.y;
float dz = z - other.z; float dz = z - other.z;
return dx * dx + dy * dy + dz * dz; return dx * dx + dy * dy + dz * dz;
} }
} }
} }

View File

@ -1,113 +1,113 @@
using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Syntax;
using System; using System;
using System.ComponentModel; using System.ComponentModel;
using System.Globalization; using System.Globalization;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Runtime.Serialization; using System.Runtime.Serialization;
namespace math namespace math
{ {
static public class fn static public class fn
{ {
static public float ToDeg( float rad ) => ( float )(180.0 / Math.PI) * rad; 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 ToRad( float deg ) => ( float )(Math.PI / 180.0) * deg;
static public float Clamp( float v, float min, float max ) static public float Clamp( float v, float min, float max )
{ {
return v < min ? min : v > max ? max : v; return v < min ? min : v > max ? max : v;
} }
static public float LogisticsUnit( float v, float spread = 4.0f, float height = 1.0f ) static public float LogisticsUnit( float v, float spread = 4.0f, float height = 1.0f )
{ {
return LogisticsFull( v, height, spread, 0, 0.1f, -0.5f ); 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 ) 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; float res = height / (1.0f + (float)Math.Pow( g, (spread * (v+h))) ) + f;
return res; return res;
} }
static public float LogisticsSymmetric( float v, float height = 1.0f, float spread = 3.65f ) static public float LogisticsSymmetric( float v, float height = 1.0f, float spread = 3.65f )
{ {
float fullHeight = height * 2.0f; float fullHeight = height * 2.0f;
float negF = -height; float negF = -height;
float res = LogisticsFull( v, fullHeight, spread, negF, 0.1f, 0.0f ); float res = LogisticsFull( v, fullHeight, spread, negF, 0.1f, 0.0f );
return res; return res;
} }
//Tracked these down in Desmos //Tracked these down in Desmos
static public float s_a = 0.0f; static public float s_a = 0.0f;
static public float s_b = 0.155f; static public float s_b = 0.155f;
static public float s_c = 1.03f; static public float s_c = 1.03f;
static public float s_d = 6.13f; static public float s_d = 6.13f;
static public float s_f = -10.2f; static public float s_f = -10.2f;
static public float s_g = 4.06f; static public float s_g = 4.06f;
static public float Quintic( float v ) static public float Quintic( float v )
{ {
var vv = v * v; var vv = v * v;
var vvv = vv * v; var vvv = vv * v;
var vvvv = vvv * v; var vvvv = vvv * v;
var vvvvv= vvvv * v; var vvvvv= vvvv * v;
var res = s_a + s_b*v + s_c*vv + s_d*vvv + s_f*vvvv + s_g * vvvvv; var res = s_a + s_b*v + s_c*vv + s_d*vvv + s_f*vvvv + s_g * vvvvv;
return res; return res;
} }
static public float s_p = 0.37f; static public float s_p = 0.37f;
static public float s_o = 0.15f; static public float s_o = 0.15f;
static public float s_m = 2.11f; static public float s_m = 2.11f;
static public float s_n = -0.57f; static public float s_n = -0.57f;
static public float PerlinToContinent( float h ) static public float PerlinToContinent( float h )
{ {
var res = Quintic( s_m * h + s_n ) * s_o + s_p; var res = Quintic( s_m * h + s_n ) * s_o + s_p;
return res; return res;
} }
static public float SmoothStepCos( float v ) static public float SmoothStepCos( float v )
{ {
var dV = (double)v; var dV = (double)v;
var newV = 0.5 - 0.5 * Math.Cos( Math.PI * dV ); var newV = 0.5 - 0.5 * Math.Cos( Math.PI * dV );
return (float)newV; return (float)newV;
} }
static public float SmoothStepSquare( float v ) static public float SmoothStepSquare( float v )
{ {
var dV = (double)v; var dV = (double)v;
var newV = dV * dV * (3.0 - 2.0 * dV); var newV = dV * dV * (3.0 - 2.0 * dV);
return (float)newV; return (float)newV;
} }
static public float SmoothStepCube( float v ) static public float SmoothStepCube( float v )
{ {
var dV = (double)v; var dV = (double)v;
var newV = dV * dV * dV * ( 6.0 * dV * dV - 15.0 * dV + 10.0 ); var newV = dV * dV * dV * ( 6.0 * dV * dV - 15.0 * dV + 10.0 );
return (float)newV; return (float)newV;
} }
} }
} }

View File

@ -1,8 +1,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
//using System.Threading.Tasks; //using System.Threading.Tasks;
using System.Diagnostics; using System.Diagnostics;
using System.Reflection; using System.Reflection;

View File

@ -1,195 +1,195 @@
using System; using System;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using System.Net.Sockets; using System.Net.Sockets;
using System.IO; using System.IO;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
//using Util; //using Util;
namespace lib namespace lib
{ {
public interface IFormatter public interface IFormatter
{ {
// //
// Summary: // Summary:
// Gets or sets the System.Runtime.Serialization.SerializationBinder that performs // Gets or sets the System.Runtime.Serialization.SerializationBinder that performs
// type lookups during deserialization. // type lookups during deserialization.
// //
// Returns: // Returns:
// The System.Runtime.Serialization.SerializationBinder that performs type lookups // The System.Runtime.Serialization.SerializationBinder that performs type lookups
// during deserialization. // during deserialization.
SerializationBinder? Binder { get; set; } SerializationBinder? Binder { get; set; }
// //
// Summary: // Summary:
// Gets or sets the System.Runtime.Serialization.StreamingContext used for serialization // Gets or sets the System.Runtime.Serialization.StreamingContext used for serialization
// and deserialization. // and deserialization.
// //
// Returns: // Returns:
// The System.Runtime.Serialization.StreamingContext used for serialization and // The System.Runtime.Serialization.StreamingContext used for serialization and
// deserialization. // deserialization.
StreamingContext Context { get; set; } StreamingContext Context { get; set; }
// //
// Summary: // Summary:
// Gets or sets the System.Runtime.Serialization.SurrogateSelector used by the current // Gets or sets the System.Runtime.Serialization.SurrogateSelector used by the current
// formatter. // formatter.
// //
// Returns: // Returns:
// The System.Runtime.Serialization.SurrogateSelector used by this formatter. // The System.Runtime.Serialization.SurrogateSelector used by this formatter.
ISurrogateSelector? SurrogateSelector { get; set; } ISurrogateSelector? SurrogateSelector { get; set; }
// //
// Summary: // Summary:
// Deserializes the data on the provided stream and reconstitutes the graph of objects. // Deserializes the data on the provided stream and reconstitutes the graph of objects.
// //
// //
// Parameters: // Parameters:
// serializationStream: // serializationStream:
// The stream that contains the data to deserialize. // The stream that contains the data to deserialize.
// //
// Returns: // Returns:
// The top object of the deserialized graph. // The top object of the deserialized graph.
[RequiresDynamicCode("BinaryFormatter serialization uses dynamic code generation, the type of objects being processed cannot be statically discovered.")] [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.")] [RequiresUnreferencedCode("BinaryFormatter serialization is not trim compatible because the type of objects being processed cannot be statically discovered.")]
object Deserialize(Stream serializationStream); object Deserialize(Stream serializationStream);
// //
// Summary: // Summary:
// Serializes an object, or graph of objects with the given root to the provided // Serializes an object, or graph of objects with the given root to the provided
// stream. // stream.
// //
// Parameters: // Parameters:
// serializationStream: // serializationStream:
// The stream where the formatter puts the serialized data. This stream can reference // 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). // a variety of backing stores (such as files, network, memory, and so on).
// //
// graph: // graph:
// The object, or root of the object graph, to serialize. All child objects of this // The object, or root of the object graph, to serialize. All child objects of this
// root object are automatically serialized. // root object are automatically serialized.
[RequiresUnreferencedCode("BinaryFormatter serialization is not trim compatible because 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.")]
void Serialize(Stream serializationStream, object graph); void Serialize(Stream serializationStream, object graph);
} }
public interface IProcess public interface IProcess
{ {
void process( object obj ); void process( object obj );
} }
public interface ISerDes<T> where T : IFormatter public interface ISerDes<T> where T : IFormatter
{ {
T getInstance(); T getInstance();
} }
public class NewEveryCall<T>: ISerDes<T> where T : IFormatter, new() public class NewEveryCall<T>: ISerDes<T> where T : IFormatter, new()
{ {
public T getInstance() public T getInstance()
{ {
return new T(); return new T();
} }
} }
public class Conn public class Conn
{ {
public static int BufferSize = 2048; public static int BufferSize = 2048;
} }
public class Conn<T, TInst> : Conn public class Conn<T, TInst> : Conn
where T : IFormatter, new() where T : IFormatter, new()
where TInst : ISerDes<T>, new() where TInst : ISerDes<T>, new()
{ {
public Socket Sock { get { return m_socket; } } public Socket Sock { get { return m_socket; } }
public Stream Stream { get { return m_streamNet; } } public Stream Stream { get { return m_streamNet; } }
private TInst m_formatter = new TInst(); private TInst m_formatter = new TInst();
public Conn( Socket sock, IProcess proc ) public Conn( Socket sock, IProcess proc )
{ {
m_socket = sock; m_socket = sock;
sock.NoDelay = true; sock.NoDelay = true;
m_streamNet = new NetworkStream( m_socket ); m_streamNet = new NetworkStream( m_socket );
m_proc = proc; m_proc = proc;
} }
public object recieveObject() public object recieveObject()
{ {
return recieveObject( Stream ); return recieveObject( Stream );
} }
public object recieveObject( Stream stream ) public object recieveObject( Stream stream )
{ {
object obj = null; object obj = null;
var formatter = m_formatter.getInstance(); var formatter = m_formatter.getInstance();
try try
{ {
obj = formatter.Deserialize( stream ); obj = formatter.Deserialize( stream );
} }
catch( System.Xml.XmlException ex ) catch( System.Xml.XmlException ex )
{ {
log.error( $"Outer Exception {ex.Message}" ); log.error( $"Outer Exception {ex.Message}" );
} }
return obj; return obj;
} }
public void send( object obj ) public void send( object obj )
{ {
var formatter = m_formatter.getInstance(); var formatter = m_formatter.getInstance();
try try
{ {
var ms = new MemoryStream( BufferSize ); var ms = new MemoryStream( BufferSize );
formatter.Serialize( ms, obj ); formatter.Serialize( ms, obj );
//var str = System.Text.Encoding.Default.GetString( mm_buffer, 0, (int)ms.Position ); //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 data {str} of length {ms.Position}" );
//log.info( $"Sent {obj}" ); //log.info( $"Sent {obj}" );
byte[] byteSize = BitConverter.GetBytes( (uint)ms.Position ); byte[] byteSize = BitConverter.GetBytes( (uint)ms.Position );
m_streamNet.Write( byteSize, 0, 4 ); m_streamNet.Write( byteSize, 0, 4 );
m_streamNet.Write( ms.GetBuffer(), 0, (int)ms.Position ); m_streamNet.Write( ms.GetBuffer(), 0, (int)ms.Position );
m_streamNet.Flush(); m_streamNet.Flush();
} }
catch( Exception e ) catch( Exception e )
{ {
log.warn( $"Exception sending obj {obj} of {e}" ); log.warn( $"Exception sending obj {obj} of {e}" );
throw; throw;
} }
} }
public virtual void recieve( object obj ) public virtual void recieve( object obj )
{ {
if( m_proc != null ) if( m_proc != null )
m_proc.process( obj ); m_proc.process( obj );
} }
Socket m_socket; Socket m_socket;
NetworkStream m_streamNet; NetworkStream m_streamNet;
IProcess m_proc; IProcess m_proc;
//private BufferedStream m_streamBufIn; //private BufferedStream m_streamBufIn;
//private BufferedStream m_streamBufOut; //private BufferedStream m_streamBufOut;
} }
} }

View File

@ -1,103 +1,103 @@
using System; using System;
namespace lib.Net namespace lib.Net
{ {
[Serializable] [Serializable]
public class Msg public class Msg
{ {
public Msg() public Msg()
{ {
} }
} }
[Serializable] [Serializable]
public class Login public class Login
{ {
public Login( String name, String pass ) public Login( String name, String pass )
{ {
m_username = name; m_username = name;
m_password = pass; m_password = pass;
} }
public readonly String m_username; public readonly String m_username;
public readonly String m_password; public readonly String m_password;
} }
[Serializable] [Serializable]
public class LoginResp public class LoginResp
{ {
public LoginResp( bool resp ) public LoginResp( bool resp )
{ {
m_resp = resp; m_resp = resp;
} }
public readonly bool m_resp; public readonly bool m_resp;
} }
#region Admin Messages #region Admin Messages
//Subclasses of this need to be on an admin client. //Subclasses of this need to be on an admin client.
[Serializable] [Serializable]
public class Admin public class Admin
{ {
}; };
[Serializable] [Serializable]
public class CreateEntity: Admin public class CreateEntity: Admin
{ {
} }
[Serializable] [Serializable]
public class MoveEntity: Admin public class MoveEntity: Admin
{ {
} }
#endregion #endregion
[Serializable] [Serializable]
public class EntityBase public class EntityBase
{ {
public EntityBase( int id ) public EntityBase( int id )
{ {
m_id = id; m_id = id;
} }
public readonly int m_id; public readonly int m_id;
}; };
[Serializable] [Serializable]
public class EntityPos: EntityBase public class EntityPos: EntityBase
{ {
public EntityPos( int id, float x, float y, float z ) : public EntityPos( int id, float x, float y, float z ) :
base( id ) base( id )
{ {
m_x = x; m_x = x;
m_y = y; m_y = y;
m_z = z; m_z = z;
} }
public readonly float m_x; public readonly float m_x;
public readonly float m_y; public readonly float m_y;
public readonly float m_z; public readonly float m_z;
} }
[Serializable] [Serializable]
public class EntityDesc: EntityBase public class EntityDesc: EntityBase
{ {
public EntityDesc( int id ) : public EntityDesc( int id ) :
base( id ) base( id )
{ {
} }
//Should an entity have a mesh? Be made up of multiple meshes? //Should an entity have a mesh? Be made up of multiple meshes?
public readonly String m_mesh; public readonly String m_mesh;
} }
} }

View File

@ -1,349 +1,349 @@
 
using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Emit; using Microsoft.CodeAnalysis.Emit;
using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.Text;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
public class MemoryRefResolver : SourceReferenceResolver public class MemoryRefResolver : SourceReferenceResolver
{ {
public override bool Equals(object other) public override bool Equals(object other)
{ {
return false; return false;
} }
public override int GetHashCode() public override int GetHashCode()
{ {
return 0; return 0;
} }
public override string NormalizePath(string path, string baseFilePath) public override string NormalizePath(string path, string baseFilePath)
{ {
return path; return path;
} }
public override Stream OpenRead(string resolvedPath) public override Stream OpenRead(string resolvedPath)
{ {
return null; return null;
} }
public override SourceText ReadText(string resolvedPath) public override SourceText ReadText(string resolvedPath)
{ {
return null; return null;
} }
public override string ResolveReference(string path, string baseFilePath) public override string ResolveReference(string path, string baseFilePath)
{ {
return null; return null;
} }
} }
public static class scr public static class scr
{ {
public static FieldInfo? GetFieldInfo(Type? t, string name) public static FieldInfo? GetFieldInfo(Type? t, string name)
{ {
if (t == null) return null; if (t == null) return null;
var fi = t.GetField(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly); var fi = t.GetField(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);
if (fi != null) if (fi != null)
return fi; return fi;
if (t.BaseType != null) if (t.BaseType != null)
return GetFieldInfo(t.BaseType, name); return GetFieldInfo(t.BaseType, name);
return null; return null;
} }
// From stack overflow // From stack overflow
static Lazy<ISet<Type>> typeSetLazy = static Lazy<ISet<Type>> typeSetLazy =
new Lazy<ISet<Type>>(() => { new Lazy<ISet<Type>>(() => {
var types = AppDomain var types = AppDomain
.CurrentDomain .CurrentDomain
.GetAssemblies() .GetAssemblies()
.SelectMany(a => a.GetTypes() .SelectMany(a => a.GetTypes()
.Where(t => t.IsClass)); .Where(t => t.IsClass));
var typesAndBaseTypes = types var typesAndBaseTypes = types
.Select(t => new { Type = t, t.BaseType }) .Select(t => new { Type = t, t.BaseType })
.ToList(); .ToList();
var typesWithSubclasses = typesAndBaseTypes var typesWithSubclasses = typesAndBaseTypes
.Join( .Join(
typesAndBaseTypes, typesAndBaseTypes,
t => t.Type, t => t.Type,
t => t.BaseType, t => t.BaseType,
(t1, t2) => t2.BaseType); (t1, t2) => t2.BaseType);
var typesHs = new HashSet<Type>(types); var typesHs = new HashSet<Type>(types);
typesHs.ExceptWith(typesWithSubclasses); typesHs.ExceptWith(typesWithSubclasses);
return typesHs; return typesHs;
}); });
static bool IsLeafType(this Type type) static bool IsLeafType(this Type type)
{ {
return typeSetLazy.Value.Contains(type); return typeSetLazy.Value.Contains(type);
} }
static HashSet<char> s_badChars = new( new char[] { '<', '>', ' ', ',', '.', '+', '[', ']', '$', ':' } ); static HashSet<char> s_badChars = new( new char[] { '<', '>', ' ', ',', '.', '+', '[', ']', '$', ':' } );
static public string TypeToIdentifier(string typename) static public string TypeToIdentifier(string typename)
{ {
var safeStr = new StringBuilder( typename ); var safeStr = new StringBuilder( typename );
for( int i = 0; i < safeStr.Length; ++i ) for( int i = 0; i < safeStr.Length; ++i )
{ {
if( s_badChars.Contains(safeStr[i]) ) safeStr[i] = '_'; if( s_badChars.Contains(safeStr[i]) ) safeStr[i] = '_';
} }
return safeStr.ToString(); return safeStr.ToString();
} }
static public FileSystemWatcher s_watcher; static public FileSystemWatcher s_watcher;
static public Action<Assembly> s_fnAss = (ass) => { static public Action<Assembly> s_fnAss = (ass) => {
log.warn( $"Need to replace s_fnAss with custom function" ); log.warn( $"Need to replace s_fnAss with custom function" );
}; };
public static void WatchPluginDir( string dir, Action<Assembly> fnAss ) public static void WatchPluginDir( string dir, Action<Assembly> fnAss )
{ {
log.info( $"Watching {dir} for changes" ); log.info( $"Watching {dir} for changes" );
s_fnAss = fnAss; s_fnAss = fnAss;
s_watcher = new FileSystemWatcher( dir ); s_watcher = new FileSystemWatcher( dir );
s_watcher.Created += OnCreated; s_watcher.Created += OnCreated;
s_watcher.Deleted += OnDeleted; s_watcher.Deleted += OnDeleted;
s_watcher.Renamed += OnRenamed; s_watcher.Renamed += OnRenamed;
s_watcher.Filter = "*.cs"; s_watcher.Filter = "*.cs";
s_watcher.IncludeSubdirectories = true; s_watcher.IncludeSubdirectories = true;
s_watcher.EnableRaisingEvents = true; s_watcher.EnableRaisingEvents = true;
var existingFiles = Directory.GetFiles( dir, "*.cs", SearchOption.AllDirectories ); var existingFiles = Directory.GetFiles( dir, "*.cs", SearchOption.AllDirectories );
foreach( var filename in existingFiles ) foreach( var filename in existingFiles )
{ {
Process( filename ); Process( filename );
} }
} }
static void OnCreated( object sender, FileSystemEventArgs e ) static void OnCreated( object sender, FileSystemEventArgs e )
{ {
log.debug( $"{e.Name} got {e.ChangeType}" ); log.debug( $"{e.Name} got {e.ChangeType}" );
if( e.Name.EndsWith( ".cs" ) ) if( e.Name.EndsWith( ".cs" ) )
{ {
Process( e.FullPath ); Process( e.FullPath );
} }
} }
static void OnDeleted( object sender, FileSystemEventArgs e ) static void OnDeleted( object sender, FileSystemEventArgs e )
{ {
log.debug( $"{e.Name} got {e.ChangeType}" ); log.debug( $"{e.Name} got {e.ChangeType}" );
} }
static void OnRenamed( object sender, FileSystemEventArgs e ) static void OnRenamed( object sender, FileSystemEventArgs e )
{ {
log.debug( $"{e.Name} got {e.ChangeType}" ); log.debug( $"{e.Name} got {e.ChangeType}" );
if( e.Name.EndsWith(".cs") ) if( e.Name.EndsWith(".cs") )
{ {
while( true ) while( true )
{ {
try try
{ {
Process( e.FullPath ); Process( e.FullPath );
return; return;
} }
catch( System.IO.IOException ex ) catch( System.IO.IOException ex )
{ {
} }
catch( Exception ex ) catch( Exception ex )
{ {
log.error( $"Got ex {ex.GetType().Name} trying to process {e.FullPath}" ); log.error( $"Got ex {ex.GetType().Name} trying to process {e.FullPath}" );
log.error( $"-> {ex.Message}" ); log.error( $"-> {ex.Message}" );
return; return;
} }
Thread.Sleep( 100 ); Thread.Sleep( 100 );
} }
} }
} }
static void Process( string filename ) static void Process( string filename )
{ {
CompileFile( filename, ( ass ) => { s_fnAss( ass ); }, ( diags ) => { } ); CompileFile( filename, ( ass ) => { s_fnAss( ass ); }, ( diags ) => { } );
} }
public static void CompileFile( string filename, Action<Assembly> onSuccess, Action<ImmutableArray<Diagnostic>> onFailure, Platform platform = Platform.X86 ) public static void CompileFile( string filename, Action<Assembly> onSuccess, Action<ImmutableArray<Diagnostic>> onFailure, Platform platform = Platform.X86 )
{ {
var fullpath = Path.GetFullPath( filename ); var fullpath = Path.GetFullPath( filename );
var stream = File.OpenRead( fullpath ); var stream = File.OpenRead( fullpath );
var sourceText = SourceText.From( stream ); var sourceText = SourceText.From( stream );
Compile( sourceText, fullpath, onSuccess, onFailure ); Compile( sourceText, fullpath, onSuccess, onFailure );
} }
public static void Compile( string str, string uniquePath, Action<Assembly> onSuccess, Action<ImmutableArray<Diagnostic>> onFailure, Platform platform = Platform.X86 ) public static void Compile( string str, string uniquePath, Action<Assembly> onSuccess, Action<ImmutableArray<Diagnostic>> onFailure, Platform platform = Platform.X86 )
{ {
var sourceText = SourceText.From( str ); var sourceText = SourceText.From( str );
Compile( sourceText, uniquePath, onSuccess, onFailure ); Compile( sourceText, uniquePath, onSuccess, onFailure );
} }
public static void Compile( SourceText sourceText, string uniquePath, Action<Assembly> onSuccess, Action<ImmutableArray<Diagnostic>> onFailure, Platform platform = Platform.X86 ) public static void Compile( SourceText sourceText, string uniquePath, Action<Assembly> onSuccess, Action<ImmutableArray<Diagnostic>> onFailure, Platform platform = Platform.X86 )
{ {
string assemblyName = Path.GetRandomFileName(); string assemblyName = Path.GetRandomFileName();
var options = new CSharpParseOptions(documentationMode: DocumentationMode.Diagnose, kind: SourceCodeKind.Regular); var options = new CSharpParseOptions(documentationMode: DocumentationMode.Diagnose, kind: SourceCodeKind.Regular);
SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText( sourceText, options, uniquePath ); SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText( sourceText, options, uniquePath );
var memRef = new MemoryRefResolver(); var memRef = new MemoryRefResolver();
using (var ms = new MemoryStream()) using (var ms = new MemoryStream())
using (var pdb = new MemoryStream()) using (var pdb = new MemoryStream())
{ {
var result = CompileAndEmit(assemblyName, new[] { syntaxTree }, ms, pdb, platform); var result = CompileAndEmit(assemblyName, new[] { syntaxTree }, ms, pdb, platform);
if (!result.Success) if (!result.Success)
{ {
if (onFailure == null) if (onFailure == null)
{ {
} }
else else
{ {
LogDiags( uniquePath, result.Diagnostics.Length, result.Diagnostics ); LogDiags( uniquePath, result.Diagnostics.Length, result.Diagnostics );
onFailure( result.Diagnostics ); onFailure( result.Diagnostics );
} }
} }
else else
{ {
ms.Seek(0, SeekOrigin.Begin); ms.Seek(0, SeekOrigin.Begin);
var assembly = Assembly.Load(ms.ToArray(), pdb.ToArray()); var assembly = Assembly.Load(ms.ToArray(), pdb.ToArray());
onSuccess( assembly ); onSuccess( assembly );
} }
} }
} }
public static void LogDiags( string uniquePath, int count, IEnumerable<Diagnostic> diags ) public static void LogDiags( string uniquePath, int count, IEnumerable<Diagnostic> diags )
{ {
log.warn( $"{count} Problems building script with name {uniquePath}" ); log.warn( $"{count} Problems building script with name {uniquePath}" );
foreach( var diag in diags ) foreach( var diag in diags )
{ {
log.debug( $"{diag}" ); log.debug( $"{diag}" );
} }
} }
private static EmitResult CompileAndEmit(string assemblyName, SyntaxTree[] syntaxTrees, MemoryStream ms, MemoryStream pdb, Platform platform) private static EmitResult CompileAndEmit(string assemblyName, SyntaxTree[] syntaxTrees, MemoryStream ms, MemoryStream pdb, Platform platform)
{ {
var memRef = new MemoryRefResolver(); var memRef = new MemoryRefResolver();
// @@@@ TODO :: Config release / debug // @@@@ TODO :: Config release / debug
CSharpCompilation compilation = CSharpCompilation.Create( CSharpCompilation compilation = CSharpCompilation.Create(
assemblyName, assemblyName,
syntaxTrees: syntaxTrees, syntaxTrees: syntaxTrees,
references: RefCache.References, references: RefCache.References,
options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary,
sourceReferenceResolver: memRef, sourceReferenceResolver: memRef,
optimizationLevel: OptimizationLevel.Release, optimizationLevel: OptimizationLevel.Release,
platform: platform, platform: platform,
specificDiagnosticOptions: new Dictionary<string, ReportDiagnostic> specificDiagnosticOptions: new Dictionary<string, ReportDiagnostic>
{ {
{ "CS1701", ReportDiagnostic.Suppress } { "CS1701", ReportDiagnostic.Suppress }
})); }));
return compilation.Emit(ms, pdb); return compilation.Emit(ms, pdb);
} }
private static class RefCache 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. // 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<ImmutableArray<MetadataReference>> lazyRef = new Lazy<ImmutableArray<MetadataReference>>(GetReferences, LazyThreadSafetyMode.PublicationOnly); private static readonly Lazy<ImmutableArray<MetadataReference>> lazyRef = new Lazy<ImmutableArray<MetadataReference>>(GetReferences, LazyThreadSafetyMode.PublicationOnly);
public static IReadOnlyList<MetadataReference> References => lazyRef.Value; public static IReadOnlyList<MetadataReference> References => lazyRef.Value;
private static ImmutableArray<MetadataReference> GetReferences() private static ImmutableArray<MetadataReference> GetReferences()
{ {
var builder = ImmutableArray.CreateBuilder<MetadataReference>(); var builder = ImmutableArray.CreateBuilder<MetadataReference>();
var assemblies = AppDomain.CurrentDomain.GetAssemblies(); var assemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach( var ass in assemblies ) foreach( var ass in assemblies )
{ {
if( ass != null && !ass.IsDynamic && ass.Location != null ) if( ass != null && !ass.IsDynamic && ass.Location != null )
{ {
try try
{ {
builder.Add( MetadataReference.CreateFromFile( ass.Location ) ); builder.Add( MetadataReference.CreateFromFile( ass.Location ) );
} }
catch( Exception ex ) catch( Exception ex )
{ {
log.warn( $"Got {ex.GetType().Name} sayaing {ex.Message}" ); log.warn( $"Got {ex.GetType().Name} sayaing {ex.Message}" );
} }
} }
} }
return builder.ToImmutable(); return builder.ToImmutable();
} }
} }
public static string PrettyName( Type t ) public static string PrettyName( Type t )
{ {
if( t.GetGenericArguments().Length == 0 ) if( t.GetGenericArguments().Length == 0 )
{ {
return t.FullName.Replace( '+', '.' ); return t.FullName.Replace( '+', '.' );
} }
var genArgs = t.GetGenericArguments(); var genArgs = t.GetGenericArguments();
var typeDef = t.FullName; var typeDef = t.FullName;
var indexOfTick = typeDef.IndexOf("`"); var indexOfTick = typeDef.IndexOf("`");
var unmangledOuterName = typeDef.Substring(0, typeDef.IndexOf('`')).Replace('+', '.'); var unmangledOuterName = typeDef.Substring(0, typeDef.IndexOf('`')).Replace('+', '.');
var innerName = ""; var innerName = "";
//Check for inner class //Check for inner class
if( typeDef.ElementAt( indexOfTick + 2 ) != '[' ) if( typeDef.ElementAt( indexOfTick + 2 ) != '[' )
{ {
var indexOfOpenBracket = typeDef.IndexOf('[', indexOfTick); var indexOfOpenBracket = typeDef.IndexOf('[', indexOfTick);
innerName = typeDef.Substring( indexOfTick + 2, indexOfOpenBracket - (indexOfTick + 2) ).Replace( '+', '.' ); innerName = typeDef.Substring( indexOfTick + 2, indexOfOpenBracket - (indexOfTick + 2) ).Replace( '+', '.' );
} }
return unmangledOuterName + "<" + String.Join( ",", genArgs.Select( PrettyName ) ) + ">" + innerName; return unmangledOuterName + "<" + String.Join( ",", genArgs.Select( PrettyName ) ) + ">" + innerName;
} }
private static void AddIfFirst<TKey, TValue>(IDictionary<TKey, TValue> dict, TKey key, TValue value) private static void AddIfFirst<TKey, TValue>(IDictionary<TKey, TValue> dict, TKey key, TValue value)
{ {
if (!dict.ContainsKey(key)) if (!dict.ContainsKey(key))
{ {
dict.Add(key, value); dict.Add(key, value);
} }
} }
} }

View File

@ -1,166 +1,166 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using System.Xml.Serialization; using System.Xml.Serialization;
using System.Xml; using System.Xml;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary; using System.Runtime.Serialization.Formatters.Binary;
using System.IO; using System.IO;
using System.Security.Permissions; using System.Security.Permissions;
namespace lib namespace lib
{ {
[Serializable] [Serializable]
public class SerializableDictionary<TKey, TVal>: Dictionary<TKey, TVal>, IXmlSerializable, ISerializable public class SerializableDictionary<TKey, TVal>: Dictionary<TKey, TVal>, IXmlSerializable, ISerializable
{ {
#region Constants #region Constants
private const string DictionaryNodeName = "Dictionary"; private const string DictionaryNodeName = "Dictionary";
private const string ItemNodeName = "Item"; private const string ItemNodeName = "Item";
private const string KeyNodeName = "Key"; private const string KeyNodeName = "Key";
private const string ValueNodeName = "Value"; private const string ValueNodeName = "Value";
#endregion #endregion
#region Constructors #region Constructors
public SerializableDictionary() public SerializableDictionary()
{ {
} }
public SerializableDictionary( IDictionary<TKey, TVal> dictionary ) public SerializableDictionary( IDictionary<TKey, TVal> dictionary )
: base( dictionary ) : base( dictionary )
{ {
} }
public SerializableDictionary( IEqualityComparer<TKey> comparer ) public SerializableDictionary( IEqualityComparer<TKey> comparer )
: base( comparer ) : base( comparer )
{ {
} }
public SerializableDictionary( int capacity ) public SerializableDictionary( int capacity )
: base( capacity ) : base( capacity )
{ {
} }
public SerializableDictionary( IDictionary<TKey, TVal> dictionary, IEqualityComparer<TKey> comparer ) public SerializableDictionary( IDictionary<TKey, TVal> dictionary, IEqualityComparer<TKey> comparer )
: base( dictionary, comparer ) : base( dictionary, comparer )
{ {
} }
public SerializableDictionary( int capacity, IEqualityComparer<TKey> comparer ) public SerializableDictionary( int capacity, IEqualityComparer<TKey> comparer )
: base( capacity, comparer ) : base( capacity, comparer )
{ {
} }
#endregion #endregion
#region ISerializable Members #region ISerializable Members
protected SerializableDictionary( SerializationInfo info, StreamingContext context ) protected SerializableDictionary( SerializationInfo info, StreamingContext context )
{ {
int itemCount = info.GetInt32("ItemCount"); int itemCount = info.GetInt32("ItemCount");
for( int i = 0; i < itemCount; i++ ) for( int i = 0; i < itemCount; i++ )
{ {
KeyValuePair<TKey, TVal> kvp = (KeyValuePair<TKey, TVal>)info.GetValue(String.Format( $"Item{i}" ), typeof(KeyValuePair<TKey, TVal>)); KeyValuePair<TKey, TVal> kvp = (KeyValuePair<TKey, TVal>)info.GetValue(String.Format( $"Item{i}" ), typeof(KeyValuePair<TKey, TVal>));
this.Add( kvp.Key, kvp.Value ); this.Add( kvp.Key, kvp.Value );
} }
} }
//[SecurityPermission( SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter )] //[SecurityPermission( SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter )]
void ISerializable.GetObjectData( SerializationInfo info, StreamingContext context ) void ISerializable.GetObjectData( SerializationInfo info, StreamingContext context )
{ {
info.AddValue( "ItemCount", this.Count ); info.AddValue( "ItemCount", this.Count );
int itemIdx = 0; int itemIdx = 0;
foreach( KeyValuePair<TKey, TVal> kvp in this ) foreach( KeyValuePair<TKey, TVal> kvp in this )
{ {
info.AddValue( String.Format( $"Item{itemIdx}" ), kvp, typeof( KeyValuePair<TKey, TVal> ) ); info.AddValue( String.Format( $"Item{itemIdx}" ), kvp, typeof( KeyValuePair<TKey, TVal> ) );
itemIdx++; itemIdx++;
} }
} }
#endregion #endregion
#region IXmlSerializable Members #region IXmlSerializable Members
void IXmlSerializable.WriteXml( System.Xml.XmlWriter writer ) void IXmlSerializable.WriteXml( System.Xml.XmlWriter writer )
{ {
//writer.WriteStartElement(DictionaryNodeName); //writer.WriteStartElement(DictionaryNodeName);
foreach( KeyValuePair<TKey, TVal> kvp in this ) foreach( KeyValuePair<TKey, TVal> kvp in this )
{ {
writer.WriteStartElement( ItemNodeName ); writer.WriteStartElement( ItemNodeName );
writer.WriteStartElement( KeyNodeName ); writer.WriteStartElement( KeyNodeName );
KeySerializer.Serialize( writer, kvp.Key ); KeySerializer.Serialize( writer, kvp.Key );
writer.WriteEndElement(); writer.WriteEndElement();
writer.WriteStartElement( ValueNodeName ); writer.WriteStartElement( ValueNodeName );
ValueSerializer.Serialize( writer, kvp.Value ); ValueSerializer.Serialize( writer, kvp.Value );
writer.WriteEndElement(); writer.WriteEndElement();
writer.WriteEndElement(); writer.WriteEndElement();
} }
//writer.WriteEndElement(); //writer.WriteEndElement();
} }
void IXmlSerializable.ReadXml( System.Xml.XmlReader reader ) void IXmlSerializable.ReadXml( System.Xml.XmlReader reader )
{ {
if( reader.IsEmptyElement ) if( reader.IsEmptyElement )
{ {
return; return;
} }
// Move past container // Move past container
if( !reader.Read() ) if( !reader.Read() )
{ {
throw new XmlException( "Error in Deserialization of Dictionary" ); throw new XmlException( "Error in Deserialization of Dictionary" );
} }
//reader.ReadStartElement(DictionaryNodeName); //reader.ReadStartElement(DictionaryNodeName);
while( reader.NodeType != XmlNodeType.EndElement ) while( reader.NodeType != XmlNodeType.EndElement )
{ {
reader.ReadStartElement( ItemNodeName ); reader.ReadStartElement( ItemNodeName );
reader.ReadStartElement( KeyNodeName ); reader.ReadStartElement( KeyNodeName );
TKey key = (TKey)KeySerializer.Deserialize(reader); TKey key = (TKey)KeySerializer.Deserialize(reader);
reader.ReadEndElement(); reader.ReadEndElement();
reader.ReadStartElement( ValueNodeName ); reader.ReadStartElement( ValueNodeName );
TVal value = (TVal)ValueSerializer.Deserialize(reader); TVal value = (TVal)ValueSerializer.Deserialize(reader);
reader.ReadEndElement(); reader.ReadEndElement();
reader.ReadEndElement(); reader.ReadEndElement();
this.Add( key, value ); this.Add( key, value );
reader.MoveToContent(); reader.MoveToContent();
} }
//reader.ReadEndElement(); //reader.ReadEndElement();
reader.ReadEndElement(); // Read End Element to close Read of containing node reader.ReadEndElement(); // Read End Element to close Read of containing node
} }
System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema() System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema()
{ {
return null; return null;
} }
#endregion #endregion
#region Private Properties #region Private Properties
protected XmlSerializer ValueSerializer protected XmlSerializer ValueSerializer
{ {
get get
{ {
if( valueSerializer == null ) if( valueSerializer == null )
{ {
valueSerializer = new XmlSerializer( typeof( TVal ) ); valueSerializer = new XmlSerializer( typeof( TVal ) );
} }
return valueSerializer; return valueSerializer;
} }
} }
private XmlSerializer KeySerializer private XmlSerializer KeySerializer
{ {
get get
{ {
if( keySerializer == null ) if( keySerializer == null )
{ {
keySerializer = new XmlSerializer( typeof( TKey ) ); keySerializer = new XmlSerializer( typeof( TKey ) );
} }
return keySerializer; return keySerializer;
} }
} }
#endregion #endregion
#region Private Members #region Private Members
private XmlSerializer keySerializer = null; private XmlSerializer keySerializer = null;
private XmlSerializer valueSerializer = null; private XmlSerializer valueSerializer = null;
#endregion #endregion
} }
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,52 +1,52 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
namespace lib namespace lib
{ {
public class Clock public class Clock
{ {
public Clock( long timeOffset ) public Clock( long timeOffset )
{ {
m_timer = new Timer(); m_timer = new Timer();
m_lastTime = m_timer.Current; m_lastTime = m_timer.Current;
m_totalMillis = timeOffset; m_totalMillis = timeOffset;
m_totalSeconds = (double)m_totalMillis / 1000.0; m_totalSeconds = (double)m_totalMillis / 1000.0;
} }
public void tick() public void tick()
{ {
long current = m_timer.Current; long current = m_timer.Current;
m_dtMillis = (int)( current - m_lastTime ); m_dtMillis = (int)( current - m_lastTime );
m_dtSeconds = (double)m_dtMillis / 1000.0; m_dtSeconds = (double)m_dtMillis / 1000.0;
m_totalMillis += m_dtMillis; m_totalMillis += m_dtMillis;
m_totalSeconds = (double)m_totalMillis / 1000.0; m_totalSeconds = (double)m_totalMillis / 1000.0;
m_lastTime = current; m_lastTime = current;
} }
public int dtMs { get { return m_dtMillis; } } public int dtMs { get { return m_dtMillis; } }
public double dtSec { get { return m_dtSeconds; } } public double dtSec { get { return m_dtSeconds; } }
public long ms { get { return m_totalMillis; } } public long ms { get { return m_totalMillis; } }
public double sec { get { return m_totalSeconds; } } public double sec { get { return m_totalSeconds; } }
Timer m_timer; Timer m_timer;
long m_lastTime = 0; long m_lastTime = 0;
int m_dtMillis = 0; int m_dtMillis = 0;
double m_dtSeconds = 0; double m_dtSeconds = 0;
long m_totalMillis = 0; long m_totalMillis = 0;
double m_totalSeconds = 0; double m_totalSeconds = 0;
} }
} }

View File

@ -1,377 +1,377 @@
using System; using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.ComponentModel; using System.ComponentModel;
using System.Threading; using System.Threading;
namespace lib namespace lib
{ {
public class MicroStopwatch: System.Diagnostics.Stopwatch public class MicroStopwatch: System.Diagnostics.Stopwatch
{ {
readonly double _microSecPerTick readonly double _microSecPerTick
= 1000000D / System.Diagnostics.Stopwatch.Frequency; = 1000000D / System.Diagnostics.Stopwatch.Frequency;
public MicroStopwatch() public MicroStopwatch()
{ {
if( !System.Diagnostics.Stopwatch.IsHighResolution ) if( !System.Diagnostics.Stopwatch.IsHighResolution )
{ {
throw new Exception( "On this system the high-resolution " + throw new Exception( "On this system the high-resolution " +
"performance counter is not available" ); "performance counter is not available" );
} }
} }
public long ElapsedMicroseconds public long ElapsedMicroseconds
{ {
get get
{ {
return (long)( ElapsedTicks * _microSecPerTick ); return (long)( ElapsedTicks * _microSecPerTick );
} }
} }
} }
/// <summary> /// <summary>
/// MicroTimer class /// MicroTimer class
/// </summary> /// </summary>
public class MicroTimer public class MicroTimer
{ {
public delegate void MicroTimerElapsedEventHandler( public delegate void MicroTimerElapsedEventHandler(
object sender, object sender,
MicroTimerEventArgs timerEventArgs ); MicroTimerEventArgs timerEventArgs );
public event MicroTimerElapsedEventHandler MicroTimerElapsed; public event MicroTimerElapsedEventHandler MicroTimerElapsed;
System.Threading.Thread _threadTimer = null; System.Threading.Thread _threadTimer = null;
long _ignoreEventIfLateBy = long.MaxValue; long _ignoreEventIfLateBy = long.MaxValue;
long _timerIntervalInMicroSec = 0; long _timerIntervalInMicroSec = 0;
bool _stopTimer = true; bool _stopTimer = true;
public MicroTimer() public MicroTimer()
{ {
} }
public MicroTimer( long timerIntervalInMicroseconds ) public MicroTimer( long timerIntervalInMicroseconds )
{ {
Interval = timerIntervalInMicroseconds; Interval = timerIntervalInMicroseconds;
} }
public long Interval public long Interval
{ {
get get
{ {
return System.Threading.Interlocked.Read( return System.Threading.Interlocked.Read(
ref _timerIntervalInMicroSec ); ref _timerIntervalInMicroSec );
} }
set set
{ {
System.Threading.Interlocked.Exchange( System.Threading.Interlocked.Exchange(
ref _timerIntervalInMicroSec, value ); ref _timerIntervalInMicroSec, value );
} }
} }
public long IgnoreEventIfLateBy public long IgnoreEventIfLateBy
{ {
get get
{ {
return System.Threading.Interlocked.Read( return System.Threading.Interlocked.Read(
ref _ignoreEventIfLateBy ); ref _ignoreEventIfLateBy );
} }
set set
{ {
System.Threading.Interlocked.Exchange( System.Threading.Interlocked.Exchange(
ref _ignoreEventIfLateBy, value <= 0 ? long.MaxValue : value ); ref _ignoreEventIfLateBy, value <= 0 ? long.MaxValue : value );
} }
} }
public bool Enabled public bool Enabled
{ {
set set
{ {
if( value ) if( value )
{ {
Start(); Start();
} }
else else
{ {
Stop(); Stop();
} }
} }
get get
{ {
return ( _threadTimer != null && _threadTimer.IsAlive ); return ( _threadTimer != null && _threadTimer.IsAlive );
} }
} }
public void Start() public void Start()
{ {
if( Enabled || Interval <= 0 ) if( Enabled || Interval <= 0 )
{ {
return; return;
} }
_stopTimer = false; _stopTimer = false;
System.Threading.ThreadStart threadStart = delegate() System.Threading.ThreadStart threadStart = delegate()
{ {
NotificationTimer(ref _timerIntervalInMicroSec, NotificationTimer(ref _timerIntervalInMicroSec,
ref _ignoreEventIfLateBy, ref _ignoreEventIfLateBy,
ref _stopTimer); ref _stopTimer);
}; };
_threadTimer = new System.Threading.Thread( threadStart ); _threadTimer = new System.Threading.Thread( threadStart );
_threadTimer.Priority = System.Threading.ThreadPriority.Highest; _threadTimer.Priority = System.Threading.ThreadPriority.Highest;
_threadTimer.Start(); _threadTimer.Start();
} }
public void Stop() public void Stop()
{ {
_stopTimer = true; _stopTimer = true;
if( _threadTimer != null && _threadTimer.ManagedThreadId == if( _threadTimer != null && _threadTimer.ManagedThreadId ==
System.Threading.Thread.CurrentThread.ManagedThreadId ) System.Threading.Thread.CurrentThread.ManagedThreadId )
{ {
return; return;
} }
while( Enabled ) while( Enabled )
{ {
System.Threading.Thread.SpinWait( 10 ); System.Threading.Thread.SpinWait( 10 );
} }
} }
void NotificationTimer( ref long timerIntervalInMicroSec, void NotificationTimer( ref long timerIntervalInMicroSec,
ref long ignoreEventIfLateBy, ref long ignoreEventIfLateBy,
ref bool stopTimer ) ref bool stopTimer )
{ {
int timerCount = 0; int timerCount = 0;
long nextNotification = 0; long nextNotification = 0;
MicroStopwatch microStopwatch = new MicroStopwatch(); MicroStopwatch microStopwatch = new MicroStopwatch();
microStopwatch.Start(); microStopwatch.Start();
while( !stopTimer ) while( !stopTimer )
{ {
long callbackFunctionExecutionTime = long callbackFunctionExecutionTime =
microStopwatch.ElapsedMicroseconds - nextNotification; microStopwatch.ElapsedMicroseconds - nextNotification;
long timerIntervalInMicroSecCurrent = long timerIntervalInMicroSecCurrent =
System.Threading.Interlocked.Read(ref timerIntervalInMicroSec); System.Threading.Interlocked.Read(ref timerIntervalInMicroSec);
long ignoreEventIfLateByCurrent = long ignoreEventIfLateByCurrent =
System.Threading.Interlocked.Read(ref ignoreEventIfLateBy); System.Threading.Interlocked.Read(ref ignoreEventIfLateBy);
nextNotification += timerIntervalInMicroSecCurrent; nextNotification += timerIntervalInMicroSecCurrent;
timerCount++; timerCount++;
long elapsedMicroseconds = 0; long elapsedMicroseconds = 0;
while( ( elapsedMicroseconds = microStopwatch.ElapsedMicroseconds ) while( ( elapsedMicroseconds = microStopwatch.ElapsedMicroseconds )
< nextNotification ) < nextNotification )
{ {
System.Threading.Thread.SpinWait( 10 ); System.Threading.Thread.SpinWait( 10 );
} }
long timerLateBy = elapsedMicroseconds - nextNotification; long timerLateBy = elapsedMicroseconds - nextNotification;
if( timerLateBy >= ignoreEventIfLateByCurrent ) if( timerLateBy >= ignoreEventIfLateByCurrent )
{ {
continue; continue;
} }
MicroTimerEventArgs microTimerEventArgs = MicroTimerEventArgs microTimerEventArgs =
new MicroTimerEventArgs(timerCount, new MicroTimerEventArgs(timerCount,
elapsedMicroseconds, elapsedMicroseconds,
timerLateBy, timerLateBy,
callbackFunctionExecutionTime); callbackFunctionExecutionTime);
MicroTimerElapsed( this, microTimerEventArgs ); MicroTimerElapsed( this, microTimerEventArgs );
} }
microStopwatch.Stop(); microStopwatch.Stop();
} }
} }
/// <summary> /// <summary>
/// MicroTimer Event Argument class /// MicroTimer Event Argument class
/// </summary> /// </summary>
public class MicroTimerEventArgs: EventArgs public class MicroTimerEventArgs: EventArgs
{ {
// Simple counter, number times timed event (callback function) executed // Simple counter, number times timed event (callback function) executed
public int TimerCount { get; private set; } public int TimerCount { get; private set; }
// Time when timed event was called since timer started // Time when timed event was called since timer started
public long ElapsedMicroseconds { get; private set; } public long ElapsedMicroseconds { get; private set; }
// How late the timer was compared to when it should have been called // How late the timer was compared to when it should have been called
public long TimerLateBy { get; private set; } public long TimerLateBy { get; private set; }
// Time it took to execute previous call to callback function (OnTimedEvent) // Time it took to execute previous call to callback function (OnTimedEvent)
public long CallbackFunctionExecutionTime { get; private set; } public long CallbackFunctionExecutionTime { get; private set; }
public MicroTimerEventArgs( int timerCount, public MicroTimerEventArgs( int timerCount,
long elapsedMicroseconds, long elapsedMicroseconds,
long timerLateBy, long timerLateBy,
long callbackFunctionExecutionTime ) long callbackFunctionExecutionTime )
{ {
TimerCount = timerCount; TimerCount = timerCount;
ElapsedMicroseconds = elapsedMicroseconds; ElapsedMicroseconds = elapsedMicroseconds;
TimerLateBy = timerLateBy; TimerLateBy = timerLateBy;
CallbackFunctionExecutionTime = callbackFunctionExecutionTime; CallbackFunctionExecutionTime = callbackFunctionExecutionTime;
} }
} }
public class Timer public class Timer
{ {
MicroStopwatch m_watch; MicroStopwatch m_watch;
private long startTime; private long startTime;
private long stopTime; private long stopTime;
private long freq; private long freq;
private long freq_millis; private long freq_millis;
public Timer() public Timer()
{ {
m_watch = new MicroStopwatch(); m_watch = new MicroStopwatch();
//startTime = m_watch.ElapsedMicroseconds; //startTime = m_watch.ElapsedMicroseconds;
//stopTime = m_watch.ElapsedMicroseconds; //stopTime = m_watch.ElapsedMicroseconds;
freq = 1000 * 1000; freq = 1000 * 1000;
freq_millis = freq / 1000; freq_millis = freq / 1000;
Start(); Start();
} }
// Start the timer // Start the timer
public Timer Start() public Timer Start()
{ {
m_watch.Start(); m_watch.Start();
startTime = m_watch.ElapsedMicroseconds; startTime = m_watch.ElapsedMicroseconds;
stopTime = m_watch.ElapsedMicroseconds; stopTime = m_watch.ElapsedMicroseconds;
return this; return this;
} }
// Stop the timer // Stop the timer
public Timer Stop() public Timer Stop()
{ {
m_watch.Stop(); m_watch.Stop();
stopTime = m_watch.ElapsedMicroseconds; stopTime = m_watch.ElapsedMicroseconds;
return this; return this;
} }
public double Seconds public double Seconds
{ {
get get
{ {
long current = m_watch.ElapsedMicroseconds; long current = m_watch.ElapsedMicroseconds;
return (double)( current - startTime ) / freq; return (double)( current - startTime ) / freq;
} }
} }
public long Current public long Current
{ {
get get
{ {
long current = m_watch.ElapsedMicroseconds; long current = m_watch.ElapsedMicroseconds;
return ( current - startTime ) / freq_millis; return ( current - startTime ) / freq_millis;
} }
} }
public double Duration public double Duration
{ {
get get
{ {
return (double)( stopTime - startTime ) / (double)freq; return (double)( stopTime - startTime ) / (double)freq;
} }
} }
public long DurationMS public long DurationMS
{ {
get { return ( stopTime - startTime ) / freq_millis; } get { return ( stopTime - startTime ) / freq_millis; }
} }
} }
public class TimerWin public class TimerWin
{ {
[DllImport( "Kernel32.dll" )] [DllImport( "Kernel32.dll" )]
private static extern bool QueryPerformanceCounter( private static extern bool QueryPerformanceCounter(
out long lpPerformanceCount ); out long lpPerformanceCount );
[DllImport( "Kernel32.dll" )] [DllImport( "Kernel32.dll" )]
private static extern bool QueryPerformanceFrequency( private static extern bool QueryPerformanceFrequency(
out long lpFrequency ); out long lpFrequency );
private long startTime; private long startTime;
private long stopTime; private long stopTime;
private long freq; private long freq;
private long freq_millis; private long freq_millis;
// Constructor // Constructor
public TimerWin() public TimerWin()
{ {
startTime = 0; startTime = 0;
stopTime = 0; stopTime = 0;
if( QueryPerformanceFrequency( out freq ) == false ) if( QueryPerformanceFrequency( out freq ) == false )
{ {
// high-performance counter not supported // high-performance counter not supported
throw new Win32Exception(); throw new Win32Exception();
} }
freq_millis = freq / 1000; freq_millis = freq / 1000;
} }
// Start the timer // Start the timer
public void Start() public void Start()
{ {
// lets do the waiting threads there work // lets do the waiting threads there work
//Thread.Sleep(0); //Thread.Sleep(0);
QueryPerformanceCounter( out startTime ); QueryPerformanceCounter( out startTime );
} }
// Stop the timer // Stop the timer
public void Stop() public void Stop()
{ {
QueryPerformanceCounter( out stopTime ); QueryPerformanceCounter( out stopTime );
} }
public double Seconds public double Seconds
{ {
get get
{ {
long current; long current;
QueryPerformanceCounter( out current ); QueryPerformanceCounter( out current );
return (double)( current - startTime ) / freq; return (double)( current - startTime ) / freq;
} }
} }
public long Current public long Current
{ {
get get
{ {
long current; long current;
QueryPerformanceCounter( out current ); QueryPerformanceCounter( out current );
return ( current - startTime ) / freq_millis; return ( current - startTime ) / freq_millis;
} }
} }
public double Duration public double Duration
{ {
get get
{ {
return (double)( stopTime - startTime ) / (double)freq; return (double)( stopTime - startTime ) / (double)freq;
} }
} }
public long DurationMS public long DurationMS
{ {
get { return ( stopTime - startTime ) / freq_millis; } get { return ( stopTime - startTime ) / freq_millis; }
} }
} }
} }