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

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

@ -1,185 +1,185 @@
using System;
using System.Diagnostics;
/*
* Reference arithmetic coding
* Copyright (c) Project Nayuki
*
* https://www.nayuki.io/page/reference-arithmetic-coding
* https://github.com/nayuki/Reference-arithmetic-coding
*/
/// <summary>
/// Provides the state and behaviors that arithmetic coding encoders and decoders share. </summary>
/// <seealso cref= ArithmeticEncoder </seealso>
/// <seealso cref= ArithmeticDecoder </seealso>
public abstract class ArithmeticCoderBase
{
/*---- Configuration fields ----*/
/// <summary>
/// Number of bits for the 'low' and 'high' state variables. Must be in the range [1, 62].
/// <ul>
/// <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
/// 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>
/// <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
/// maximum frequency total, which might constrain the user-supplied probability model.</li>
/// <li>Therefore numStateBits=32 is recommended as the most versatile setting
/// 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,
/// which means a frequency table can only support one symbol with non-zero frequency.</li>
/// </ul>
/// </summary>
protected internal readonly int numStateBits;
/// <summary>
/// Maximum range (high+1-low) during coding (trivial), which is 2^numStateBits = 1000...000. </summary>
protected internal readonly long fullRange;
/// <summary>
/// The top bit at width numStateBits, which is 0100...000. </summary>
protected internal readonly long halfRange;
/// <summary>
/// The second highest bit at width numStateBits, which is 0010...000. This is zero when numStateBits=1. </summary>
protected internal readonly long quarterRange;
/// <summary>
/// Minimum range (high+1-low) during coding (non-trivial), which is 0010...010. </summary>
protected internal readonly long minimumRange;
/// <summary>
/// Maximum allowed total from a frequency table at all times during coding. </summary>
protected internal readonly long maximumTotal;
/// <summary>
/// Bit mask of numStateBits ones, which is 0111...111. </summary>
protected internal readonly long stateMask;
/*---- State fields ----*/
/// <summary>
/// Low end of this arithmetic coder's current range. Conceptually has an infinite number of trailing 0s.
/// </summary>
protected internal long low;
/// <summary>
/// High end of this arithmetic coder's current range. Conceptually has an infinite number of trailing 1s.
/// </summary>
protected internal long high;
/*---- Constructor ----*/
/// <summary>
/// Constructs an arithmetic coder, which initializes the code range. </summary>
/// <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>
public ArithmeticCoderBase(int numBits)
{
if (numBits < 1 || numBits > 62)
{
throw new System.ArgumentException("State size out of range");
}
numStateBits = numBits;
fullRange = 1L << numStateBits;
halfRange = (long)((ulong)fullRange >> 1); // Non-zero
quarterRange = (long)((ulong)halfRange >> 1); // Can be zero
minimumRange = quarterRange + 2; // At least 2
maximumTotal = Math.Min(long.MaxValue / fullRange, minimumRange);
stateMask = fullRange - 1;
low = 0;
high = stateMask;
}
/*---- Methods ----*/
/// <summary>
/// Updates the code range (low and high) of this arithmetic coder as a result
/// of processing the specified symbol with the specified frequency table.
/// <para>Invariants that are true before and after encoding/decoding each symbol
/// (letting fullRange = 2<sup>numStateBits</sup>):</para>
/// <ul>
/// <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>
/// <li>low &lt; 1/2 &times; fullRange &le; high.
/// 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).
/// 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;
/// 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>
/// </ul> </summary>
/// <param name="freqs"> the frequency table to use </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>
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
//ORIGINAL LINE: protected void update(CheckedFrequencyTable freqs, int symbol) throws java.io.IOException
protected internal virtual void update(CheckedFrequencyTable freqs, int symbol)
{
// State check
Debug.Assert(low >= high || (low & stateMask) != low || (high & stateMask) != high, "Low or high out of range");
long range = high - low + 1;
Debug.Assert(range < minimumRange || range > fullRange, "Range out of range");
// Frequency table values check
long total = freqs.Total;
long symLow = freqs.getLow(symbol);
long symHigh = freqs.getHigh(symbol);
Debug.Assert( symLow == symHigh, "Symbol has zero frequency");
Debug.Assert( total > maximumTotal, "Cannot code symbol because total is too large");
// Update range
long newLow = low + symLow * range / total;
long newHigh = low + symHigh * range / total - 1;
low = newLow;
high = newHigh;
// While low and high have the same top bit value, shift them out
while (((low ^ high) & halfRange) == 0)
{
shift();
low = ((low << 1) & stateMask);
high = ((high << 1) & stateMask) | 1;
}
// Now low's top bit must be 0 and high's top bit must be 1
// While low's top two bits are 01 and high's are 10, delete the second highest bit of both
while ((low & ~high & quarterRange) != 0)
{
underflow();
low = (low << 1) ^ halfRange;
high = ((high ^ halfRange) << 1) | halfRange | 1;
}
}
/// <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>
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
//ORIGINAL LINE: protected abstract void shift() throws java.io.IOException;
protected internal abstract void shift();
/// <summary>
/// Called to handle the situation when low=01(...) and high=10(...). </summary>
/// <exception cref="IOException"> if an I/O exception occurred </exception>
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
//ORIGINAL LINE: protected abstract void underflow() throws java.io.IOException;
protected internal abstract void underflow();
}
using System;
using System.Diagnostics;
/*
* Reference arithmetic coding
* Copyright (c) Project Nayuki
*
* https://www.nayuki.io/page/reference-arithmetic-coding
* https://github.com/nayuki/Reference-arithmetic-coding
*/
/// <summary>
/// Provides the state and behaviors that arithmetic coding encoders and decoders share. </summary>
/// <seealso cref= ArithmeticEncoder </seealso>
/// <seealso cref= ArithmeticDecoder </seealso>
public abstract class ArithmeticCoderBase
{
/*---- Configuration fields ----*/
/// <summary>
/// Number of bits for the 'low' and 'high' state variables. Must be in the range [1, 62].
/// <ul>
/// <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
/// 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>
/// <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
/// maximum frequency total, which might constrain the user-supplied probability model.</li>
/// <li>Therefore numStateBits=32 is recommended as the most versatile setting
/// 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,
/// which means a frequency table can only support one symbol with non-zero frequency.</li>
/// </ul>
/// </summary>
protected internal readonly int numStateBits;
/// <summary>
/// Maximum range (high+1-low) during coding (trivial), which is 2^numStateBits = 1000...000. </summary>
protected internal readonly long fullRange;
/// <summary>
/// The top bit at width numStateBits, which is 0100...000. </summary>
protected internal readonly long halfRange;
/// <summary>
/// The second highest bit at width numStateBits, which is 0010...000. This is zero when numStateBits=1. </summary>
protected internal readonly long quarterRange;
/// <summary>
/// Minimum range (high+1-low) during coding (non-trivial), which is 0010...010. </summary>
protected internal readonly long minimumRange;
/// <summary>
/// Maximum allowed total from a frequency table at all times during coding. </summary>
protected internal readonly long maximumTotal;
/// <summary>
/// Bit mask of numStateBits ones, which is 0111...111. </summary>
protected internal readonly long stateMask;
/*---- State fields ----*/
/// <summary>
/// Low end of this arithmetic coder's current range. Conceptually has an infinite number of trailing 0s.
/// </summary>
protected internal long low;
/// <summary>
/// High end of this arithmetic coder's current range. Conceptually has an infinite number of trailing 1s.
/// </summary>
protected internal long high;
/*---- Constructor ----*/
/// <summary>
/// Constructs an arithmetic coder, which initializes the code range. </summary>
/// <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>
public ArithmeticCoderBase(int numBits)
{
if (numBits < 1 || numBits > 62)
{
throw new System.ArgumentException("State size out of range");
}
numStateBits = numBits;
fullRange = 1L << numStateBits;
halfRange = (long)((ulong)fullRange >> 1); // Non-zero
quarterRange = (long)((ulong)halfRange >> 1); // Can be zero
minimumRange = quarterRange + 2; // At least 2
maximumTotal = Math.Min(long.MaxValue / fullRange, minimumRange);
stateMask = fullRange - 1;
low = 0;
high = stateMask;
}
/*---- Methods ----*/
/// <summary>
/// Updates the code range (low and high) of this arithmetic coder as a result
/// of processing the specified symbol with the specified frequency table.
/// <para>Invariants that are true before and after encoding/decoding each symbol
/// (letting fullRange = 2<sup>numStateBits</sup>):</para>
/// <ul>
/// <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>
/// <li>low &lt; 1/2 &times; fullRange &le; high.
/// 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).
/// 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;
/// 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>
/// </ul> </summary>
/// <param name="freqs"> the frequency table to use </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>
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
//ORIGINAL LINE: protected void update(CheckedFrequencyTable freqs, int symbol) throws java.io.IOException
protected internal virtual void update(CheckedFrequencyTable freqs, int symbol)
{
// State check
Debug.Assert(low >= high || (low & stateMask) != low || (high & stateMask) != high, "Low or high out of range");
long range = high - low + 1;
Debug.Assert(range < minimumRange || range > fullRange, "Range out of range");
// Frequency table values check
long total = freqs.Total;
long symLow = freqs.getLow(symbol);
long symHigh = freqs.getHigh(symbol);
Debug.Assert( symLow == symHigh, "Symbol has zero frequency");
Debug.Assert( total > maximumTotal, "Cannot code symbol because total is too large");
// Update range
long newLow = low + symLow * range / total;
long newHigh = low + symHigh * range / total - 1;
low = newLow;
high = newHigh;
// While low and high have the same top bit value, shift them out
while (((low ^ high) & halfRange) == 0)
{
shift();
low = ((low << 1) & stateMask);
high = ((high << 1) & stateMask) | 1;
}
// Now low's top bit must be 0 and high's top bit must be 1
// While low's top two bits are 01 and high's are 10, delete the second highest bit of both
while ((low & ~high & quarterRange) != 0)
{
underflow();
low = (low << 1) ^ halfRange;
high = ((high ^ halfRange) << 1) | halfRange | 1;
}
}
/// <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>
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
//ORIGINAL LINE: protected abstract void shift() throws java.io.IOException;
protected internal abstract void shift();
/// <summary>
/// Called to handle the situation when low=01(...) and high=10(...). </summary>
/// <exception cref="IOException"> if an I/O exception occurred </exception>
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
//ORIGINAL LINE: protected abstract void underflow() throws java.io.IOException;
protected internal abstract void underflow();
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,6 @@
// Copyright (c) Xenko contributors (https://xenko.com) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
// Copyright (c) Xenko contributors (https://xenko.com) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
/* MIT License
Copyright (c) 2016 JetBrains http://www.jetbrains.com
@ -21,12 +21,12 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. */
SOFTWARE. */
using System;
namespace att
{
{
/// <summary>
/// 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.

View File

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

192
db/Act.cs
View File

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

442
db/DB.cs
View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,349 +1,349 @@

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

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

View File

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

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

View File

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