Whitespace changes
This commit is contained in:
parent
f965662031
commit
8879e98229
54
Helpers.cs
54
Helpers.cs
@ -1,8 +1,8 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* TODO: Need to verify types are correct when deserializing.
|
* TODO: Need to verify types are correct when deserializing.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -22,10 +22,10 @@ namespace lib
|
|||||||
{
|
{
|
||||||
FileStream fs = new FileStream( filename, FileMode.Create, FileAccess.Write );
|
FileStream fs = new FileStream( filename, FileMode.Create, FileAccess.Write );
|
||||||
|
|
||||||
XmlSerializer xs = new XmlSerializer( obj.GetType() );
|
XmlSerializer xs = new XmlSerializer( obj.GetType() );
|
||||||
//MemoryStream memoryStream = new MemoryStream( StringToUTF8ByteArray( pXmlizedString ) );
|
//MemoryStream memoryStream = new MemoryStream( StringToUTF8ByteArray( pXmlizedString ) );
|
||||||
//XmlTextReader reader = new XmlTextReader( fs, Encoding.UTF8 );
|
//XmlTextReader reader = new XmlTextReader( fs, Encoding.UTF8 );
|
||||||
|
|
||||||
xs.Serialize( fs, obj );
|
xs.Serialize( fs, obj );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,10 +33,10 @@ namespace lib
|
|||||||
{
|
{
|
||||||
FileStream fs = new FileStream( filename, FileMode.Open, FileAccess.Read );
|
FileStream fs = new FileStream( filename, FileMode.Open, FileAccess.Read );
|
||||||
|
|
||||||
XmlSerializer xs = new XmlSerializer( typeof( TType ) );
|
XmlSerializer xs = new XmlSerializer( typeof( TType ) );
|
||||||
//MemoryStream memoryStream = new MemoryStream( StringToUTF8ByteArray( pXmlizedString ) );
|
//MemoryStream memoryStream = new MemoryStream( StringToUTF8ByteArray( pXmlizedString ) );
|
||||||
//XmlTextReader reader = new XmlTextReader( fs, Encoding.UTF8 );
|
//XmlTextReader reader = new XmlTextReader( fs, Encoding.UTF8 );
|
||||||
|
|
||||||
return xs.Deserialize( fs );
|
return xs.Deserialize( fs );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,10 +72,10 @@ namespace lib
|
|||||||
{
|
{
|
||||||
XmlTextWriter xmlWriter = new XmlTextWriter( filename, null );
|
XmlTextWriter xmlWriter = new XmlTextWriter( filename, null );
|
||||||
|
|
||||||
xmlWriter.Formatting = Formatting.Indented;
|
xmlWriter.Formatting = Formatting.Indented;
|
||||||
|
|
||||||
//xmlWriter.WriteStartDocument();
|
//xmlWriter.WriteStartDocument();
|
||||||
|
|
||||||
xmlWriter.WriteStartElement( "dictionary" );
|
xmlWriter.WriteStartElement( "dictionary" );
|
||||||
|
|
||||||
Type[] types = dict.GetType().GetGenericArguments();
|
Type[] types = dict.GetType().GetGenericArguments();
|
||||||
@ -93,10 +93,10 @@ namespace lib
|
|||||||
xmlWriter.WriteEndElement();
|
xmlWriter.WriteEndElement();
|
||||||
}
|
}
|
||||||
|
|
||||||
xmlWriter.WriteEndElement();
|
xmlWriter.WriteEndElement();
|
||||||
|
|
||||||
//xmlWriter.WriteEndDocument();
|
//xmlWriter.WriteEndDocument();
|
||||||
|
|
||||||
xmlWriter.Close();
|
xmlWriter.Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,10 +106,10 @@ namespace lib
|
|||||||
|
|
||||||
XmlDocument doc = new XmlDocument();
|
XmlDocument doc = new XmlDocument();
|
||||||
|
|
||||||
doc.Load( fs );
|
doc.Load( fs );
|
||||||
|
|
||||||
//CreateTypeFor()
|
//CreateTypeFor()
|
||||||
|
|
||||||
XmlElement docElem = doc.DocumentElement;
|
XmlElement docElem = doc.DocumentElement;
|
||||||
|
|
||||||
if( docElem.Name == "dictionary" )
|
if( docElem.Name == "dictionary" )
|
||||||
@ -125,10 +125,10 @@ namespace lib
|
|||||||
{
|
{
|
||||||
XmlNodeList nodeList = docElem.ChildNodes;
|
XmlNodeList nodeList = docElem.ChildNodes;
|
||||||
|
|
||||||
object[] args = new object[ 1 ];
|
object[] args = new object[ 1 ];
|
||||||
|
|
||||||
//fi.SetValue( newObj, obj );
|
//fi.SetValue( newObj, obj );
|
||||||
|
|
||||||
foreach( XmlElement node in nodeList )
|
foreach( XmlElement node in nodeList )
|
||||||
{
|
{
|
||||||
if( node.Name == "kvp" )
|
if( node.Name == "kvp" )
|
||||||
|
|||||||
108
Token.cs
108
Token.cs
@ -1,54 +1,54 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
|
||||||
namespace lib
|
namespace lib
|
||||||
{
|
{
|
||||||
|
|
||||||
//TODO PERF fix this and make it fast.
|
//TODO PERF fix this and make it fast.
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public struct Token
|
public struct Token
|
||||||
{
|
{
|
||||||
public string str { get { return m_str; } }
|
public string str { get { return m_str; } }
|
||||||
|
|
||||||
public Token( String str )
|
public Token( String str )
|
||||||
{
|
{
|
||||||
m_str = str;
|
m_str = str;
|
||||||
m_hash = m_str.GetHashCode();
|
m_hash = m_str.GetHashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Equals( object obj )
|
public override bool Equals( object obj )
|
||||||
{
|
{
|
||||||
if( !( obj is Token ) )
|
if( !( obj is Token ) )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
//This doesnt use as because Token is a struct
|
//This doesnt use as because Token is a struct
|
||||||
var otherId = (Token)obj;
|
var otherId = (Token)obj;
|
||||||
|
|
||||||
if( m_hash != otherId.m_hash )
|
if( m_hash != otherId.m_hash )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return m_str == otherId.m_str;
|
return m_str == otherId.m_str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public bool Equals_fast( Token other )
|
public bool Equals_fast( Token other )
|
||||||
{
|
{
|
||||||
return m_hash == other.m_hash && m_str == other.m_str;
|
return m_hash == other.m_hash && m_str == other.m_str;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int GetHashCode()
|
public override int GetHashCode()
|
||||||
{
|
{
|
||||||
return m_hash;
|
return m_hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return m_str;
|
return m_str;
|
||||||
}
|
}
|
||||||
|
|
||||||
int m_hash;
|
int m_hash;
|
||||||
String m_str;
|
String m_str;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,32 +1,32 @@
|
|||||||
// Copyright (c) Xenko contributors (https://xenko.com) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
|
// Copyright (c) Xenko contributors (https://xenko.com) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
|
||||||
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
|
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
|
||||||
//
|
//
|
||||||
// Copyright (c) 2010-2012 SharpDX - Alexandre Mutel
|
// Copyright (c) 2010-2012 SharpDX - Alexandre Mutel
|
||||||
//
|
//
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
// in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
// furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
// The above copyright notice and this permission notice shall be included in
|
// The above copyright notice and this permission notice shall be included in
|
||||||
// all copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
// THE SOFTWARE.
|
// THE SOFTWARE.
|
||||||
#pragma warning disable SA1300 // Element must begin with upper-case letter
|
#pragma warning disable SA1300 // Element must begin with upper-case letter
|
||||||
#pragma warning disable SA1649 // File name must match first type name
|
#pragma warning disable SA1649 // File name must match first type name
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace lib
|
namespace lib
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Utility class.
|
/// Utility class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
1700
Utilities.cs
1700
Utilities.cs
File diff suppressed because it is too large
Load Diff
@ -1,73 +1,73 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reference arithmetic coding
|
* Reference arithmetic coding
|
||||||
* Copyright (c) Project Nayuki
|
* Copyright (c) Project Nayuki
|
||||||
*
|
*
|
||||||
* https://www.nayuki.io/page/reference-arithmetic-coding
|
* https://www.nayuki.io/page/reference-arithmetic-coding
|
||||||
* https://github.com/nayuki/Reference-arithmetic-coding
|
* https://github.com/nayuki/Reference-arithmetic-coding
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Compression application using adaptive arithmetic coding.
|
/// Compression application using adaptive arithmetic coding.
|
||||||
/// <para>Usage: java AdaptiveArithmeticCompress InputFile OutputFile</para>
|
/// <para>Usage: java AdaptiveArithmeticCompress InputFile OutputFile</para>
|
||||||
/// <para>Then use the corresponding "AdaptiveArithmeticDecompress" application to recreate the original input file.</para>
|
/// <para>Then use the corresponding "AdaptiveArithmeticDecompress" application to recreate the original input file.</para>
|
||||||
/// <para>Note that the application starts with a flat frequency table of 257 symbols (all set to a frequency of 1),
|
/// <para>Note that the application starts with a flat frequency table of 257 symbols (all set to a frequency of 1),
|
||||||
/// and updates it after each byte encoded. The corresponding decompressor program also starts with a flat
|
/// and updates it after each byte encoded. The corresponding decompressor program also starts with a flat
|
||||||
/// frequency table and updates it after each byte decoded. It is by design that the compressor and
|
/// frequency table and updates it after each byte decoded. It is by design that the compressor and
|
||||||
/// decompressor have synchronized states, so that the data can be decompressed properly.</para>
|
/// decompressor have synchronized states, so that the data can be decompressed properly.</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class AdaptiveArithmeticCompress
|
public class AdaptiveArithmeticCompress
|
||||||
{
|
{
|
||||||
|
|
||||||
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
||||||
//ORIGINAL LINE: public static void main(String[] args) throws java.io.IOException
|
//ORIGINAL LINE: public static void main(String[] args) throws java.io.IOException
|
||||||
public static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
{
|
{
|
||||||
/* @@@@ PORT
|
/* @@@@ PORT
|
||||||
// Handle command line arguments
|
// Handle command line arguments
|
||||||
if (args.Length != 2)
|
if (args.Length != 2)
|
||||||
{
|
{
|
||||||
Console.Error.WriteLine("Usage: java AdaptiveArithmeticCompress InputFile OutputFile");
|
Console.Error.WriteLine("Usage: java AdaptiveArithmeticCompress InputFile OutputFile");
|
||||||
Environment.Exit(1);
|
Environment.Exit(1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
File inputFile = new File(args[0]);
|
File inputFile = new File(args[0]);
|
||||||
File outputFile = new File(args[1]);
|
File outputFile = new File(args[1]);
|
||||||
|
|
||||||
// Perform file compression
|
// Perform file compression
|
||||||
using (Stream @in = new BufferedInputStream(new FileStream(inputFile, FileMode.Open, FileAccess.Read)), BitOutputStream @out = new BitOutputStream(new BufferedOutputStream(new FileStream(outputFile, FileMode.Create, FileAccess.Write))))
|
using (Stream @in = new BufferedInputStream(new FileStream(inputFile, FileMode.Open, FileAccess.Read)), BitOutputStream @out = new BitOutputStream(new BufferedOutputStream(new FileStream(outputFile, FileMode.Create, FileAccess.Write))))
|
||||||
{
|
{
|
||||||
compress(@in, @out);
|
compress(@in, @out);
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// To allow unit testing, this method is package-private instead of private.
|
// To allow unit testing, this method is package-private instead of private.
|
||||||
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
||||||
//ORIGINAL LINE: static void compress(java.io.InputStream in, BitOutputStream out) throws java.io.IOException
|
//ORIGINAL LINE: static void compress(java.io.InputStream in, BitOutputStream out) throws java.io.IOException
|
||||||
internal static void compress(Stream @in, BitOutputStream @out)
|
internal static void compress(Stream @in, BitOutputStream @out)
|
||||||
{
|
{
|
||||||
FlatFrequencyTable initFreqs = new FlatFrequencyTable(257);
|
FlatFrequencyTable initFreqs = new FlatFrequencyTable(257);
|
||||||
FrequencyTable freqs = new SimpleFrequencyTable(initFreqs);
|
FrequencyTable freqs = new SimpleFrequencyTable(initFreqs);
|
||||||
ArithmeticEncoder enc = new ArithmeticEncoder(32, @out);
|
ArithmeticEncoder enc = new ArithmeticEncoder(32, @out);
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
// Read and encode one byte
|
// Read and encode one byte
|
||||||
int symbol = @in.ReadByte();
|
int symbol = @in.ReadByte();
|
||||||
if (symbol == -1)
|
if (symbol == -1)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
enc.write(freqs, symbol);
|
enc.write(freqs, symbol);
|
||||||
freqs.increment(symbol);
|
freqs.increment(symbol);
|
||||||
}
|
}
|
||||||
enc.write(freqs, 256); // EOF
|
enc.write(freqs, 256); // EOF
|
||||||
enc.finish(); // Flush remaining code bits
|
enc.finish(); // Flush remaining code bits
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,67 +1,67 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reference arithmetic coding
|
* Reference arithmetic coding
|
||||||
* Copyright (c) Project Nayuki
|
* Copyright (c) Project Nayuki
|
||||||
*
|
*
|
||||||
* https://www.nayuki.io/page/reference-arithmetic-coding
|
* https://www.nayuki.io/page/reference-arithmetic-coding
|
||||||
* https://github.com/nayuki/Reference-arithmetic-coding
|
* https://github.com/nayuki/Reference-arithmetic-coding
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Decompression application using adaptive arithmetic coding.
|
/// Decompression application using adaptive arithmetic coding.
|
||||||
/// <para>Usage: java AdaptiveArithmeticDecompress InputFile OutputFile</para>
|
/// <para>Usage: java AdaptiveArithmeticDecompress InputFile OutputFile</para>
|
||||||
/// <para>This decompresses files generated by the "AdaptiveArithmeticCompress" application.</para>
|
/// <para>This decompresses files generated by the "AdaptiveArithmeticCompress" application.</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class AdaptiveArithmeticDecompress
|
public class AdaptiveArithmeticDecompress
|
||||||
{
|
{
|
||||||
|
|
||||||
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
||||||
//ORIGINAL LINE: public static void main(String[] args) throws java.io.IOException
|
//ORIGINAL LINE: public static void main(String[] args) throws java.io.IOException
|
||||||
public static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
{
|
{
|
||||||
/* @@@@ PORT
|
/* @@@@ PORT
|
||||||
// Handle command line arguments
|
// Handle command line arguments
|
||||||
if (args.Length != 2)
|
if (args.Length != 2)
|
||||||
{
|
{
|
||||||
Console.Error.WriteLine("Usage: java AdaptiveArithmeticDecompress InputFile OutputFile");
|
Console.Error.WriteLine("Usage: java AdaptiveArithmeticDecompress InputFile OutputFile");
|
||||||
Environment.Exit(1);
|
Environment.Exit(1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
File inputFile = new File(args[0]);
|
File inputFile = new File(args[0]);
|
||||||
File outputFile = new File(args[1]);
|
File outputFile = new File(args[1]);
|
||||||
|
|
||||||
// Perform file decompression
|
// Perform file decompression
|
||||||
using (BitInputStream @in = new BitInputStream(new BufferedInputStream(new FileStream(inputFile, FileMode.Open, FileAccess.Read))), Stream @out = new BufferedOutputStream(new FileStream(outputFile, FileMode.Create, FileAccess.Write)))
|
using (BitInputStream @in = new BitInputStream(new BufferedInputStream(new FileStream(inputFile, FileMode.Open, FileAccess.Read))), Stream @out = new BufferedOutputStream(new FileStream(outputFile, FileMode.Create, FileAccess.Write)))
|
||||||
{
|
{
|
||||||
decompress(@in, @out);
|
decompress(@in, @out);
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// To allow unit testing, this method is package-private instead of private.
|
// To allow unit testing, this method is package-private instead of private.
|
||||||
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
||||||
//ORIGINAL LINE: static void decompress(BitInputStream in, java.io.OutputStream out) throws java.io.IOException
|
//ORIGINAL LINE: static void decompress(BitInputStream in, java.io.OutputStream out) throws java.io.IOException
|
||||||
internal static void decompress(BitInputStream @in, Stream @out)
|
internal static void decompress(BitInputStream @in, Stream @out)
|
||||||
{
|
{
|
||||||
FlatFrequencyTable initFreqs = new FlatFrequencyTable(257);
|
FlatFrequencyTable initFreqs = new FlatFrequencyTable(257);
|
||||||
FrequencyTable freqs = new SimpleFrequencyTable(initFreqs);
|
FrequencyTable freqs = new SimpleFrequencyTable(initFreqs);
|
||||||
ArithmeticDecoder dec = new ArithmeticDecoder(32, @in);
|
ArithmeticDecoder dec = new ArithmeticDecoder(32, @in);
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
// Decode and write one byte
|
// Decode and write one byte
|
||||||
int symbol = dec.read(freqs);
|
int symbol = dec.read(freqs);
|
||||||
if (symbol == 256) // EOF symbol
|
if (symbol == 256) // EOF symbol
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@out.WriteByte((byte)symbol);
|
@out.WriteByte((byte)symbol);
|
||||||
freqs.increment(symbol);
|
freqs.increment(symbol);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,185 +1,185 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reference arithmetic coding
|
* Reference arithmetic coding
|
||||||
* Copyright (c) Project Nayuki
|
* Copyright (c) Project Nayuki
|
||||||
*
|
*
|
||||||
* https://www.nayuki.io/page/reference-arithmetic-coding
|
* https://www.nayuki.io/page/reference-arithmetic-coding
|
||||||
* https://github.com/nayuki/Reference-arithmetic-coding
|
* https://github.com/nayuki/Reference-arithmetic-coding
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Provides the state and behaviors that arithmetic coding encoders and decoders share. </summary>
|
/// Provides the state and behaviors that arithmetic coding encoders and decoders share. </summary>
|
||||||
/// <seealso cref= ArithmeticEncoder </seealso>
|
/// <seealso cref= ArithmeticEncoder </seealso>
|
||||||
/// <seealso cref= ArithmeticDecoder </seealso>
|
/// <seealso cref= ArithmeticDecoder </seealso>
|
||||||
public abstract class ArithmeticCoderBase
|
public abstract class ArithmeticCoderBase
|
||||||
{
|
{
|
||||||
|
|
||||||
/*---- Configuration fields ----*/
|
/*---- Configuration fields ----*/
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Number of bits for the 'low' and 'high' state variables. Must be in the range [1, 62].
|
/// Number of bits for the 'low' and 'high' state variables. Must be in the range [1, 62].
|
||||||
/// <ul>
|
/// <ul>
|
||||||
/// <li>For state sizes less than the midpoint of around 32, larger values are generally better -
|
/// <li>For state sizes less than the midpoint of around 32, larger values are generally better -
|
||||||
/// they allow a larger maximum frequency total (maximumTotal), and they reduce the approximation
|
/// they allow a larger maximum frequency total (maximumTotal), and they reduce the approximation
|
||||||
/// error inherent in adapting fractions to integers; both effects reduce the data encoding loss
|
/// error inherent in adapting fractions to integers; both effects reduce the data encoding loss
|
||||||
/// and asymptotically approach the efficiency of arithmetic coding using exact fractions.</li>
|
/// and asymptotically approach the efficiency of arithmetic coding using exact fractions.</li>
|
||||||
/// <li>But for state sizes greater than the midpoint, because intermediate computations are limited
|
/// <li>But for state sizes greater than the midpoint, because intermediate computations are limited
|
||||||
/// to the long integer type's 63-bit unsigned precision, larger state sizes will decrease the
|
/// to the long integer type's 63-bit unsigned precision, larger state sizes will decrease the
|
||||||
/// maximum frequency total, which might constrain the user-supplied probability model.</li>
|
/// maximum frequency total, which might constrain the user-supplied probability model.</li>
|
||||||
/// <li>Therefore numStateBits=32 is recommended as the most versatile setting
|
/// <li>Therefore numStateBits=32 is recommended as the most versatile setting
|
||||||
/// because it maximizes maximumTotal (which ends up being slightly over 2^30).</li>
|
/// because it maximizes maximumTotal (which ends up being slightly over 2^30).</li>
|
||||||
/// <li>Note that numStateBits=62 is legal but useless because it implies maximumTotal=1,
|
/// <li>Note that numStateBits=62 is legal but useless because it implies maximumTotal=1,
|
||||||
/// which means a frequency table can only support one symbol with non-zero frequency.</li>
|
/// which means a frequency table can only support one symbol with non-zero frequency.</li>
|
||||||
/// </ul>
|
/// </ul>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected internal readonly int numStateBits;
|
protected internal readonly int numStateBits;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Maximum range (high+1-low) during coding (trivial), which is 2^numStateBits = 1000...000. </summary>
|
/// Maximum range (high+1-low) during coding (trivial), which is 2^numStateBits = 1000...000. </summary>
|
||||||
protected internal readonly long fullRange;
|
protected internal readonly long fullRange;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The top bit at width numStateBits, which is 0100...000. </summary>
|
/// The top bit at width numStateBits, which is 0100...000. </summary>
|
||||||
protected internal readonly long halfRange;
|
protected internal readonly long halfRange;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The second highest bit at width numStateBits, which is 0010...000. This is zero when numStateBits=1. </summary>
|
/// The second highest bit at width numStateBits, which is 0010...000. This is zero when numStateBits=1. </summary>
|
||||||
protected internal readonly long quarterRange;
|
protected internal readonly long quarterRange;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Minimum range (high+1-low) during coding (non-trivial), which is 0010...010. </summary>
|
/// Minimum range (high+1-low) during coding (non-trivial), which is 0010...010. </summary>
|
||||||
protected internal readonly long minimumRange;
|
protected internal readonly long minimumRange;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Maximum allowed total from a frequency table at all times during coding. </summary>
|
/// Maximum allowed total from a frequency table at all times during coding. </summary>
|
||||||
protected internal readonly long maximumTotal;
|
protected internal readonly long maximumTotal;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Bit mask of numStateBits ones, which is 0111...111. </summary>
|
/// Bit mask of numStateBits ones, which is 0111...111. </summary>
|
||||||
protected internal readonly long stateMask;
|
protected internal readonly long stateMask;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*---- State fields ----*/
|
/*---- State fields ----*/
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Low end of this arithmetic coder's current range. Conceptually has an infinite number of trailing 0s.
|
/// Low end of this arithmetic coder's current range. Conceptually has an infinite number of trailing 0s.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected internal long low;
|
protected internal long low;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// High end of this arithmetic coder's current range. Conceptually has an infinite number of trailing 1s.
|
/// High end of this arithmetic coder's current range. Conceptually has an infinite number of trailing 1s.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected internal long high;
|
protected internal long high;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*---- Constructor ----*/
|
/*---- Constructor ----*/
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Constructs an arithmetic coder, which initializes the code range. </summary>
|
/// Constructs an arithmetic coder, which initializes the code range. </summary>
|
||||||
/// <param name="numBits"> the number of bits for the arithmetic coding range </param>
|
/// <param name="numBits"> the number of bits for the arithmetic coding range </param>
|
||||||
/// <exception cref="IllegalArgumentException"> if stateSize is outside the range [1, 62] </exception>
|
/// <exception cref="IllegalArgumentException"> if stateSize is outside the range [1, 62] </exception>
|
||||||
public ArithmeticCoderBase(int numBits)
|
public ArithmeticCoderBase(int numBits)
|
||||||
{
|
{
|
||||||
if (numBits < 1 || numBits > 62)
|
if (numBits < 1 || numBits > 62)
|
||||||
{
|
{
|
||||||
throw new System.ArgumentException("State size out of range");
|
throw new System.ArgumentException("State size out of range");
|
||||||
}
|
}
|
||||||
numStateBits = numBits;
|
numStateBits = numBits;
|
||||||
fullRange = 1L << numStateBits;
|
fullRange = 1L << numStateBits;
|
||||||
halfRange = (long)((ulong)fullRange >> 1); // Non-zero
|
halfRange = (long)((ulong)fullRange >> 1); // Non-zero
|
||||||
quarterRange = (long)((ulong)halfRange >> 1); // Can be zero
|
quarterRange = (long)((ulong)halfRange >> 1); // Can be zero
|
||||||
minimumRange = quarterRange + 2; // At least 2
|
minimumRange = quarterRange + 2; // At least 2
|
||||||
maximumTotal = Math.Min(long.MaxValue / fullRange, minimumRange);
|
maximumTotal = Math.Min(long.MaxValue / fullRange, minimumRange);
|
||||||
stateMask = fullRange - 1;
|
stateMask = fullRange - 1;
|
||||||
|
|
||||||
low = 0;
|
low = 0;
|
||||||
high = stateMask;
|
high = stateMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*---- Methods ----*/
|
/*---- Methods ----*/
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Updates the code range (low and high) of this arithmetic coder as a result
|
/// Updates the code range (low and high) of this arithmetic coder as a result
|
||||||
/// of processing the specified symbol with the specified frequency table.
|
/// of processing the specified symbol with the specified frequency table.
|
||||||
/// <para>Invariants that are true before and after encoding/decoding each symbol
|
/// <para>Invariants that are true before and after encoding/decoding each symbol
|
||||||
/// (letting fullRange = 2<sup>numStateBits</sup>):</para>
|
/// (letting fullRange = 2<sup>numStateBits</sup>):</para>
|
||||||
/// <ul>
|
/// <ul>
|
||||||
/// <li>0 ≤ low ≤ code ≤ high < fullRange. ('code' exists only in the decoder.)
|
/// <li>0 ≤ low ≤ code ≤ high < fullRange. ('code' exists only in the decoder.)
|
||||||
/// Therefore these variables are unsigned integers of numStateBits bits.</li>
|
/// Therefore these variables are unsigned integers of numStateBits bits.</li>
|
||||||
/// <li>low < 1/2 × fullRange ≤ high.
|
/// <li>low < 1/2 × fullRange ≤ high.
|
||||||
/// In other words, they are in different halves of the full range.</li>
|
/// In other words, they are in different halves of the full range.</li>
|
||||||
/// <li>(low < 1/4 × fullRange) || (high ≥ 3/4 × fullRange).
|
/// <li>(low < 1/4 × fullRange) || (high ≥ 3/4 × fullRange).
|
||||||
/// In other words, they are not both in the middle two quarters.</li>
|
/// In other words, they are not both in the middle two quarters.</li>
|
||||||
/// <li>Let range = high − low + 1, then fullRange/4 < minimumRange ≤ range ≤
|
/// <li>Let range = high − low + 1, then fullRange/4 < minimumRange ≤ range ≤
|
||||||
/// fullRange. These invariants for 'range' essentially dictate the maximum total that the
|
/// fullRange. These invariants for 'range' essentially dictate the maximum total that the
|
||||||
/// incoming frequency table can have, such that intermediate calculations don't overflow.</li>
|
/// incoming frequency table can have, such that intermediate calculations don't overflow.</li>
|
||||||
/// </ul> </summary>
|
/// </ul> </summary>
|
||||||
/// <param name="freqs"> the frequency table to use </param>
|
/// <param name="freqs"> the frequency table to use </param>
|
||||||
/// <param name="symbol"> the symbol that was processed </param>
|
/// <param name="symbol"> the symbol that was processed </param>
|
||||||
/// <exception cref="IllegalArgumentException"> if the symbol has zero frequency or the frequency table's total is too large </exception>
|
/// <exception cref="IllegalArgumentException"> if the symbol has zero frequency or the frequency table's total is too large </exception>
|
||||||
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
||||||
//ORIGINAL LINE: protected void update(CheckedFrequencyTable freqs, int symbol) throws java.io.IOException
|
//ORIGINAL LINE: protected void update(CheckedFrequencyTable freqs, int symbol) throws java.io.IOException
|
||||||
protected internal virtual void update(CheckedFrequencyTable freqs, int symbol)
|
protected internal virtual void update(CheckedFrequencyTable freqs, int symbol)
|
||||||
{
|
{
|
||||||
// State check
|
// State check
|
||||||
Debug.Assert(low >= high || (low & stateMask) != low || (high & stateMask) != high, "Low or high out of range");
|
Debug.Assert(low >= high || (low & stateMask) != low || (high & stateMask) != high, "Low or high out of range");
|
||||||
|
|
||||||
long range = high - low + 1;
|
long range = high - low + 1;
|
||||||
Debug.Assert(range < minimumRange || range > fullRange, "Range out of range");
|
Debug.Assert(range < minimumRange || range > fullRange, "Range out of range");
|
||||||
|
|
||||||
// Frequency table values check
|
// Frequency table values check
|
||||||
long total = freqs.Total;
|
long total = freqs.Total;
|
||||||
long symLow = freqs.getLow(symbol);
|
long symLow = freqs.getLow(symbol);
|
||||||
long symHigh = freqs.getHigh(symbol);
|
long symHigh = freqs.getHigh(symbol);
|
||||||
Debug.Assert( symLow == symHigh, "Symbol has zero frequency");
|
Debug.Assert( symLow == symHigh, "Symbol has zero frequency");
|
||||||
|
|
||||||
Debug.Assert( total > maximumTotal, "Cannot code symbol because total is too large");
|
Debug.Assert( total > maximumTotal, "Cannot code symbol because total is too large");
|
||||||
|
|
||||||
// Update range
|
// Update range
|
||||||
long newLow = low + symLow * range / total;
|
long newLow = low + symLow * range / total;
|
||||||
long newHigh = low + symHigh * range / total - 1;
|
long newHigh = low + symHigh * range / total - 1;
|
||||||
low = newLow;
|
low = newLow;
|
||||||
high = newHigh;
|
high = newHigh;
|
||||||
|
|
||||||
// While low and high have the same top bit value, shift them out
|
// While low and high have the same top bit value, shift them out
|
||||||
while (((low ^ high) & halfRange) == 0)
|
while (((low ^ high) & halfRange) == 0)
|
||||||
{
|
{
|
||||||
shift();
|
shift();
|
||||||
low = ((low << 1) & stateMask);
|
low = ((low << 1) & stateMask);
|
||||||
high = ((high << 1) & stateMask) | 1;
|
high = ((high << 1) & stateMask) | 1;
|
||||||
}
|
}
|
||||||
// Now low's top bit must be 0 and high's top bit must be 1
|
// Now low's top bit must be 0 and high's top bit must be 1
|
||||||
|
|
||||||
// While low's top two bits are 01 and high's are 10, delete the second highest bit of both
|
// While low's top two bits are 01 and high's are 10, delete the second highest bit of both
|
||||||
while ((low & ~high & quarterRange) != 0)
|
while ((low & ~high & quarterRange) != 0)
|
||||||
{
|
{
|
||||||
underflow();
|
underflow();
|
||||||
low = (low << 1) ^ halfRange;
|
low = (low << 1) ^ halfRange;
|
||||||
high = ((high ^ halfRange) << 1) | halfRange | 1;
|
high = ((high ^ halfRange) << 1) | halfRange | 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called to handle the situation when the top bit of {@code low} and {@code high} are equal. </summary>
|
/// Called to handle the situation when the top bit of {@code low} and {@code high} are equal. </summary>
|
||||||
/// <exception cref="IOException"> if an I/O exception occurred </exception>
|
/// <exception cref="IOException"> if an I/O exception occurred </exception>
|
||||||
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
||||||
//ORIGINAL LINE: protected abstract void shift() throws java.io.IOException;
|
//ORIGINAL LINE: protected abstract void shift() throws java.io.IOException;
|
||||||
protected internal abstract void shift();
|
protected internal abstract void shift();
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called to handle the situation when low=01(...) and high=10(...). </summary>
|
/// Called to handle the situation when low=01(...) and high=10(...). </summary>
|
||||||
/// <exception cref="IOException"> if an I/O exception occurred </exception>
|
/// <exception cref="IOException"> if an I/O exception occurred </exception>
|
||||||
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
||||||
//ORIGINAL LINE: protected abstract void underflow() throws java.io.IOException;
|
//ORIGINAL LINE: protected abstract void underflow() throws java.io.IOException;
|
||||||
protected internal abstract void underflow();
|
protected internal abstract void underflow();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,127 +1,127 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reference arithmetic coding
|
* Reference arithmetic coding
|
||||||
* Copyright (c) Project Nayuki
|
* Copyright (c) Project Nayuki
|
||||||
*
|
*
|
||||||
* https://www.nayuki.io/page/reference-arithmetic-coding
|
* https://www.nayuki.io/page/reference-arithmetic-coding
|
||||||
* https://github.com/nayuki/Reference-arithmetic-coding
|
* https://github.com/nayuki/Reference-arithmetic-coding
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Compression application using static arithmetic coding.
|
/// Compression application using static arithmetic coding.
|
||||||
/// <para>Usage: java ArithmeticCompress InputFile OutputFile</para>
|
/// <para>Usage: java ArithmeticCompress InputFile OutputFile</para>
|
||||||
/// <para>Then use the corresponding "ArithmeticDecompress" application to recreate the original input file.</para>
|
/// <para>Then use the corresponding "ArithmeticDecompress" application to recreate the original input file.</para>
|
||||||
/// <para>Note that the application uses an alphabet of 257 symbols - 256 symbols for the byte
|
/// <para>Note that the application uses an alphabet of 257 symbols - 256 symbols for the byte
|
||||||
/// values and 1 symbol for the EOF marker. The compressed file format starts with a list
|
/// values and 1 symbol for the EOF marker. The compressed file format starts with a list
|
||||||
/// of 256 symbol frequencies, and then followed by the arithmetic-coded data.</para>
|
/// of 256 symbol frequencies, and then followed by the arithmetic-coded data.</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ArithmeticCompress
|
public class ArithmeticCompress
|
||||||
{
|
{
|
||||||
|
|
||||||
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
||||||
//ORIGINAL LINE: public static void main(String[] args) throws java.io.IOException
|
//ORIGINAL LINE: public static void main(String[] args) throws java.io.IOException
|
||||||
public static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
{
|
{
|
||||||
/* @@ PORT
|
/* @@ PORT
|
||||||
// Handle command line arguments
|
// Handle command line arguments
|
||||||
if (args.Length != 2)
|
if (args.Length != 2)
|
||||||
{
|
{
|
||||||
Console.Error.WriteLine("Usage: java ArithmeticCompress InputFile OutputFile");
|
Console.Error.WriteLine("Usage: java ArithmeticCompress InputFile OutputFile");
|
||||||
Environment.Exit(1);
|
Environment.Exit(1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
File inputFile = new File(args[0]);
|
File inputFile = new File(args[0]);
|
||||||
File outputFile = new File(args[1]);
|
File outputFile = new File(args[1]);
|
||||||
|
|
||||||
// Read input file once to compute symbol frequencies
|
// Read input file once to compute symbol frequencies
|
||||||
FrequencyTable freqs = getFrequencies(inputFile);
|
FrequencyTable freqs = getFrequencies(inputFile);
|
||||||
freqs.increment(256); // EOF symbol gets a frequency of 1
|
freqs.increment(256); // EOF symbol gets a frequency of 1
|
||||||
|
|
||||||
// Read input file again, compress with arithmetic coding, and write output file
|
// Read input file again, compress with arithmetic coding, and write output file
|
||||||
using (Stream @in = new BufferedInputStream(new FileStream(inputFile, FileMode.Open, FileAccess.Read)), BitOutputStream @out = new BitOutputStream(new BufferedOutputStream(new FileStream(outputFile, FileMode.Create, FileAccess.Write))))
|
using (Stream @in = new BufferedInputStream(new FileStream(inputFile, FileMode.Open, FileAccess.Read)), BitOutputStream @out = new BitOutputStream(new BufferedOutputStream(new FileStream(outputFile, FileMode.Create, FileAccess.Write))))
|
||||||
{
|
{
|
||||||
writeFrequencies(@out, freqs);
|
writeFrequencies(@out, freqs);
|
||||||
compress(freqs, @in, @out);
|
compress(freqs, @in, @out);
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Returns a frequency table based on the bytes in the given file.
|
// Returns a frequency table based on the bytes in the given file.
|
||||||
// Also contains an extra entry for symbol 256, whose frequency is set to 0.
|
// Also contains an extra entry for symbol 256, whose frequency is set to 0.
|
||||||
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
||||||
//ORIGINAL LINE: private static FrequencyTable getFrequencies(java.io.File file) throws java.io.IOException
|
//ORIGINAL LINE: private static FrequencyTable getFrequencies(java.io.File file) throws java.io.IOException
|
||||||
private static FrequencyTable getFrequencies(string file)
|
private static FrequencyTable getFrequencies(string file)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
FrequencyTable freqs = new SimpleFrequencyTable(new int[257]);
|
FrequencyTable freqs = new SimpleFrequencyTable(new int[257]);
|
||||||
using (Stream input = new BufferedStream( new FileStream(file, FileMode.Open, FileAccess.Read)))
|
using (Stream input = new BufferedStream( new FileStream(file, FileMode.Open, FileAccess.Read)))
|
||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
int b = input.ReadByte();
|
int b = input.ReadByte();
|
||||||
if (b == -1)
|
if (b == -1)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
freqs.increment(b);
|
freqs.increment(b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return freqs;
|
return freqs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// To allow unit testing, this method is package-private instead of private.
|
// To allow unit testing, this method is package-private instead of private.
|
||||||
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
||||||
//ORIGINAL LINE: static void writeFrequencies(BitOutputStream out, FrequencyTable freqs) throws java.io.IOException
|
//ORIGINAL LINE: static void writeFrequencies(BitOutputStream out, FrequencyTable freqs) throws java.io.IOException
|
||||||
internal static void writeFrequencies(BitOutputStream @out, FrequencyTable freqs)
|
internal static void writeFrequencies(BitOutputStream @out, FrequencyTable freqs)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < 256; i++)
|
for (int i = 0; i < 256; i++)
|
||||||
{
|
{
|
||||||
writeInt(@out, 32, freqs.get(i));
|
writeInt(@out, 32, freqs.get(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// To allow unit testing, this method is package-private instead of private.
|
// To allow unit testing, this method is package-private instead of private.
|
||||||
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
||||||
//ORIGINAL LINE: static void compress(FrequencyTable freqs, java.io.InputStream in, BitOutputStream out) throws java.io.IOException
|
//ORIGINAL LINE: static void compress(FrequencyTable freqs, java.io.InputStream in, BitOutputStream out) throws java.io.IOException
|
||||||
internal static void compress(FrequencyTable freqs, Stream @in, BitOutputStream @out)
|
internal static void compress(FrequencyTable freqs, Stream @in, BitOutputStream @out)
|
||||||
{
|
{
|
||||||
ArithmeticEncoder enc = new ArithmeticEncoder(32, @out);
|
ArithmeticEncoder enc = new ArithmeticEncoder(32, @out);
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
int symbol = @in.ReadByte();
|
int symbol = @in.ReadByte();
|
||||||
if (symbol == -1)
|
if (symbol == -1)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
enc.write(freqs, symbol);
|
enc.write(freqs, symbol);
|
||||||
}
|
}
|
||||||
enc.write(freqs, 256); // EOF
|
enc.write(freqs, 256); // EOF
|
||||||
enc.finish(); // Flush remaining code bits
|
enc.finish(); // Flush remaining code bits
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Writes an unsigned integer of the given bit width to the given stream.
|
// Writes an unsigned integer of the given bit width to the given stream.
|
||||||
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
||||||
//ORIGINAL LINE: private static void writeInt(BitOutputStream out, int numBits, int value) throws java.io.IOException
|
//ORIGINAL LINE: private static void writeInt(BitOutputStream out, int numBits, int value) throws java.io.IOException
|
||||||
private static void writeInt(BitOutputStream @out, int numBits, int value)
|
private static void writeInt(BitOutputStream @out, int numBits, int value)
|
||||||
{
|
{
|
||||||
if (numBits < 0 || numBits > 32)
|
if (numBits < 0 || numBits > 32)
|
||||||
{
|
{
|
||||||
throw new System.ArgumentException();
|
throw new System.ArgumentException();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = numBits - 1; i >= 0; i--)
|
for (int i = numBits - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
@out.write(((int)((uint)value >> i)) & 1); // Big endian
|
@out.write(((int)((uint)value >> i)) & 1); // Big endian
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,152 +1,152 @@
|
|||||||
/*
|
/*
|
||||||
* Reference arithmetic coding
|
* Reference arithmetic coding
|
||||||
* Copyright (c) Project Nayuki
|
* Copyright (c) Project Nayuki
|
||||||
*
|
*
|
||||||
* https://www.nayuki.io/page/reference-arithmetic-coding
|
* https://www.nayuki.io/page/reference-arithmetic-coding
|
||||||
* https://github.com/nayuki/Reference-arithmetic-coding
|
* https://github.com/nayuki/Reference-arithmetic-coding
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reads from an arithmetic-coded bit stream and decodes symbols. Not thread-safe. </summary>
|
/// Reads from an arithmetic-coded bit stream and decodes symbols. Not thread-safe. </summary>
|
||||||
/// <seealso cref= ArithmeticEncoder </seealso>
|
/// <seealso cref= ArithmeticEncoder </seealso>
|
||||||
public sealed class ArithmeticDecoder : ArithmeticCoderBase
|
public sealed class ArithmeticDecoder : ArithmeticCoderBase
|
||||||
{
|
{
|
||||||
|
|
||||||
/*---- Fields ----*/
|
/*---- Fields ----*/
|
||||||
|
|
||||||
// The underlying bit input stream (not null).
|
// The underlying bit input stream (not null).
|
||||||
private BitInputStream input;
|
private BitInputStream input;
|
||||||
|
|
||||||
// The current raw code bits being buffered, which is always in the range [low, high].
|
// The current raw code bits being buffered, which is always in the range [low, high].
|
||||||
private long code;
|
private long code;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*---- Constructor ----*/
|
/*---- Constructor ----*/
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Constructs an arithmetic coding decoder based on the
|
/// Constructs an arithmetic coding decoder based on the
|
||||||
/// specified bit input stream, and fills the code bits. </summary>
|
/// specified bit input stream, and fills the code bits. </summary>
|
||||||
/// <param name="numBits"> the number of bits for the arithmetic coding range </param>
|
/// <param name="numBits"> the number of bits for the arithmetic coding range </param>
|
||||||
/// <param name="in"> the bit input stream to read from </param>
|
/// <param name="in"> the bit input stream to read from </param>
|
||||||
/// <exception cref="NullPointerException"> if the input steam is {@code null} </exception>
|
/// <exception cref="NullPointerException"> if the input steam is {@code null} </exception>
|
||||||
/// <exception cref="IllegalArgumentException"> if stateSize is outside the range [1, 62] </exception>
|
/// <exception cref="IllegalArgumentException"> if stateSize is outside the range [1, 62] </exception>
|
||||||
/// <exception cref="IOException"> if an I/O exception occurred </exception>
|
/// <exception cref="IOException"> if an I/O exception occurred </exception>
|
||||||
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
||||||
//ORIGINAL LINE: public ArithmeticDecoder(int numBits, BitInputStream in) throws java.io.IOException
|
//ORIGINAL LINE: public ArithmeticDecoder(int numBits, BitInputStream in) throws java.io.IOException
|
||||||
public ArithmeticDecoder(int numBits, BitInputStream @in) : base(numBits)
|
public ArithmeticDecoder(int numBits, BitInputStream @in) : base(numBits)
|
||||||
{
|
{
|
||||||
input = @in; //Objects.requireNonNull(@in);
|
input = @in; //Objects.requireNonNull(@in);
|
||||||
code = 0;
|
code = 0;
|
||||||
for (int i = 0; i < numStateBits; i++)
|
for (int i = 0; i < numStateBits; i++)
|
||||||
{
|
{
|
||||||
code = code << 1 | readCodeBit();
|
code = code << 1 | readCodeBit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*---- Methods ----*/
|
/*---- Methods ----*/
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Decodes the next symbol based on the specified frequency table and returns it.
|
/// Decodes the next symbol based on the specified frequency table and returns it.
|
||||||
/// Also updates this arithmetic coder's state and may read in some bits. </summary>
|
/// Also updates this arithmetic coder's state and may read in some bits. </summary>
|
||||||
/// <param name="freqs"> the frequency table to use </param>
|
/// <param name="freqs"> the frequency table to use </param>
|
||||||
/// <returns> the next symbol </returns>
|
/// <returns> the next symbol </returns>
|
||||||
/// <exception cref="NullPointerException"> if the frequency table is {@code null} </exception>
|
/// <exception cref="NullPointerException"> if the frequency table is {@code null} </exception>
|
||||||
/// <exception cref="IOException"> if an I/O exception occurred </exception>
|
/// <exception cref="IOException"> if an I/O exception occurred </exception>
|
||||||
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
||||||
//ORIGINAL LINE: public int read(FrequencyTable freqs) throws java.io.IOException
|
//ORIGINAL LINE: public int read(FrequencyTable freqs) throws java.io.IOException
|
||||||
public int read(FrequencyTable freqs)
|
public int read(FrequencyTable freqs)
|
||||||
{
|
{
|
||||||
return read(new CheckedFrequencyTable(freqs));
|
return read(new CheckedFrequencyTable(freqs));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Decodes the next symbol based on the specified frequency table and returns it.
|
/// Decodes the next symbol based on the specified frequency table and returns it.
|
||||||
/// Also updates this arithmetic coder's state and may read in some bits. </summary>
|
/// Also updates this arithmetic coder's state and may read in some bits. </summary>
|
||||||
/// <param name="freqs"> the frequency table to use </param>
|
/// <param name="freqs"> the frequency table to use </param>
|
||||||
/// <returns> the next symbol </returns>
|
/// <returns> the next symbol </returns>
|
||||||
/// <exception cref="NullPointerException"> if the frequency table is {@code null} </exception>
|
/// <exception cref="NullPointerException"> if the frequency table is {@code null} </exception>
|
||||||
/// <exception cref="IllegalArgumentException"> if the frequency table's total is too large </exception>
|
/// <exception cref="IllegalArgumentException"> if the frequency table's total is too large </exception>
|
||||||
/// <exception cref="IOException"> if an I/O exception occurred </exception>
|
/// <exception cref="IOException"> if an I/O exception occurred </exception>
|
||||||
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
||||||
//ORIGINAL LINE: public int read(CheckedFrequencyTable freqs) throws java.io.IOException
|
//ORIGINAL LINE: public int read(CheckedFrequencyTable freqs) throws java.io.IOException
|
||||||
public int read(CheckedFrequencyTable freqs)
|
public int read(CheckedFrequencyTable freqs)
|
||||||
{
|
{
|
||||||
// Translate from coding range scale to frequency table scale
|
// Translate from coding range scale to frequency table scale
|
||||||
long total = freqs.Total;
|
long total = freqs.Total;
|
||||||
if (total > maximumTotal)
|
if (total > maximumTotal)
|
||||||
{
|
{
|
||||||
throw new System.ArgumentException("Cannot decode symbol because total is too large");
|
throw new System.ArgumentException("Cannot decode symbol because total is too large");
|
||||||
}
|
}
|
||||||
long range = high - low + 1;
|
long range = high - low + 1;
|
||||||
long offset = code - low;
|
long offset = code - low;
|
||||||
long value = ((offset + 1) * total - 1) / range;
|
long value = ((offset + 1) * total - 1) / range;
|
||||||
Debug.Assert(value * range / total > offset);
|
Debug.Assert(value * range / total > offset);
|
||||||
|
|
||||||
Debug.Assert(value < 0 || value >= total);
|
Debug.Assert(value < 0 || value >= total);
|
||||||
|
|
||||||
// A kind of binary search. Find highest symbol such that freqs.getLow(symbol) <= value.
|
// A kind of binary search. Find highest symbol such that freqs.getLow(symbol) <= value.
|
||||||
int start = 0;
|
int start = 0;
|
||||||
int end = freqs.SymbolLimit;
|
int end = freqs.SymbolLimit;
|
||||||
while (end - start > 1)
|
while (end - start > 1)
|
||||||
{
|
{
|
||||||
int middle = (int)((uint)(start + end) >> 1);
|
int middle = (int)((uint)(start + end) >> 1);
|
||||||
if (freqs.getLow(middle) > value)
|
if (freqs.getLow(middle) > value)
|
||||||
{
|
{
|
||||||
end = middle;
|
end = middle;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
start = middle;
|
start = middle;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Debug.Assert( start + 1 != end);
|
Debug.Assert( start + 1 != end);
|
||||||
|
|
||||||
|
|
||||||
int symbol = start;
|
int symbol = start;
|
||||||
Debug.Assert(offset < freqs.getLow(symbol) * range / total || freqs.getHigh(symbol) * range / total <= offset);
|
Debug.Assert(offset < freqs.getLow(symbol) * range / total || freqs.getHigh(symbol) * range / total <= offset);
|
||||||
|
|
||||||
update(freqs, symbol);
|
update(freqs, symbol);
|
||||||
Debug.Assert(code < low || code > high);
|
Debug.Assert(code < low || code > high);
|
||||||
|
|
||||||
return symbol;
|
return symbol;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
||||||
//ORIGINAL LINE: protected void shift() throws java.io.IOException
|
//ORIGINAL LINE: protected void shift() throws java.io.IOException
|
||||||
protected internal override void shift()
|
protected internal override void shift()
|
||||||
{
|
{
|
||||||
code = ((code << 1) & stateMask) | readCodeBit();
|
code = ((code << 1) & stateMask) | readCodeBit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
||||||
//ORIGINAL LINE: protected void underflow() throws java.io.IOException
|
//ORIGINAL LINE: protected void underflow() throws java.io.IOException
|
||||||
protected internal override void underflow()
|
protected internal override void underflow()
|
||||||
{
|
{
|
||||||
code = (code & halfRange) | ((code << 1) & ((long)((ulong)stateMask >> 1))) | readCodeBit();
|
code = (code & halfRange) | ((code << 1) & ((long)((ulong)stateMask >> 1))) | readCodeBit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Returns the next bit (0 or 1) from the input stream. The end
|
// Returns the next bit (0 or 1) from the input stream. The end
|
||||||
// of stream is treated as an infinite number of trailing zeros.
|
// of stream is treated as an infinite number of trailing zeros.
|
||||||
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
||||||
//ORIGINAL LINE: private int readCodeBit() throws java.io.IOException
|
//ORIGINAL LINE: private int readCodeBit() throws java.io.IOException
|
||||||
private int readCodeBit()
|
private int readCodeBit()
|
||||||
{
|
{
|
||||||
int temp = input.read();
|
int temp = input.read();
|
||||||
if (temp == -1)
|
if (temp == -1)
|
||||||
{
|
{
|
||||||
temp = 0;
|
temp = 0;
|
||||||
}
|
}
|
||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,99 +1,99 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reference arithmetic coding
|
* Reference arithmetic coding
|
||||||
* Copyright (c) Project Nayuki
|
* Copyright (c) Project Nayuki
|
||||||
*
|
*
|
||||||
* https://www.nayuki.io/page/reference-arithmetic-coding
|
* https://www.nayuki.io/page/reference-arithmetic-coding
|
||||||
* https://github.com/nayuki/Reference-arithmetic-coding
|
* https://github.com/nayuki/Reference-arithmetic-coding
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Decompression application using static arithmetic coding.
|
/// Decompression application using static arithmetic coding.
|
||||||
/// <para>Usage: java ArithmeticDecompress InputFile OutputFile</para>
|
/// <para>Usage: java ArithmeticDecompress InputFile OutputFile</para>
|
||||||
/// <para>This decompresses files generated by the "ArithmeticCompress" application.</para>
|
/// <para>This decompresses files generated by the "ArithmeticCompress" application.</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ArithmeticDecompress
|
public class ArithmeticDecompress
|
||||||
{
|
{
|
||||||
|
|
||||||
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
||||||
//ORIGINAL LINE: public static void main(String[] args) throws java.io.IOException
|
//ORIGINAL LINE: public static void main(String[] args) throws java.io.IOException
|
||||||
public static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
{
|
{
|
||||||
// Handle command line arguments
|
// Handle command line arguments
|
||||||
if (args.Length != 2)
|
if (args.Length != 2)
|
||||||
{
|
{
|
||||||
Console.Error.WriteLine("Usage: java ArithmeticDecompress InputFile OutputFile");
|
Console.Error.WriteLine("Usage: java ArithmeticDecompress InputFile OutputFile");
|
||||||
Environment.Exit(1);
|
Environment.Exit(1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
string inputFile = args[0]; // new File(args[0]);
|
string inputFile = args[0]; // new File(args[0]);
|
||||||
string outputFile = args[1]; //new File(args[1]);
|
string outputFile = args[1]; //new File(args[1]);
|
||||||
|
|
||||||
// Perform file decompression
|
// Perform file decompression
|
||||||
using( BitInputStream @in = new BitInputStream(new BufferedStream(new FileStream(inputFile, FileMode.Open, FileAccess.Read))))
|
using( BitInputStream @in = new BitInputStream(new BufferedStream(new FileStream(inputFile, FileMode.Open, FileAccess.Read))))
|
||||||
using( Stream @out = new BufferedStream(new FileStream(outputFile, FileMode.Create, FileAccess.Write) ) )
|
using( Stream @out = new BufferedStream(new FileStream(outputFile, FileMode.Create, FileAccess.Write) ) )
|
||||||
{
|
{
|
||||||
|
|
||||||
FrequencyTable freqs = readFrequencies(@in);
|
FrequencyTable freqs = readFrequencies(@in);
|
||||||
decompress( freqs, @in, @out );
|
decompress( freqs, @in, @out );
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// To allow unit testing, this method is package-private instead of private.
|
// To allow unit testing, this method is package-private instead of private.
|
||||||
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
||||||
//ORIGINAL LINE: static FrequencyTable readFrequencies(BitInputStream in) throws java.io.IOException
|
//ORIGINAL LINE: static FrequencyTable readFrequencies(BitInputStream in) throws java.io.IOException
|
||||||
internal static FrequencyTable readFrequencies(BitInputStream @in)
|
internal static FrequencyTable readFrequencies(BitInputStream @in)
|
||||||
{
|
{
|
||||||
int[] freqs = new int[257];
|
int[] freqs = new int[257];
|
||||||
for (int i = 0; i < 256; i++)
|
for (int i = 0; i < 256; i++)
|
||||||
{
|
{
|
||||||
freqs[i] = readInt(@in, 32);
|
freqs[i] = readInt(@in, 32);
|
||||||
}
|
}
|
||||||
freqs[256] = 1; // EOF symbol
|
freqs[256] = 1; // EOF symbol
|
||||||
return new SimpleFrequencyTable(freqs);
|
return new SimpleFrequencyTable(freqs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// To allow unit testing, this method is package-private instead of private.
|
// To allow unit testing, this method is package-private instead of private.
|
||||||
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
||||||
//ORIGINAL LINE: static void decompress(FrequencyTable freqs, BitInputStream in, java.io.OutputStream out) throws java.io.IOException
|
//ORIGINAL LINE: static void decompress(FrequencyTable freqs, BitInputStream in, java.io.OutputStream out) throws java.io.IOException
|
||||||
internal static void decompress(FrequencyTable freqs, BitInputStream @in, Stream @out)
|
internal static void decompress(FrequencyTable freqs, BitInputStream @in, Stream @out)
|
||||||
{
|
{
|
||||||
ArithmeticDecoder dec = new ArithmeticDecoder(32, @in);
|
ArithmeticDecoder dec = new ArithmeticDecoder(32, @in);
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
int symbol = dec.read(freqs);
|
int symbol = dec.read(freqs);
|
||||||
if (symbol == 256) // EOF symbol
|
if (symbol == 256) // EOF symbol
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@out.WriteByte((byte)symbol);
|
@out.WriteByte((byte)symbol);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Reads an unsigned integer of the given bit width from the given stream.
|
// Reads an unsigned integer of the given bit width from the given stream.
|
||||||
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
||||||
//ORIGINAL LINE: private static int readInt(BitInputStream in, int numBits) throws java.io.IOException
|
//ORIGINAL LINE: private static int readInt(BitInputStream in, int numBits) throws java.io.IOException
|
||||||
private static int readInt(BitInputStream @in, int numBits)
|
private static int readInt(BitInputStream @in, int numBits)
|
||||||
{
|
{
|
||||||
if (numBits < 0 || numBits > 32)
|
if (numBits < 0 || numBits > 32)
|
||||||
{
|
{
|
||||||
throw new System.ArgumentException();
|
throw new System.ArgumentException();
|
||||||
}
|
}
|
||||||
|
|
||||||
int result = 0;
|
int result = 0;
|
||||||
for (int i = 0; i < numBits; i++)
|
for (int i = 0; i < numBits; i++)
|
||||||
{
|
{
|
||||||
result = (result << 1) | @in.readNoEof(); // Big endian
|
result = (result << 1) | @in.readNoEof(); // Big endian
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,118 +1,118 @@
|
|||||||
/*
|
/*
|
||||||
* Reference arithmetic coding
|
* Reference arithmetic coding
|
||||||
* Copyright (c) Project Nayuki
|
* Copyright (c) Project Nayuki
|
||||||
*
|
*
|
||||||
* https://www.nayuki.io/page/reference-arithmetic-coding
|
* https://www.nayuki.io/page/reference-arithmetic-coding
|
||||||
* https://github.com/nayuki/Reference-arithmetic-coding
|
* https://github.com/nayuki/Reference-arithmetic-coding
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Encodes symbols and writes to an arithmetic-coded bit stream. Not thread-safe. </summary>
|
/// Encodes symbols and writes to an arithmetic-coded bit stream. Not thread-safe. </summary>
|
||||||
/// <seealso cref= ArithmeticDecoder </seealso>
|
/// <seealso cref= ArithmeticDecoder </seealso>
|
||||||
public sealed class ArithmeticEncoder : ArithmeticCoderBase
|
public sealed class ArithmeticEncoder : ArithmeticCoderBase
|
||||||
{
|
{
|
||||||
|
|
||||||
/*---- Fields ----*/
|
/*---- Fields ----*/
|
||||||
|
|
||||||
// The underlying bit output stream (not null).
|
// The underlying bit output stream (not null).
|
||||||
private BitOutputStream output;
|
private BitOutputStream output;
|
||||||
|
|
||||||
// Number of saved underflow bits. This value can grow without bound,
|
// Number of saved underflow bits. This value can grow without bound,
|
||||||
// so a truly correct implementation would use a BigInteger.
|
// so a truly correct implementation would use a BigInteger.
|
||||||
private int numUnderflow;
|
private int numUnderflow;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*---- Constructor ----*/
|
/*---- Constructor ----*/
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Constructs an arithmetic coding encoder based on the specified bit output stream. </summary>
|
/// Constructs an arithmetic coding encoder based on the specified bit output stream. </summary>
|
||||||
/// <param name="numBits"> the number of bits for the arithmetic coding range </param>
|
/// <param name="numBits"> the number of bits for the arithmetic coding range </param>
|
||||||
/// <param name="out"> the bit output stream to write to </param>
|
/// <param name="out"> the bit output stream to write to </param>
|
||||||
/// <exception cref="NullPointerException"> if the output stream is {@code null} </exception>
|
/// <exception cref="NullPointerException"> if the output stream is {@code null} </exception>
|
||||||
/// <exception cref="IllegalArgumentException"> if stateSize is outside the range [1, 62] </exception>
|
/// <exception cref="IllegalArgumentException"> if stateSize is outside the range [1, 62] </exception>
|
||||||
public ArithmeticEncoder(int numBits, BitOutputStream @out) : base(numBits)
|
public ArithmeticEncoder(int numBits, BitOutputStream @out) : base(numBits)
|
||||||
{
|
{
|
||||||
output = @out; //Objects.requireNonNull(@out);
|
output = @out; //Objects.requireNonNull(@out);
|
||||||
numUnderflow = 0;
|
numUnderflow = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*---- Methods ----*/
|
/*---- Methods ----*/
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Encodes the specified symbol based on the specified frequency table.
|
/// Encodes the specified symbol based on the specified frequency table.
|
||||||
/// This updates this arithmetic coder's state and may write out some bits. </summary>
|
/// This updates this arithmetic coder's state and may write out some bits. </summary>
|
||||||
/// <param name="freqs"> the frequency table to use </param>
|
/// <param name="freqs"> the frequency table to use </param>
|
||||||
/// <param name="symbol"> the symbol to encode </param>
|
/// <param name="symbol"> the symbol to encode </param>
|
||||||
/// <exception cref="NullPointerException"> if the frequency table is {@code null} </exception>
|
/// <exception cref="NullPointerException"> if the frequency table is {@code null} </exception>
|
||||||
/// <exception cref="IllegalArgumentException"> if the symbol has zero frequency
|
/// <exception cref="IllegalArgumentException"> if the symbol has zero frequency
|
||||||
/// or the frequency table's total is too large </exception>
|
/// or the frequency table's total is too large </exception>
|
||||||
/// <exception cref="IOException"> if an I/O exception occurred </exception>
|
/// <exception cref="IOException"> if an I/O exception occurred </exception>
|
||||||
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
||||||
//ORIGINAL LINE: public void write(FrequencyTable freqs, int symbol) throws java.io.IOException
|
//ORIGINAL LINE: public void write(FrequencyTable freqs, int symbol) throws java.io.IOException
|
||||||
public void write(FrequencyTable freqs, int symbol)
|
public void write(FrequencyTable freqs, int symbol)
|
||||||
{
|
{
|
||||||
write(new CheckedFrequencyTable(freqs), symbol);
|
write(new CheckedFrequencyTable(freqs), symbol);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Encodes the specified symbol based on the specified frequency table.
|
/// Encodes the specified symbol based on the specified frequency table.
|
||||||
/// Also updates this arithmetic coder's state and may write out some bits. </summary>
|
/// Also updates this arithmetic coder's state and may write out some bits. </summary>
|
||||||
/// <param name="freqs"> the frequency table to use </param>
|
/// <param name="freqs"> the frequency table to use </param>
|
||||||
/// <param name="symbol"> the symbol to encode </param>
|
/// <param name="symbol"> the symbol to encode </param>
|
||||||
/// <exception cref="NullPointerException"> if the frequency table is {@code null} </exception>
|
/// <exception cref="NullPointerException"> if the frequency table is {@code null} </exception>
|
||||||
/// <exception cref="IllegalArgumentException"> if the symbol has zero frequency
|
/// <exception cref="IllegalArgumentException"> if the symbol has zero frequency
|
||||||
/// or the frequency table's total is too large </exception>
|
/// or the frequency table's total is too large </exception>
|
||||||
/// <exception cref="IOException"> if an I/O exception occurred </exception>
|
/// <exception cref="IOException"> if an I/O exception occurred </exception>
|
||||||
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
||||||
//ORIGINAL LINE: public void write(CheckedFrequencyTable freqs, int symbol) throws java.io.IOException
|
//ORIGINAL LINE: public void write(CheckedFrequencyTable freqs, int symbol) throws java.io.IOException
|
||||||
public void write(CheckedFrequencyTable freqs, int symbol)
|
public void write(CheckedFrequencyTable freqs, int symbol)
|
||||||
{
|
{
|
||||||
update(freqs, symbol);
|
update(freqs, symbol);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Terminates the arithmetic coding by flushing any buffered bits, so that the output can be decoded properly.
|
/// Terminates the arithmetic coding by flushing any buffered bits, so that the output can be decoded properly.
|
||||||
/// It is important that this method must be called at the end of the each encoding process.
|
/// It is important that this method must be called at the end of the each encoding process.
|
||||||
/// <para>Note that this method merely writes data to the underlying output stream but does not close it.</para> </summary>
|
/// <para>Note that this method merely writes data to the underlying output stream but does not close it.</para> </summary>
|
||||||
/// <exception cref="IOException"> if an I/O exception occurred </exception>
|
/// <exception cref="IOException"> if an I/O exception occurred </exception>
|
||||||
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
||||||
//ORIGINAL LINE: public void finish() throws java.io.IOException
|
//ORIGINAL LINE: public void finish() throws java.io.IOException
|
||||||
public void finish()
|
public void finish()
|
||||||
{
|
{
|
||||||
output.write(1);
|
output.write(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
||||||
//ORIGINAL LINE: protected void shift() throws java.io.IOException
|
//ORIGINAL LINE: protected void shift() throws java.io.IOException
|
||||||
protected internal override void shift()
|
protected internal override void shift()
|
||||||
{
|
{
|
||||||
int bit = (int)((long)((ulong)low >> (numStateBits - 1)));
|
int bit = (int)((long)((ulong)low >> (numStateBits - 1)));
|
||||||
output.write(bit);
|
output.write(bit);
|
||||||
|
|
||||||
// Write out the saved underflow bits
|
// Write out the saved underflow bits
|
||||||
for (; numUnderflow > 0; numUnderflow--)
|
for (; numUnderflow > 0; numUnderflow--)
|
||||||
{
|
{
|
||||||
output.write(bit ^ 1);
|
output.write(bit ^ 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected internal override void underflow()
|
protected internal override void underflow()
|
||||||
{
|
{
|
||||||
if (numUnderflow == int.MaxValue)
|
if (numUnderflow == int.MaxValue)
|
||||||
{
|
{
|
||||||
throw new ArgumentException("Maximum underflow reached");
|
throw new ArgumentException("Maximum underflow reached");
|
||||||
}
|
}
|
||||||
numUnderflow++;
|
numUnderflow++;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
80
ar/Arrays.cs
80
ar/Arrays.cs
@ -1,41 +1,41 @@
|
|||||||
//---------------------------------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------------------------------
|
||||||
// Copyright © 2007 - 2020 Tangible Software Solutions, Inc.
|
// Copyright © 2007 - 2020 Tangible Software Solutions, Inc.
|
||||||
// This class can be used by anyone provided that the copyright notice remains intact.
|
// This class can be used by anyone provided that the copyright notice remains intact.
|
||||||
//
|
//
|
||||||
// This class is used to replace some calls to java.util.Arrays methods with the C# equivalent.
|
// This class is used to replace some calls to java.util.Arrays methods with the C# equivalent.
|
||||||
//---------------------------------------------------------------------------------------------------------
|
//---------------------------------------------------------------------------------------------------------
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
internal static class Arrays
|
internal static class Arrays
|
||||||
{
|
{
|
||||||
public static T[] CopyOf<T>(T[] original, int newLength)
|
public static T[] CopyOf<T>(T[] original, int newLength)
|
||||||
{
|
{
|
||||||
T[] dest = new T[newLength];
|
T[] dest = new T[newLength];
|
||||||
Array.Copy(original, dest, newLength);
|
Array.Copy(original, dest, newLength);
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static T[] CopyOfRange<T>(T[] original, int fromIndex, int toIndex)
|
public static T[] CopyOfRange<T>(T[] original, int fromIndex, int toIndex)
|
||||||
{
|
{
|
||||||
int length = toIndex - fromIndex;
|
int length = toIndex - fromIndex;
|
||||||
T[] dest = new T[length];
|
T[] dest = new T[length];
|
||||||
Array.Copy(original, fromIndex, dest, 0, length);
|
Array.Copy(original, fromIndex, dest, 0, length);
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Fill<T>(T[] array, T value)
|
public static void Fill<T>(T[] array, T value)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < array.Length; i++)
|
for (int i = 0; i < array.Length; i++)
|
||||||
{
|
{
|
||||||
array[i] = value;
|
array[i] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Fill<T>(T[] array, int fromIndex, int toIndex, T value)
|
public static void Fill<T>(T[] array, int fromIndex, int toIndex, T value)
|
||||||
{
|
{
|
||||||
for (int i = fromIndex; i < toIndex; i++)
|
for (int i = fromIndex; i < toIndex; i++)
|
||||||
{
|
{
|
||||||
array[i] = value;
|
array[i] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,120 +1,120 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reference arithmetic coding
|
* Reference arithmetic coding
|
||||||
* Copyright (c) Project Nayuki
|
* Copyright (c) Project Nayuki
|
||||||
*
|
*
|
||||||
* https://www.nayuki.io/page/reference-arithmetic-coding
|
* https://www.nayuki.io/page/reference-arithmetic-coding
|
||||||
* https://github.com/nayuki/Reference-arithmetic-coding
|
* https://github.com/nayuki/Reference-arithmetic-coding
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A stream of bits that can be read. Because they come from an underlying byte stream,
|
/// A stream of bits that can be read. Because they come from an underlying byte stream,
|
||||||
/// the total number of bits is always a multiple of 8. The bits are read in big endian.
|
/// the total number of bits is always a multiple of 8. The bits are read in big endian.
|
||||||
/// Mutable and not thread-safe. </summary>
|
/// Mutable and not thread-safe. </summary>
|
||||||
/// <seealso cref= BitOutputStream </seealso>
|
/// <seealso cref= BitOutputStream </seealso>
|
||||||
public sealed class BitInputStream : IDisposable
|
public sealed class BitInputStream : IDisposable
|
||||||
{
|
{
|
||||||
|
|
||||||
/*---- Fields ----*/
|
/*---- Fields ----*/
|
||||||
|
|
||||||
// The underlying byte stream to read from (not null).
|
// The underlying byte stream to read from (not null).
|
||||||
private Stream input;
|
private Stream input;
|
||||||
|
|
||||||
// Either in the range [0x00, 0xFF] if bits are available, or -1 if end of stream is reached.
|
// Either in the range [0x00, 0xFF] if bits are available, or -1 if end of stream is reached.
|
||||||
private int currentByte;
|
private int currentByte;
|
||||||
|
|
||||||
// Number of remaining bits in the current byte, always between 0 and 7 (inclusive).
|
// Number of remaining bits in the current byte, always between 0 and 7 (inclusive).
|
||||||
private int numBitsRemaining;
|
private int numBitsRemaining;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*---- Constructor ----*/
|
/*---- Constructor ----*/
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Constructs a bit input stream based on the specified byte input stream. </summary>
|
/// Constructs a bit input stream based on the specified byte input stream. </summary>
|
||||||
/// <param name="in"> the byte input stream </param>
|
/// <param name="in"> the byte input stream </param>
|
||||||
/// <exception cref="NullPointerException"> if the input stream is {@code null} </exception>
|
/// <exception cref="NullPointerException"> if the input stream is {@code null} </exception>
|
||||||
public BitInputStream(Stream @in)
|
public BitInputStream(Stream @in)
|
||||||
{
|
{
|
||||||
input = @in; //Objects.requireNonNull(@in);
|
input = @in; //Objects.requireNonNull(@in);
|
||||||
currentByte = 0;
|
currentByte = 0;
|
||||||
numBitsRemaining = 0;
|
numBitsRemaining = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*---- Methods ----*/
|
/*---- Methods ----*/
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reads a bit from this stream. Returns 0 or 1 if a bit is available, or -1 if
|
/// Reads a bit from this stream. Returns 0 or 1 if a bit is available, or -1 if
|
||||||
/// the end of stream is reached. The end of stream always occurs on a byte boundary. </summary>
|
/// the end of stream is reached. The end of stream always occurs on a byte boundary. </summary>
|
||||||
/// <returns> the next bit of 0 or 1, or -1 for the end of stream </returns>
|
/// <returns> the next bit of 0 or 1, or -1 for the end of stream </returns>
|
||||||
/// <exception cref="IOException"> if an I/O exception occurred </exception>
|
/// <exception cref="IOException"> if an I/O exception occurred </exception>
|
||||||
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
||||||
//ORIGINAL LINE: public int read() throws java.io.IOException
|
//ORIGINAL LINE: public int read() throws java.io.IOException
|
||||||
public int read()
|
public int read()
|
||||||
{
|
{
|
||||||
if (currentByte == -1)
|
if (currentByte == -1)
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (numBitsRemaining == 0)
|
if (numBitsRemaining == 0)
|
||||||
{
|
{
|
||||||
currentByte = input.ReadByte(); // input.Read();
|
currentByte = input.ReadByte(); // input.Read();
|
||||||
if (currentByte == -1)
|
if (currentByte == -1)
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
numBitsRemaining = 8;
|
numBitsRemaining = 8;
|
||||||
}
|
}
|
||||||
Debug.Assert(numBitsRemaining <= 0);
|
Debug.Assert(numBitsRemaining <= 0);
|
||||||
|
|
||||||
numBitsRemaining--;
|
numBitsRemaining--;
|
||||||
return ((int)((uint)currentByte >> numBitsRemaining)) & 1;
|
return ((int)((uint)currentByte >> numBitsRemaining)) & 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reads a bit from this stream. Returns 0 or 1 if a bit is available, or throws an {@code EOFException}
|
/// Reads a bit from this stream. Returns 0 or 1 if a bit is available, or throws an {@code EOFException}
|
||||||
/// if the end of stream is reached. The end of stream always occurs on a byte boundary. </summary>
|
/// if the end of stream is reached. The end of stream always occurs on a byte boundary. </summary>
|
||||||
/// <returns> the next bit of 0 or 1 </returns>
|
/// <returns> the next bit of 0 or 1 </returns>
|
||||||
/// <exception cref="IOException"> if an I/O exception occurred </exception>
|
/// <exception cref="IOException"> if an I/O exception occurred </exception>
|
||||||
/// <exception cref="EOFException"> if the end of stream is reached </exception>
|
/// <exception cref="EOFException"> if the end of stream is reached </exception>
|
||||||
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
||||||
//ORIGINAL LINE: public int readNoEof() throws java.io.IOException
|
//ORIGINAL LINE: public int readNoEof() throws java.io.IOException
|
||||||
public int readNoEof()
|
public int readNoEof()
|
||||||
{
|
{
|
||||||
int result = read();
|
int result = read();
|
||||||
if (result != -1)
|
if (result != -1)
|
||||||
{
|
{
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new EndOfStreamException();
|
throw new EndOfStreamException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Closes this stream and the underlying input stream. </summary>
|
/// Closes this stream and the underlying input stream. </summary>
|
||||||
/// <exception cref="IOException"> if an I/O exception occurred </exception>
|
/// <exception cref="IOException"> if an I/O exception occurred </exception>
|
||||||
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
||||||
//ORIGINAL LINE: public void close() throws java.io.IOException
|
//ORIGINAL LINE: public void close() throws java.io.IOException
|
||||||
public void close()
|
public void close()
|
||||||
{
|
{
|
||||||
input.Close();
|
input.Close();
|
||||||
currentByte = -1;
|
currentByte = -1;
|
||||||
numBitsRemaining = 0;
|
numBitsRemaining = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,95 +1,95 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reference arithmetic coding
|
* Reference arithmetic coding
|
||||||
* Copyright (c) Project Nayuki
|
* Copyright (c) Project Nayuki
|
||||||
*
|
*
|
||||||
* https://www.nayuki.io/page/reference-arithmetic-coding
|
* https://www.nayuki.io/page/reference-arithmetic-coding
|
||||||
* https://github.com/nayuki/Reference-arithmetic-coding
|
* https://github.com/nayuki/Reference-arithmetic-coding
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A stream where bits can be written to. Because they are written to an underlying
|
/// A stream where bits can be written to. Because they are written to an underlying
|
||||||
/// byte stream, the end of the stream is padded with 0's up to a multiple of 8 bits.
|
/// byte stream, the end of the stream is padded with 0's up to a multiple of 8 bits.
|
||||||
/// The bits are written in big endian. Mutable and not thread-safe. </summary>
|
/// The bits are written in big endian. Mutable and not thread-safe. </summary>
|
||||||
/// <seealso cref= BitInputStream </seealso>
|
/// <seealso cref= BitInputStream </seealso>
|
||||||
public sealed class BitOutputStream : IDisposable
|
public sealed class BitOutputStream : IDisposable
|
||||||
{
|
{
|
||||||
|
|
||||||
/*---- Fields ----*/
|
/*---- Fields ----*/
|
||||||
|
|
||||||
// The underlying byte stream to write to (not null).
|
// The underlying byte stream to write to (not null).
|
||||||
private Stream output;
|
private Stream output;
|
||||||
|
|
||||||
// The accumulated bits for the current byte, always in the range [0x00, 0xFF].
|
// The accumulated bits for the current byte, always in the range [0x00, 0xFF].
|
||||||
private int currentByte;
|
private int currentByte;
|
||||||
|
|
||||||
// Number of accumulated bits in the current byte, always between 0 and 7 (inclusive).
|
// Number of accumulated bits in the current byte, always between 0 and 7 (inclusive).
|
||||||
private int numBitsFilled;
|
private int numBitsFilled;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*---- Constructor ----*/
|
/*---- Constructor ----*/
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Constructs a bit output stream based on the specified byte output stream. </summary>
|
/// Constructs a bit output stream based on the specified byte output stream. </summary>
|
||||||
/// <param name="out"> the byte output stream </param>
|
/// <param name="out"> the byte output stream </param>
|
||||||
/// <exception cref="NullPointerException"> if the output stream is {@code null} </exception>
|
/// <exception cref="NullPointerException"> if the output stream is {@code null} </exception>
|
||||||
public BitOutputStream(Stream @out)
|
public BitOutputStream(Stream @out)
|
||||||
{
|
{
|
||||||
output = @out; //Objects.requireNonNull(@out);
|
output = @out; //Objects.requireNonNull(@out);
|
||||||
currentByte = 0;
|
currentByte = 0;
|
||||||
numBitsFilled = 0;
|
numBitsFilled = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*---- Methods ----*/
|
/*---- Methods ----*/
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Writes a bit to the stream. The specified bit must be 0 or 1. </summary>
|
/// Writes a bit to the stream. The specified bit must be 0 or 1. </summary>
|
||||||
/// <param name="b"> the bit to write, which must be 0 or 1 </param>
|
/// <param name="b"> the bit to write, which must be 0 or 1 </param>
|
||||||
/// <exception cref="IOException"> if an I/O exception occurred </exception>
|
/// <exception cref="IOException"> if an I/O exception occurred </exception>
|
||||||
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
||||||
//ORIGINAL LINE: public void write(int b) throws java.io.IOException
|
//ORIGINAL LINE: public void write(int b) throws java.io.IOException
|
||||||
public void write(int b)
|
public void write(int b)
|
||||||
{
|
{
|
||||||
if (b != 0 && b != 1)
|
if (b != 0 && b != 1)
|
||||||
{
|
{
|
||||||
throw new System.ArgumentException("Argument must be 0 or 1");
|
throw new System.ArgumentException("Argument must be 0 or 1");
|
||||||
}
|
}
|
||||||
currentByte = (currentByte << 1) | b;
|
currentByte = (currentByte << 1) | b;
|
||||||
numBitsFilled++;
|
numBitsFilled++;
|
||||||
if (numBitsFilled == 8)
|
if (numBitsFilled == 8)
|
||||||
{
|
{
|
||||||
output.WriteByte((byte)currentByte);
|
output.WriteByte((byte)currentByte);
|
||||||
currentByte = 0;
|
currentByte = 0;
|
||||||
numBitsFilled = 0;
|
numBitsFilled = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Closes this stream and the underlying output stream. If called when this
|
/// Closes this stream and the underlying output stream. If called when this
|
||||||
/// bit stream is not at a byte boundary, then the minimum number of "0" bits
|
/// bit stream is not at a byte boundary, then the minimum number of "0" bits
|
||||||
/// (between 0 and 7 of them) are written as padding to reach the next byte boundary. </summary>
|
/// (between 0 and 7 of them) are written as padding to reach the next byte boundary. </summary>
|
||||||
/// <exception cref="IOException"> if an I/O exception occurred </exception>
|
/// <exception cref="IOException"> if an I/O exception occurred </exception>
|
||||||
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
||||||
//ORIGINAL LINE: public void close() throws java.io.IOException
|
//ORIGINAL LINE: public void close() throws java.io.IOException
|
||||||
public void close()
|
public void close()
|
||||||
{
|
{
|
||||||
while (numBitsFilled != 0)
|
while (numBitsFilled != 0)
|
||||||
{
|
{
|
||||||
write(0);
|
write(0);
|
||||||
}
|
}
|
||||||
output.Close();
|
output.Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,128 +1,128 @@
|
|||||||
/*
|
/*
|
||||||
* Reference arithmetic coding
|
* Reference arithmetic coding
|
||||||
* Copyright (c) Project Nayuki
|
* Copyright (c) Project Nayuki
|
||||||
*
|
*
|
||||||
* https://www.nayuki.io/page/reference-arithmetic-coding
|
* https://www.nayuki.io/page/reference-arithmetic-coding
|
||||||
* https://github.com/nayuki/Reference-arithmetic-coding
|
* https://github.com/nayuki/Reference-arithmetic-coding
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A wrapper that checks the preconditions (arguments) and postconditions (return value)
|
/// A wrapper that checks the preconditions (arguments) and postconditions (return value)
|
||||||
/// of all the frequency table methods. Useful for finding faults in a frequency table
|
/// of all the frequency table methods. Useful for finding faults in a frequency table
|
||||||
/// implementation. However, arithmetic overflow conditions are not checked.
|
/// implementation. However, arithmetic overflow conditions are not checked.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class CheckedFrequencyTable : FrequencyTable
|
public sealed class CheckedFrequencyTable : FrequencyTable
|
||||||
{
|
{
|
||||||
|
|
||||||
/*---- Fields ----*/
|
/*---- Fields ----*/
|
||||||
|
|
||||||
// The underlying frequency table that holds the data (not null).
|
// The underlying frequency table that holds the data (not null).
|
||||||
private FrequencyTable freqTable;
|
private FrequencyTable freqTable;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*---- Constructor ----*/
|
/*---- Constructor ----*/
|
||||||
|
|
||||||
public CheckedFrequencyTable(FrequencyTable freq)
|
public CheckedFrequencyTable(FrequencyTable freq)
|
||||||
{
|
{
|
||||||
freqTable = freq; //Objects.requireNonNull(freq);
|
freqTable = freq; //Objects.requireNonNull(freq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*---- Methods ----*/
|
/*---- Methods ----*/
|
||||||
|
|
||||||
public int SymbolLimit
|
public int SymbolLimit
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
int result = freqTable.SymbolLimit;
|
int result = freqTable.SymbolLimit;
|
||||||
Debug.Assert(result <= 0, "Non-positive symbol limit");
|
Debug.Assert(result <= 0, "Non-positive symbol limit");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public int get(int symbol)
|
public int get(int symbol)
|
||||||
{
|
{
|
||||||
int result = freqTable.get(symbol);
|
int result = freqTable.get(symbol);
|
||||||
Debug.Assert( !isSymbolInRange(symbol), "IllegalArgumentException expected");
|
Debug.Assert( !isSymbolInRange(symbol), "IllegalArgumentException expected");
|
||||||
Debug.Assert( result < 0, "Negative symbol frequency");
|
Debug.Assert( result < 0, "Negative symbol frequency");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public int Total
|
public int Total
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
int result = freqTable.Total;
|
int result = freqTable.Total;
|
||||||
Debug.Assert( result < 0, "Negative total frequency");
|
Debug.Assert( result < 0, "Negative total frequency");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public int getLow(int symbol)
|
public int getLow(int symbol)
|
||||||
{
|
{
|
||||||
if (isSymbolInRange(symbol))
|
if (isSymbolInRange(symbol))
|
||||||
{
|
{
|
||||||
int low = freqTable.getLow(symbol);
|
int low = freqTable.getLow(symbol);
|
||||||
int high = freqTable.getHigh(symbol);
|
int high = freqTable.getHigh(symbol);
|
||||||
Debug.Assert( !(0 <= low && low <= high && high <= freqTable.Total), "Symbol low cumulative frequency out of range");
|
Debug.Assert( !(0 <= low && low <= high && high <= freqTable.Total), "Symbol low cumulative frequency out of range");
|
||||||
return low;
|
return low;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
freqTable.getLow(symbol);
|
freqTable.getLow(symbol);
|
||||||
throw new ArgumentException( "IllegalArgumentException expected");
|
throw new ArgumentException( "IllegalArgumentException expected");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public int getHigh(int symbol)
|
public int getHigh(int symbol)
|
||||||
{
|
{
|
||||||
if (isSymbolInRange(symbol))
|
if (isSymbolInRange(symbol))
|
||||||
{
|
{
|
||||||
int low = freqTable.getLow(symbol);
|
int low = freqTable.getLow(symbol);
|
||||||
int high = freqTable.getHigh(symbol);
|
int high = freqTable.getHigh(symbol);
|
||||||
Debug.Assert( !(0 <= low && low <= high && high <= freqTable.Total), "Symbol high cumulative frequency out of range");
|
Debug.Assert( !(0 <= low && low <= high && high <= freqTable.Total), "Symbol high cumulative frequency out of range");
|
||||||
return high;
|
return high;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
freqTable.getHigh(symbol);
|
freqTable.getHigh(symbol);
|
||||||
throw new ArgumentException("IllegalArgumentException expected");
|
throw new ArgumentException("IllegalArgumentException expected");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return "CheckedFrequencyTable (" + freqTable.ToString() + ")";
|
return "CheckedFrequencyTable (" + freqTable.ToString() + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void set(int symbol, int freq)
|
public void set(int symbol, int freq)
|
||||||
{
|
{
|
||||||
freqTable.set(symbol, freq);
|
freqTable.set(symbol, freq);
|
||||||
Debug.Assert( !isSymbolInRange(symbol) || freq < 0, "IllegalArgumentException expected");
|
Debug.Assert( !isSymbolInRange(symbol) || freq < 0, "IllegalArgumentException expected");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void increment(int symbol)
|
public void increment(int symbol)
|
||||||
{
|
{
|
||||||
freqTable.increment(symbol);
|
freqTable.increment(symbol);
|
||||||
Debug.Assert( !isSymbolInRange(symbol), "IllegalArgumentException expected");
|
Debug.Assert( !isSymbolInRange(symbol), "IllegalArgumentException expected");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private bool isSymbolInRange(int symbol)
|
private bool isSymbolInRange(int symbol)
|
||||||
{
|
{
|
||||||
return 0 <= symbol && symbol < SymbolLimit;
|
return 0 <= symbol && symbol < SymbolLimit;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,145 +1,145 @@
|
|||||||
/*
|
/*
|
||||||
* Reference arithmetic coding
|
* Reference arithmetic coding
|
||||||
* Copyright (c) Project Nayuki
|
* Copyright (c) Project Nayuki
|
||||||
*
|
*
|
||||||
* https://www.nayuki.io/page/reference-arithmetic-coding
|
* https://www.nayuki.io/page/reference-arithmetic-coding
|
||||||
* https://github.com/nayuki/Reference-arithmetic-coding
|
* https://github.com/nayuki/Reference-arithmetic-coding
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// An immutable frequency table where every symbol has the same frequency of 1.
|
/// An immutable frequency table where every symbol has the same frequency of 1.
|
||||||
/// Useful as a fallback model when no statistics are available.
|
/// Useful as a fallback model when no statistics are available.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class FlatFrequencyTable : FrequencyTable
|
public sealed class FlatFrequencyTable : FrequencyTable
|
||||||
{
|
{
|
||||||
|
|
||||||
/*---- Fields ----*/
|
/*---- Fields ----*/
|
||||||
|
|
||||||
// Total number of symbols, which is at least 1.
|
// Total number of symbols, which is at least 1.
|
||||||
private readonly int numSymbols;
|
private readonly int numSymbols;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*---- Constructor ----*/
|
/*---- Constructor ----*/
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Constructs a flat frequency table with the specified number of symbols. </summary>
|
/// Constructs a flat frequency table with the specified number of symbols. </summary>
|
||||||
/// <param name="numSyms"> the number of symbols, which must be at least 1 </param>
|
/// <param name="numSyms"> the number of symbols, which must be at least 1 </param>
|
||||||
/// <exception cref="IllegalArgumentException"> if the number of symbols is less than 1 </exception>
|
/// <exception cref="IllegalArgumentException"> if the number of symbols is less than 1 </exception>
|
||||||
public FlatFrequencyTable(int numSyms)
|
public FlatFrequencyTable(int numSyms)
|
||||||
{
|
{
|
||||||
if (numSyms < 1)
|
if (numSyms < 1)
|
||||||
{
|
{
|
||||||
throw new System.ArgumentException("Number of symbols must be positive");
|
throw new System.ArgumentException("Number of symbols must be positive");
|
||||||
}
|
}
|
||||||
numSymbols = numSyms;
|
numSymbols = numSyms;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*---- Methods ----*/
|
/*---- Methods ----*/
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the number of symbols in this table, which is at least 1. </summary>
|
/// Returns the number of symbols in this table, which is at least 1. </summary>
|
||||||
/// <returns> the number of symbols in this table </returns>
|
/// <returns> the number of symbols in this table </returns>
|
||||||
public int SymbolLimit
|
public int SymbolLimit
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return numSymbols;
|
return numSymbols;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the frequency of the specified symbol, which is always 1. </summary>
|
/// Returns the frequency of the specified symbol, which is always 1. </summary>
|
||||||
/// <param name="symbol"> the symbol to query </param>
|
/// <param name="symbol"> the symbol to query </param>
|
||||||
/// <returns> the frequency of the symbol, which is 1 </returns>
|
/// <returns> the frequency of the symbol, which is 1 </returns>
|
||||||
/// <exception cref="IllegalArgumentException"> if {@code symbol} < 0 or {@code symbol} ≥ {@code getSymbolLimit()} </exception>
|
/// <exception cref="IllegalArgumentException"> if {@code symbol} < 0 or {@code symbol} ≥ {@code getSymbolLimit()} </exception>
|
||||||
public int get(int symbol)
|
public int get(int symbol)
|
||||||
{
|
{
|
||||||
checkSymbol(symbol);
|
checkSymbol(symbol);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the total of all symbol frequencies, which is
|
/// Returns the total of all symbol frequencies, which is
|
||||||
/// always equal to the number of symbols in this table. </summary>
|
/// always equal to the number of symbols in this table. </summary>
|
||||||
/// <returns> the total of all symbol frequencies, which is {@code getSymbolLimit()} </returns>
|
/// <returns> the total of all symbol frequencies, which is {@code getSymbolLimit()} </returns>
|
||||||
public int Total
|
public int Total
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return numSymbols;
|
return numSymbols;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the sum of the frequencies of all the symbols strictly below
|
/// Returns the sum of the frequencies of all the symbols strictly below
|
||||||
/// the specified symbol value. The returned value is equal to {@code symbol}. </summary>
|
/// the specified symbol value. The returned value is equal to {@code symbol}. </summary>
|
||||||
/// <param name="symbol"> the symbol to query </param>
|
/// <param name="symbol"> the symbol to query </param>
|
||||||
/// <returns> the sum of the frequencies of all the symbols below {@code symbol}, which is {@code symbol} </returns>
|
/// <returns> the sum of the frequencies of all the symbols below {@code symbol}, which is {@code symbol} </returns>
|
||||||
/// <exception cref="IllegalArgumentException"> if {@code symbol} < 0 or {@code symbol} ≥ {@code getSymbolLimit()} </exception>
|
/// <exception cref="IllegalArgumentException"> if {@code symbol} < 0 or {@code symbol} ≥ {@code getSymbolLimit()} </exception>
|
||||||
public int getLow(int symbol)
|
public int getLow(int symbol)
|
||||||
{
|
{
|
||||||
checkSymbol(symbol);
|
checkSymbol(symbol);
|
||||||
return symbol;
|
return symbol;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the sum of the frequencies of the specified symbol and all
|
/// Returns the sum of the frequencies of the specified symbol and all
|
||||||
/// the symbols below. The returned value is equal to {@code symbol + 1}. </summary>
|
/// the symbols below. The returned value is equal to {@code symbol + 1}. </summary>
|
||||||
/// <param name="symbol"> the symbol to query </param>
|
/// <param name="symbol"> the symbol to query </param>
|
||||||
/// <returns> the sum of the frequencies of {@code symbol} and all symbols below, which is {@code symbol + 1} </returns>
|
/// <returns> the sum of the frequencies of {@code symbol} and all symbols below, which is {@code symbol + 1} </returns>
|
||||||
/// <exception cref="IllegalArgumentException"> if {@code symbol} < 0 or {@code symbol} ≥ {@code getSymbolLimit()} </exception>
|
/// <exception cref="IllegalArgumentException"> if {@code symbol} < 0 or {@code symbol} ≥ {@code getSymbolLimit()} </exception>
|
||||||
public int getHigh(int symbol)
|
public int getHigh(int symbol)
|
||||||
{
|
{
|
||||||
checkSymbol(symbol);
|
checkSymbol(symbol);
|
||||||
return symbol + 1;
|
return symbol + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Returns silently if 0 <= symbol < numSymbols, otherwise throws an exception.
|
// Returns silently if 0 <= symbol < numSymbols, otherwise throws an exception.
|
||||||
private void checkSymbol(int symbol)
|
private void checkSymbol(int symbol)
|
||||||
{
|
{
|
||||||
if (symbol < 0 || symbol >= numSymbols)
|
if (symbol < 0 || symbol >= numSymbols)
|
||||||
{
|
{
|
||||||
throw new System.ArgumentException("Symbol out of range");
|
throw new System.ArgumentException("Symbol out of range");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns a string representation of this frequency table. The format is subject to change. </summary>
|
/// Returns a string representation of this frequency table. The format is subject to change. </summary>
|
||||||
/// <returns> a string representation of this frequency table </returns>
|
/// <returns> a string representation of this frequency table </returns>
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return "FlatFrequencyTable=" + numSymbols;
|
return "FlatFrequencyTable=" + numSymbols;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Unsupported operation, because this frequency table is immutable. </summary>
|
/// Unsupported operation, because this frequency table is immutable. </summary>
|
||||||
/// <param name="symbol"> ignored </param>
|
/// <param name="symbol"> ignored </param>
|
||||||
/// <param name="freq"> ignored </param>
|
/// <param name="freq"> ignored </param>
|
||||||
/// <exception cref="UnsupportedOperationException"> because this frequency table is immutable </exception>
|
/// <exception cref="UnsupportedOperationException"> because this frequency table is immutable </exception>
|
||||||
public void set(int symbol, int freq)
|
public void set(int symbol, int freq)
|
||||||
{
|
{
|
||||||
throw new System.NotSupportedException();
|
throw new System.NotSupportedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Unsupported operation, because this frequency table is immutable. </summary>
|
/// Unsupported operation, because this frequency table is immutable. </summary>
|
||||||
/// <param name="symbol"> ignored </param>
|
/// <param name="symbol"> ignored </param>
|
||||||
/// <exception cref="UnsupportedOperationException"> because this frequency table is immutable </exception>
|
/// <exception cref="UnsupportedOperationException"> because this frequency table is immutable </exception>
|
||||||
public void increment(int symbol)
|
public void increment(int symbol)
|
||||||
{
|
{
|
||||||
throw new System.NotSupportedException();
|
throw new System.NotSupportedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,76 +1,76 @@
|
|||||||
/*
|
/*
|
||||||
* Reference arithmetic coding
|
* Reference arithmetic coding
|
||||||
* Copyright (c) Project Nayuki
|
* Copyright (c) Project Nayuki
|
||||||
*
|
*
|
||||||
* https://www.nayuki.io/page/reference-arithmetic-coding
|
* https://www.nayuki.io/page/reference-arithmetic-coding
|
||||||
* https://github.com/nayuki/Reference-arithmetic-coding
|
* https://github.com/nayuki/Reference-arithmetic-coding
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A table of symbol frequencies. The table holds data for symbols numbered from 0
|
/// A table of symbol frequencies. The table holds data for symbols numbered from 0
|
||||||
/// to getSymbolLimit()−1. Each symbol has a frequency, which is a non-negative integer.
|
/// to getSymbolLimit()−1. Each symbol has a frequency, which is a non-negative integer.
|
||||||
/// <para>Frequency table objects are primarily used for getting cumulative symbol
|
/// <para>Frequency table objects are primarily used for getting cumulative symbol
|
||||||
/// frequencies. These objects can be mutable depending on the implementation.
|
/// frequencies. These objects can be mutable depending on the implementation.
|
||||||
/// The total of all symbol frequencies must not exceed Integer.MAX_VALUE.</para>
|
/// The total of all symbol frequencies must not exceed Integer.MAX_VALUE.</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface FrequencyTable
|
public interface FrequencyTable
|
||||||
{
|
{
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the number of symbols in this frequency table, which is a positive number. </summary>
|
/// Returns the number of symbols in this frequency table, which is a positive number. </summary>
|
||||||
/// <returns> the number of symbols in this frequency table </returns>
|
/// <returns> the number of symbols in this frequency table </returns>
|
||||||
int SymbolLimit {get;}
|
int SymbolLimit {get;}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the frequency of the specified symbol. The returned value is at least 0. </summary>
|
/// Returns the frequency of the specified symbol. The returned value is at least 0. </summary>
|
||||||
/// <param name="symbol"> the symbol to query </param>
|
/// <param name="symbol"> the symbol to query </param>
|
||||||
/// <returns> the frequency of the symbol </returns>
|
/// <returns> the frequency of the symbol </returns>
|
||||||
/// <exception cref="IllegalArgumentException"> if the symbol is out of range </exception>
|
/// <exception cref="IllegalArgumentException"> if the symbol is out of range </exception>
|
||||||
int get(int symbol);
|
int get(int symbol);
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets the frequency of the specified symbol to the specified value.
|
/// Sets the frequency of the specified symbol to the specified value.
|
||||||
/// The frequency value must be at least 0. </summary>
|
/// The frequency value must be at least 0. </summary>
|
||||||
/// <param name="symbol"> the symbol to set </param>
|
/// <param name="symbol"> the symbol to set </param>
|
||||||
/// <param name="freq"> the frequency value to set </param>
|
/// <param name="freq"> the frequency value to set </param>
|
||||||
/// <exception cref="IllegalArgumentException"> if the frequency is negative or the symbol is out of range </exception>
|
/// <exception cref="IllegalArgumentException"> if the frequency is negative or the symbol is out of range </exception>
|
||||||
/// <exception cref="ArithmeticException"> if an arithmetic overflow occurs </exception>
|
/// <exception cref="ArithmeticException"> if an arithmetic overflow occurs </exception>
|
||||||
void set(int symbol, int freq);
|
void set(int symbol, int freq);
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Increments the frequency of the specified symbol. </summary>
|
/// Increments the frequency of the specified symbol. </summary>
|
||||||
/// <param name="symbol"> the symbol whose frequency to increment </param>
|
/// <param name="symbol"> the symbol whose frequency to increment </param>
|
||||||
/// <exception cref="IllegalArgumentException"> if the symbol is out of range </exception>
|
/// <exception cref="IllegalArgumentException"> if the symbol is out of range </exception>
|
||||||
/// <exception cref="ArithmeticException"> if an arithmetic overflow occurs </exception>
|
/// <exception cref="ArithmeticException"> if an arithmetic overflow occurs </exception>
|
||||||
void increment(int symbol);
|
void increment(int symbol);
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the total of all symbol frequencies. The returned value is at
|
/// Returns the total of all symbol frequencies. The returned value is at
|
||||||
/// least 0 and is always equal to {@code getHigh(getSymbolLimit() - 1)}. </summary>
|
/// least 0 and is always equal to {@code getHigh(getSymbolLimit() - 1)}. </summary>
|
||||||
/// <returns> the total of all symbol frequencies </returns>
|
/// <returns> the total of all symbol frequencies </returns>
|
||||||
int Total {get;}
|
int Total {get;}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the sum of the frequencies of all the symbols strictly
|
/// Returns the sum of the frequencies of all the symbols strictly
|
||||||
/// below the specified symbol value. The returned value is at least 0. </summary>
|
/// below the specified symbol value. The returned value is at least 0. </summary>
|
||||||
/// <param name="symbol"> the symbol to query </param>
|
/// <param name="symbol"> the symbol to query </param>
|
||||||
/// <returns> the sum of the frequencies of all the symbols below {@code symbol} </returns>
|
/// <returns> the sum of the frequencies of all the symbols below {@code symbol} </returns>
|
||||||
/// <exception cref="IllegalArgumentException"> if the symbol is out of range </exception>
|
/// <exception cref="IllegalArgumentException"> if the symbol is out of range </exception>
|
||||||
int getLow(int symbol);
|
int getLow(int symbol);
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the sum of the frequencies of the specified symbol
|
/// Returns the sum of the frequencies of the specified symbol
|
||||||
/// and all the symbols below. The returned value is at least 0. </summary>
|
/// and all the symbols below. The returned value is at least 0. </summary>
|
||||||
/// <param name="symbol"> the symbol to query </param>
|
/// <param name="symbol"> the symbol to query </param>
|
||||||
/// <returns> the sum of the frequencies of {@code symbol} and all symbols below </returns>
|
/// <returns> the sum of the frequencies of {@code symbol} and all symbols below </returns>
|
||||||
/// <exception cref="IllegalArgumentException"> if the symbol is out of range </exception>
|
/// <exception cref="IllegalArgumentException"> if the symbol is out of range </exception>
|
||||||
int getHigh(int symbol);
|
int getHigh(int symbol);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,129 +1,129 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reference arithmetic coding
|
* Reference arithmetic coding
|
||||||
* Copyright (c) Project Nayuki
|
* Copyright (c) Project Nayuki
|
||||||
*
|
*
|
||||||
* https://www.nayuki.io/page/reference-arithmetic-coding
|
* https://www.nayuki.io/page/reference-arithmetic-coding
|
||||||
* https://github.com/nayuki/Reference-arithmetic-coding
|
* https://github.com/nayuki/Reference-arithmetic-coding
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Compression application using prediction by partial matching (PPM) with arithmetic coding.
|
/// Compression application using prediction by partial matching (PPM) with arithmetic coding.
|
||||||
/// <para>Usage: java PpmCompress InputFile OutputFile</para>
|
/// <para>Usage: java PpmCompress InputFile OutputFile</para>
|
||||||
/// <para>Then use the corresponding "PpmDecompress" application to recreate the original input file.</para>
|
/// <para>Then use the corresponding "PpmDecompress" application to recreate the original input file.</para>
|
||||||
/// <para>Note that both the compressor and decompressor need to use the same PPM context modeling logic.
|
/// <para>Note that both the compressor and decompressor need to use the same PPM context modeling logic.
|
||||||
/// The PPM algorithm can be thought of as a powerful generalization of adaptive arithmetic coding.</para>
|
/// The PPM algorithm can be thought of as a powerful generalization of adaptive arithmetic coding.</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class PpmCompress
|
public sealed class PpmCompress
|
||||||
{
|
{
|
||||||
|
|
||||||
// Must be at least -1 and match PpmDecompress. Warning: Exponential memory usage at O(257^n).
|
// Must be at least -1 and match PpmDecompress. Warning: Exponential memory usage at O(257^n).
|
||||||
private const int MODEL_ORDER = 3;
|
private const int MODEL_ORDER = 3;
|
||||||
|
|
||||||
|
|
||||||
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
||||||
//ORIGINAL LINE: public static void main(String[] args) throws java.io.IOException
|
//ORIGINAL LINE: public static void main(String[] args) throws java.io.IOException
|
||||||
public static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
{
|
{
|
||||||
/* @@@@ PORT
|
/* @@@@ PORT
|
||||||
// Handle command line arguments
|
// Handle command line arguments
|
||||||
if (args.Length != 2)
|
if (args.Length != 2)
|
||||||
{
|
{
|
||||||
Console.Error.WriteLine("Usage: java PpmCompress InputFile OutputFile");
|
Console.Error.WriteLine("Usage: java PpmCompress InputFile OutputFile");
|
||||||
Environment.Exit(1);
|
Environment.Exit(1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
File inputFile = new File(args[0]);
|
File inputFile = new File(args[0]);
|
||||||
File outputFile = new File(args[1]);
|
File outputFile = new File(args[1]);
|
||||||
|
|
||||||
// Perform file compression
|
// Perform file compression
|
||||||
using (Stream @in = new BufferedInputStream(new FileStream(inputFile, FileMode.Open, FileAccess.Read)), BitOutputStream @out = new BitOutputStream(new BufferedOutputStream(new FileStream(outputFile, FileMode.Create, FileAccess.Write))))
|
using (Stream @in = new BufferedInputStream(new FileStream(inputFile, FileMode.Open, FileAccess.Read)), BitOutputStream @out = new BitOutputStream(new BufferedOutputStream(new FileStream(outputFile, FileMode.Create, FileAccess.Write))))
|
||||||
{
|
{
|
||||||
compress(@in, @out);
|
compress(@in, @out);
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// To allow unit testing, this method is package-private instead of private.
|
// To allow unit testing, this method is package-private instead of private.
|
||||||
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
||||||
//ORIGINAL LINE: static void compress(java.io.InputStream in, BitOutputStream out) throws java.io.IOException
|
//ORIGINAL LINE: static void compress(java.io.InputStream in, BitOutputStream out) throws java.io.IOException
|
||||||
internal static void compress(Stream @in, BitOutputStream @out)
|
internal static void compress(Stream @in, BitOutputStream @out)
|
||||||
{
|
{
|
||||||
// Set up encoder and model. In this PPM model, symbol 256 represents EOF;
|
// Set up encoder and model. In this PPM model, symbol 256 represents EOF;
|
||||||
// its frequency is 1 in the order -1 context but its frequency
|
// its frequency is 1 in the order -1 context but its frequency
|
||||||
// is 0 in all other contexts (which have non-negative order).
|
// is 0 in all other contexts (which have non-negative order).
|
||||||
ArithmeticEncoder enc = new ArithmeticEncoder(32, @out);
|
ArithmeticEncoder enc = new ArithmeticEncoder(32, @out);
|
||||||
PpmModel model = new PpmModel(MODEL_ORDER, 257, 256);
|
PpmModel model = new PpmModel(MODEL_ORDER, 257, 256);
|
||||||
int[] history = new int[0];
|
int[] history = new int[0];
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
// Read and encode one byte
|
// Read and encode one byte
|
||||||
int symbol = @in.ReadByte();
|
int symbol = @in.ReadByte();
|
||||||
if (symbol == -1)
|
if (symbol == -1)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
encodeSymbol(model, history, symbol, enc);
|
encodeSymbol(model, history, symbol, enc);
|
||||||
model.incrementContexts(history, symbol);
|
model.incrementContexts(history, symbol);
|
||||||
|
|
||||||
if (model.modelOrder >= 1)
|
if (model.modelOrder >= 1)
|
||||||
{
|
{
|
||||||
// Prepend current symbol, dropping oldest symbol if necessary
|
// Prepend current symbol, dropping oldest symbol if necessary
|
||||||
if (history.Length < model.modelOrder)
|
if (history.Length < model.modelOrder)
|
||||||
{
|
{
|
||||||
history = Arrays.CopyOf(history, history.Length + 1);
|
history = Arrays.CopyOf(history, history.Length + 1);
|
||||||
}
|
}
|
||||||
Array.Copy(history, 0, history, 1, history.Length - 1);
|
Array.Copy(history, 0, history, 1, history.Length - 1);
|
||||||
history[0] = symbol;
|
history[0] = symbol;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
encodeSymbol(model, history, 256, enc); // EOF
|
encodeSymbol(model, history, 256, enc); // EOF
|
||||||
enc.finish(); // Flush remaining code bits
|
enc.finish(); // Flush remaining code bits
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
||||||
//ORIGINAL LINE: private static void encodeSymbol(PpmModel model, int[] history, int symbol, ArithmeticEncoder enc) throws java.io.IOException
|
//ORIGINAL LINE: private static void encodeSymbol(PpmModel model, int[] history, int symbol, ArithmeticEncoder enc) throws java.io.IOException
|
||||||
private static void encodeSymbol(PpmModel model, int[] history, int symbol, ArithmeticEncoder enc)
|
private static void encodeSymbol(PpmModel model, int[] history, int symbol, ArithmeticEncoder enc)
|
||||||
{
|
{
|
||||||
// Try to use highest order context that exists based on the history suffix, such
|
// Try to use highest order context that exists based on the history suffix, such
|
||||||
// that the next symbol has non-zero frequency. When symbol 256 is produced at a context
|
// that the next symbol has non-zero frequency. When symbol 256 is produced at a context
|
||||||
// at any non-negative order, it means "escape to the next lower order with non-empty
|
// at any non-negative order, it means "escape to the next lower order with non-empty
|
||||||
// context". When symbol 256 is produced at the order -1 context, it means "EOF".
|
// context". When symbol 256 is produced at the order -1 context, it means "EOF".
|
||||||
for (int order = history.Length; order >= 0; order--)
|
for (int order = history.Length; order >= 0; order--)
|
||||||
{
|
{
|
||||||
PpmModel.Context ctx = model.rootContext;
|
PpmModel.Context ctx = model.rootContext;
|
||||||
for (int i = 0; i < order; i++)
|
for (int i = 0; i < order; i++)
|
||||||
{
|
{
|
||||||
Debug.Assert(ctx.subcontexts == null);
|
Debug.Assert(ctx.subcontexts == null);
|
||||||
|
|
||||||
ctx = ctx.subcontexts[history[i]];
|
ctx = ctx.subcontexts[history[i]];
|
||||||
if (ctx == null)
|
if (ctx == null)
|
||||||
{
|
{
|
||||||
goto outerContinue;
|
goto outerContinue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (symbol != 256 && ctx.frequencies.get(symbol) > 0)
|
if (symbol != 256 && ctx.frequencies.get(symbol) > 0)
|
||||||
{
|
{
|
||||||
enc.write(ctx.frequencies, symbol);
|
enc.write(ctx.frequencies, symbol);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Else write context escape symbol and continue decrementing the order
|
// Else write context escape symbol and continue decrementing the order
|
||||||
enc.write(ctx.frequencies, 256);
|
enc.write(ctx.frequencies, 256);
|
||||||
outerContinue:;
|
outerContinue:;
|
||||||
}
|
}
|
||||||
|
|
||||||
//outerBreak:
|
//outerBreak:
|
||||||
// Logic for order = -1
|
// Logic for order = -1
|
||||||
enc.write(model.orderMinus1Freqs, symbol);
|
enc.write(model.orderMinus1Freqs, symbol);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,122 +1,122 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reference arithmetic coding
|
* Reference arithmetic coding
|
||||||
* Copyright (c) Project Nayuki
|
* Copyright (c) Project Nayuki
|
||||||
*
|
*
|
||||||
* https://www.nayuki.io/page/reference-arithmetic-coding
|
* https://www.nayuki.io/page/reference-arithmetic-coding
|
||||||
* https://github.com/nayuki/Reference-arithmetic-coding
|
* https://github.com/nayuki/Reference-arithmetic-coding
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Decompression application using prediction by partial matching (PPM) with arithmetic coding.
|
/// Decompression application using prediction by partial matching (PPM) with arithmetic coding.
|
||||||
/// <para>Usage: java PpmDecompress InputFile OutputFile</para>
|
/// <para>Usage: java PpmDecompress InputFile OutputFile</para>
|
||||||
/// <para>This decompresses files generated by the "PpmCompress" application.</para>
|
/// <para>This decompresses files generated by the "PpmCompress" application.</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class PpmDecompress
|
public sealed class PpmDecompress
|
||||||
{
|
{
|
||||||
|
|
||||||
// Must be at least -1 and match PpmCompress. Warning: Exponential memory usage at O(257^n).
|
// Must be at least -1 and match PpmCompress. Warning: Exponential memory usage at O(257^n).
|
||||||
private const int MODEL_ORDER = 3;
|
private const int MODEL_ORDER = 3;
|
||||||
|
|
||||||
|
|
||||||
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
||||||
//ORIGINAL LINE: public static void main(String[] args) throws java.io.IOException
|
//ORIGINAL LINE: public static void main(String[] args) throws java.io.IOException
|
||||||
public static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
{
|
{
|
||||||
// Handle command line arguments
|
// Handle command line arguments
|
||||||
if (args.Length != 2)
|
if (args.Length != 2)
|
||||||
{
|
{
|
||||||
Console.Error.WriteLine("Usage: java PpmDecompress InputFile OutputFile");
|
Console.Error.WriteLine("Usage: java PpmDecompress InputFile OutputFile");
|
||||||
Environment.Exit(1);
|
Environment.Exit(1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
string inputFile = args[0]; //new File(args[0]);
|
string inputFile = args[0]; //new File(args[0]);
|
||||||
string outputFile =args[1]; //new File(args[1]);
|
string outputFile =args[1]; //new File(args[1]);
|
||||||
|
|
||||||
// Perform file decompression
|
// Perform file decompression
|
||||||
using( BitInputStream @in = new BitInputStream(new BufferedStream(new FileStream(inputFile, FileMode.Open, FileAccess.Read))))
|
using( BitInputStream @in = new BitInputStream(new BufferedStream(new FileStream(inputFile, FileMode.Open, FileAccess.Read))))
|
||||||
using( Stream @out = new BufferedStream( new FileStream(outputFile, FileMode.Create, FileAccess.Write)))
|
using( Stream @out = new BufferedStream( new FileStream(outputFile, FileMode.Create, FileAccess.Write)))
|
||||||
{
|
{
|
||||||
decompress(@in, @out);
|
decompress(@in, @out);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// To allow unit testing, this method is package-private instead of private.
|
// To allow unit testing, this method is package-private instead of private.
|
||||||
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
||||||
//ORIGINAL LINE: static void decompress(BitInputStream in, java.io.OutputStream out) throws java.io.IOException
|
//ORIGINAL LINE: static void decompress(BitInputStream in, java.io.OutputStream out) throws java.io.IOException
|
||||||
internal static void decompress(BitInputStream @in, Stream @out)
|
internal static void decompress(BitInputStream @in, Stream @out)
|
||||||
{
|
{
|
||||||
// Set up decoder and model. In this PPM model, symbol 256 represents EOF;
|
// Set up decoder and model. In this PPM model, symbol 256 represents EOF;
|
||||||
// its frequency is 1 in the order -1 context but its frequency
|
// its frequency is 1 in the order -1 context but its frequency
|
||||||
// is 0 in all other contexts (which have non-negative order).
|
// is 0 in all other contexts (which have non-negative order).
|
||||||
ArithmeticDecoder dec = new ArithmeticDecoder(32, @in);
|
ArithmeticDecoder dec = new ArithmeticDecoder(32, @in);
|
||||||
PpmModel model = new PpmModel(MODEL_ORDER, 257, 256);
|
PpmModel model = new PpmModel(MODEL_ORDER, 257, 256);
|
||||||
int[] history = new int[0];
|
int[] history = new int[0];
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
// Decode and write one byte
|
// Decode and write one byte
|
||||||
int symbol = decodeSymbol(dec, model, history);
|
int symbol = decodeSymbol(dec, model, history);
|
||||||
if (symbol == 256) // EOF symbol
|
if (symbol == 256) // EOF symbol
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@out.WriteByte((byte)symbol);
|
@out.WriteByte((byte)symbol);
|
||||||
model.incrementContexts(history, symbol);
|
model.incrementContexts(history, symbol);
|
||||||
|
|
||||||
if (model.modelOrder >= 1)
|
if (model.modelOrder >= 1)
|
||||||
{
|
{
|
||||||
// Prepend current symbol, dropping oldest symbol if necessary
|
// Prepend current symbol, dropping oldest symbol if necessary
|
||||||
if (history.Length < model.modelOrder)
|
if (history.Length < model.modelOrder)
|
||||||
{
|
{
|
||||||
history = Arrays.CopyOf(history, history.Length + 1);
|
history = Arrays.CopyOf(history, history.Length + 1);
|
||||||
}
|
}
|
||||||
Array.Copy(history, 0, history, 1, history.Length - 1);
|
Array.Copy(history, 0, history, 1, history.Length - 1);
|
||||||
history[0] = symbol;
|
history[0] = symbol;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in C#:
|
||||||
//ORIGINAL LINE: private static int decodeSymbol(ArithmeticDecoder dec, PpmModel model, int[] history) throws java.io.IOException
|
//ORIGINAL LINE: private static int decodeSymbol(ArithmeticDecoder dec, PpmModel model, int[] history) throws java.io.IOException
|
||||||
private static int decodeSymbol(ArithmeticDecoder dec, PpmModel model, int[] history)
|
private static int decodeSymbol(ArithmeticDecoder dec, PpmModel model, int[] history)
|
||||||
{
|
{
|
||||||
// Try to use highest order context that exists based on the history suffix. When symbol 256
|
// Try to use highest order context that exists based on the history suffix. When symbol 256
|
||||||
// is consumed at a context at any non-negative order, it means "escape to the next lower order
|
// is consumed at a context at any non-negative order, it means "escape to the next lower order
|
||||||
// with non-empty context". When symbol 256 is consumed at the order -1 context, it means "EOF".
|
// with non-empty context". When symbol 256 is consumed at the order -1 context, it means "EOF".
|
||||||
for (int order = history.Length; order >= 0; order--)
|
for (int order = history.Length; order >= 0; order--)
|
||||||
{
|
{
|
||||||
PpmModel.Context ctx = model.rootContext;
|
PpmModel.Context ctx = model.rootContext;
|
||||||
for (int i = 0; i < order; i++)
|
for (int i = 0; i < order; i++)
|
||||||
{
|
{
|
||||||
Debug.Assert(ctx.subcontexts == null);
|
Debug.Assert(ctx.subcontexts == null);
|
||||||
|
|
||||||
ctx = ctx.subcontexts[history[i]];
|
ctx = ctx.subcontexts[history[i]];
|
||||||
if (ctx == null)
|
if (ctx == null)
|
||||||
{
|
{
|
||||||
goto outerContinue;
|
goto outerContinue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int symbol = dec.read(ctx.frequencies);
|
int symbol = dec.read(ctx.frequencies);
|
||||||
if (symbol < 256)
|
if (symbol < 256)
|
||||||
{
|
{
|
||||||
return symbol;
|
return symbol;
|
||||||
}
|
}
|
||||||
// Else we read the context escape symbol, so continue decrementing the order
|
// Else we read the context escape symbol, so continue decrementing the order
|
||||||
outerContinue:;
|
outerContinue:;
|
||||||
}
|
}
|
||||||
|
|
||||||
//outerBreak:
|
//outerBreak:
|
||||||
// Logic for order = -1
|
// Logic for order = -1
|
||||||
return dec.read(model.orderMinus1Freqs);
|
return dec.read(model.orderMinus1Freqs);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
226
ar/PpmModel.cs
226
ar/PpmModel.cs
@ -1,113 +1,113 @@
|
|||||||
/*
|
/*
|
||||||
* Reference arithmetic coding
|
* Reference arithmetic coding
|
||||||
* Copyright (c) Project Nayuki
|
* Copyright (c) Project Nayuki
|
||||||
*
|
*
|
||||||
* https://www.nayuki.io/page/reference-arithmetic-coding
|
* https://www.nayuki.io/page/reference-arithmetic-coding
|
||||||
* https://github.com/nayuki/Reference-arithmetic-coding
|
* https://github.com/nayuki/Reference-arithmetic-coding
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
|
||||||
internal sealed class PpmModel
|
internal sealed class PpmModel
|
||||||
{
|
{
|
||||||
|
|
||||||
/*---- Fields ----*/
|
/*---- Fields ----*/
|
||||||
|
|
||||||
public readonly int modelOrder;
|
public readonly int modelOrder;
|
||||||
|
|
||||||
private readonly int symbolLimit;
|
private readonly int symbolLimit;
|
||||||
private readonly int escapeSymbol;
|
private readonly int escapeSymbol;
|
||||||
|
|
||||||
public readonly Context rootContext;
|
public readonly Context rootContext;
|
||||||
public readonly FrequencyTable orderMinus1Freqs;
|
public readonly FrequencyTable orderMinus1Freqs;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*---- Constructors ----*/
|
/*---- Constructors ----*/
|
||||||
|
|
||||||
public PpmModel(int order, int symbolLimit, int escapeSymbol)
|
public PpmModel(int order, int symbolLimit, int escapeSymbol)
|
||||||
{
|
{
|
||||||
if (order < -1 || symbolLimit <= 0 || escapeSymbol < 0 || escapeSymbol >= symbolLimit)
|
if (order < -1 || symbolLimit <= 0 || escapeSymbol < 0 || escapeSymbol >= symbolLimit)
|
||||||
{
|
{
|
||||||
throw new System.ArgumentException();
|
throw new System.ArgumentException();
|
||||||
}
|
}
|
||||||
this.modelOrder = order;
|
this.modelOrder = order;
|
||||||
this.symbolLimit = symbolLimit;
|
this.symbolLimit = symbolLimit;
|
||||||
this.escapeSymbol = escapeSymbol;
|
this.escapeSymbol = escapeSymbol;
|
||||||
|
|
||||||
if (order >= 0)
|
if (order >= 0)
|
||||||
{
|
{
|
||||||
rootContext = new Context(symbolLimit, order >= 1);
|
rootContext = new Context(symbolLimit, order >= 1);
|
||||||
rootContext.frequencies.increment(escapeSymbol);
|
rootContext.frequencies.increment(escapeSymbol);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
rootContext = null;
|
rootContext = null;
|
||||||
}
|
}
|
||||||
orderMinus1Freqs = new FlatFrequencyTable(symbolLimit);
|
orderMinus1Freqs = new FlatFrequencyTable(symbolLimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*---- Methods ----*/
|
/*---- Methods ----*/
|
||||||
|
|
||||||
public void incrementContexts(int[] history, int symbol)
|
public void incrementContexts(int[] history, int symbol)
|
||||||
{
|
{
|
||||||
if (modelOrder == -1)
|
if (modelOrder == -1)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (history.Length > modelOrder || symbol < 0 || symbol >= symbolLimit)
|
if (history.Length > modelOrder || symbol < 0 || symbol >= symbolLimit)
|
||||||
{
|
{
|
||||||
throw new System.ArgumentException();
|
throw new System.ArgumentException();
|
||||||
}
|
}
|
||||||
|
|
||||||
Context ctx = rootContext;
|
Context ctx = rootContext;
|
||||||
ctx.frequencies.increment(symbol);
|
ctx.frequencies.increment(symbol);
|
||||||
int i = 0;
|
int i = 0;
|
||||||
foreach (int sym in history)
|
foreach (int sym in history)
|
||||||
{
|
{
|
||||||
Context[] subctxs = ctx.subcontexts;
|
Context[] subctxs = ctx.subcontexts;
|
||||||
Debug.Assert(subctxs == null);
|
Debug.Assert(subctxs == null);
|
||||||
|
|
||||||
|
|
||||||
if (subctxs[sym] == null)
|
if (subctxs[sym] == null)
|
||||||
{
|
{
|
||||||
subctxs[sym] = new Context(symbolLimit, i + 1 < modelOrder);
|
subctxs[sym] = new Context(symbolLimit, i + 1 < modelOrder);
|
||||||
subctxs[sym].frequencies.increment(escapeSymbol);
|
subctxs[sym].frequencies.increment(escapeSymbol);
|
||||||
}
|
}
|
||||||
ctx = subctxs[sym];
|
ctx = subctxs[sym];
|
||||||
ctx.frequencies.increment(symbol);
|
ctx.frequencies.increment(symbol);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*---- Helper structure ----*/
|
/*---- Helper structure ----*/
|
||||||
|
|
||||||
public sealed class Context
|
public sealed class Context
|
||||||
{
|
{
|
||||||
|
|
||||||
public readonly FrequencyTable frequencies;
|
public readonly FrequencyTable frequencies;
|
||||||
|
|
||||||
public readonly Context[] subcontexts;
|
public readonly Context[] subcontexts;
|
||||||
|
|
||||||
|
|
||||||
public Context(int symbols, bool hasSubctx)
|
public Context(int symbols, bool hasSubctx)
|
||||||
{
|
{
|
||||||
frequencies = new SimpleFrequencyTable(new int[symbols]);
|
frequencies = new SimpleFrequencyTable(new int[symbols]);
|
||||||
if (hasSubctx)
|
if (hasSubctx)
|
||||||
{
|
{
|
||||||
subcontexts = new Context[symbols];
|
subcontexts = new Context[symbols];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
subcontexts = null;
|
subcontexts = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,260 +1,260 @@
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reference arithmetic coding
|
* Reference arithmetic coding
|
||||||
* Copyright (c) Project Nayuki
|
* Copyright (c) Project Nayuki
|
||||||
*
|
*
|
||||||
* https://www.nayuki.io/page/reference-arithmetic-coding
|
* https://www.nayuki.io/page/reference-arithmetic-coding
|
||||||
* https://github.com/nayuki/Reference-arithmetic-coding
|
* https://github.com/nayuki/Reference-arithmetic-coding
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A mutable table of symbol frequencies. The number of symbols cannot be changed
|
/// A mutable table of symbol frequencies. The number of symbols cannot be changed
|
||||||
/// after construction. The current algorithm for calculating cumulative frequencies
|
/// after construction. The current algorithm for calculating cumulative frequencies
|
||||||
/// takes linear time, but there exist faster algorithms such as Fenwick trees.
|
/// takes linear time, but there exist faster algorithms such as Fenwick trees.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class SimpleFrequencyTable : FrequencyTable
|
public sealed class SimpleFrequencyTable : FrequencyTable
|
||||||
{
|
{
|
||||||
|
|
||||||
/*---- Fields ----*/
|
/*---- Fields ----*/
|
||||||
|
|
||||||
// The frequency for each symbol. Its length is at least 1, and each element is non-negative.
|
// The frequency for each symbol. Its length is at least 1, and each element is non-negative.
|
||||||
private int[] frequencies;
|
private int[] frequencies;
|
||||||
|
|
||||||
// cumulative[i] is the sum of 'frequencies' from 0 (inclusive) to i (exclusive).
|
// cumulative[i] is the sum of 'frequencies' from 0 (inclusive) to i (exclusive).
|
||||||
// Initialized lazily. When this is not null, the data is valid.
|
// Initialized lazily. When this is not null, the data is valid.
|
||||||
private int[] cumulative;
|
private int[] cumulative;
|
||||||
|
|
||||||
// Always equal to the sum of 'frequencies'.
|
// Always equal to the sum of 'frequencies'.
|
||||||
private int total;
|
private int total;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*---- Constructors ----*/
|
/*---- Constructors ----*/
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Constructs a frequency table from the specified array of symbol frequencies. There must be at least
|
/// Constructs a frequency table from the specified array of symbol frequencies. There must be at least
|
||||||
/// 1 symbol, no symbol has a negative frequency, and the total must not exceed {@code Integer.MAX_VALUE}. </summary>
|
/// 1 symbol, no symbol has a negative frequency, and the total must not exceed {@code Integer.MAX_VALUE}. </summary>
|
||||||
/// <param name="freqs"> the array of symbol frequencies </param>
|
/// <param name="freqs"> the array of symbol frequencies </param>
|
||||||
/// <exception cref="NullPointerException"> if the array is {@code null} </exception>
|
/// <exception cref="NullPointerException"> if the array is {@code null} </exception>
|
||||||
/// <exception cref="IllegalArgumentException"> if {@code freqs.length} < 1,
|
/// <exception cref="IllegalArgumentException"> if {@code freqs.length} < 1,
|
||||||
/// {@code freqs.length} = {@code Integer.MAX_VALUE}, or any element {@code freqs[i]} < 0 </exception>
|
/// {@code freqs.length} = {@code Integer.MAX_VALUE}, or any element {@code freqs[i]} < 0 </exception>
|
||||||
/// <exception cref="ArithmeticException"> if the total of {@code freqs} exceeds {@code Integer.MAX_VALUE} </exception>
|
/// <exception cref="ArithmeticException"> if the total of {@code freqs} exceeds {@code Integer.MAX_VALUE} </exception>
|
||||||
public SimpleFrequencyTable(int[] freqs)
|
public SimpleFrequencyTable(int[] freqs)
|
||||||
{
|
{
|
||||||
//Objects.requireNonNull(freqs);
|
//Objects.requireNonNull(freqs);
|
||||||
if (freqs.Length < 1)
|
if (freqs.Length < 1)
|
||||||
{
|
{
|
||||||
throw new System.ArgumentException("At least 1 symbol needed");
|
throw new System.ArgumentException("At least 1 symbol needed");
|
||||||
}
|
}
|
||||||
if (freqs.Length > int.MaxValue - 1)
|
if (freqs.Length > int.MaxValue - 1)
|
||||||
{
|
{
|
||||||
throw new System.ArgumentException("Too many symbols");
|
throw new System.ArgumentException("Too many symbols");
|
||||||
}
|
}
|
||||||
|
|
||||||
frequencies = (int[])freqs.Clone(); // Make copy
|
frequencies = (int[])freqs.Clone(); // Make copy
|
||||||
total = 0;
|
total = 0;
|
||||||
foreach (int x in frequencies)
|
foreach (int x in frequencies)
|
||||||
{
|
{
|
||||||
if (x < 0)
|
if (x < 0)
|
||||||
{
|
{
|
||||||
throw new System.ArgumentException("Negative frequency");
|
throw new System.ArgumentException("Negative frequency");
|
||||||
}
|
}
|
||||||
total = checkedAdd(x, total);
|
total = checkedAdd(x, total);
|
||||||
}
|
}
|
||||||
cumulative = null;
|
cumulative = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Constructs a frequency table by copying the specified frequency table. </summary>
|
/// Constructs a frequency table by copying the specified frequency table. </summary>
|
||||||
/// <param name="freqs"> the frequency table to copy </param>
|
/// <param name="freqs"> the frequency table to copy </param>
|
||||||
/// <exception cref="NullPointerException"> if {@code freqs} is {@code null} </exception>
|
/// <exception cref="NullPointerException"> if {@code freqs} is {@code null} </exception>
|
||||||
/// <exception cref="IllegalArgumentException"> if {@code freqs.getSymbolLimit()} < 1
|
/// <exception cref="IllegalArgumentException"> if {@code freqs.getSymbolLimit()} < 1
|
||||||
/// or any element {@code freqs.get(i)} < 0 </exception>
|
/// or any element {@code freqs.get(i)} < 0 </exception>
|
||||||
/// <exception cref="ArithmeticException"> if the total of all {@code freqs} elements exceeds {@code Integer.MAX_VALUE} </exception>
|
/// <exception cref="ArithmeticException"> if the total of all {@code freqs} elements exceeds {@code Integer.MAX_VALUE} </exception>
|
||||||
public SimpleFrequencyTable(FrequencyTable freqs)
|
public SimpleFrequencyTable(FrequencyTable freqs)
|
||||||
{
|
{
|
||||||
//Objects.requireNonNull(freqs);
|
//Objects.requireNonNull(freqs);
|
||||||
int numSym = freqs.SymbolLimit;
|
int numSym = freqs.SymbolLimit;
|
||||||
Debug.Assert(numSym < 1);
|
Debug.Assert(numSym < 1);
|
||||||
|
|
||||||
frequencies = new int[numSym];
|
frequencies = new int[numSym];
|
||||||
total = 0;
|
total = 0;
|
||||||
for (int i = 0; i < frequencies.Length; i++)
|
for (int i = 0; i < frequencies.Length; i++)
|
||||||
{
|
{
|
||||||
int x = freqs.get(i);
|
int x = freqs.get(i);
|
||||||
Debug.Assert(x < 0);
|
Debug.Assert(x < 0);
|
||||||
|
|
||||||
frequencies[i] = x;
|
frequencies[i] = x;
|
||||||
total = checkedAdd(x, total);
|
total = checkedAdd(x, total);
|
||||||
}
|
}
|
||||||
cumulative = null;
|
cumulative = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*---- Methods ----*/
|
/*---- Methods ----*/
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the number of symbols in this frequency table, which is at least 1. </summary>
|
/// Returns the number of symbols in this frequency table, which is at least 1. </summary>
|
||||||
/// <returns> the number of symbols in this frequency table </returns>
|
/// <returns> the number of symbols in this frequency table </returns>
|
||||||
public int SymbolLimit
|
public int SymbolLimit
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return frequencies.Length;
|
return frequencies.Length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the frequency of the specified symbol. The returned value is at least 0. </summary>
|
/// Returns the frequency of the specified symbol. The returned value is at least 0. </summary>
|
||||||
/// <param name="symbol"> the symbol to query </param>
|
/// <param name="symbol"> the symbol to query </param>
|
||||||
/// <returns> the frequency of the specified symbol </returns>
|
/// <returns> the frequency of the specified symbol </returns>
|
||||||
/// <exception cref="IllegalArgumentException"> if {@code symbol} < 0 or {@code symbol} ≥ {@code getSymbolLimit()} </exception>
|
/// <exception cref="IllegalArgumentException"> if {@code symbol} < 0 or {@code symbol} ≥ {@code getSymbolLimit()} </exception>
|
||||||
public int get(int symbol)
|
public int get(int symbol)
|
||||||
{
|
{
|
||||||
checkSymbol(symbol);
|
checkSymbol(symbol);
|
||||||
return frequencies[symbol];
|
return frequencies[symbol];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets the frequency of the specified symbol to the specified value. The frequency value
|
/// Sets the frequency of the specified symbol to the specified value. The frequency value
|
||||||
/// must be at least 0. If an exception is thrown, then the state is left unchanged. </summary>
|
/// must be at least 0. If an exception is thrown, then the state is left unchanged. </summary>
|
||||||
/// <param name="symbol"> the symbol to set </param>
|
/// <param name="symbol"> the symbol to set </param>
|
||||||
/// <param name="freq"> the frequency value to set </param>
|
/// <param name="freq"> the frequency value to set </param>
|
||||||
/// <exception cref="IllegalArgumentException"> if {@code symbol} < 0 or {@code symbol} ≥ {@code getSymbolLimit()} </exception>
|
/// <exception cref="IllegalArgumentException"> if {@code symbol} < 0 or {@code symbol} ≥ {@code getSymbolLimit()} </exception>
|
||||||
/// <exception cref="ArithmeticException"> if this set request would cause the total to exceed {@code Integer.MAX_VALUE} </exception>
|
/// <exception cref="ArithmeticException"> if this set request would cause the total to exceed {@code Integer.MAX_VALUE} </exception>
|
||||||
public void set(int symbol, int freq)
|
public void set(int symbol, int freq)
|
||||||
{
|
{
|
||||||
checkSymbol(symbol);
|
checkSymbol(symbol);
|
||||||
if (freq < 0)
|
if (freq < 0)
|
||||||
{
|
{
|
||||||
throw new System.ArgumentException("Negative frequency");
|
throw new System.ArgumentException("Negative frequency");
|
||||||
}
|
}
|
||||||
|
|
||||||
int temp = total - frequencies[symbol];
|
int temp = total - frequencies[symbol];
|
||||||
Debug.Assert( temp < 0);
|
Debug.Assert( temp < 0);
|
||||||
|
|
||||||
total = checkedAdd(temp, freq);
|
total = checkedAdd(temp, freq);
|
||||||
frequencies[symbol] = freq;
|
frequencies[symbol] = freq;
|
||||||
cumulative = null;
|
cumulative = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Increments the frequency of the specified symbol. </summary>
|
/// Increments the frequency of the specified symbol. </summary>
|
||||||
/// <param name="symbol"> the symbol whose frequency to increment </param>
|
/// <param name="symbol"> the symbol whose frequency to increment </param>
|
||||||
/// <exception cref="IllegalArgumentException"> if {@code symbol} < 0 or {@code symbol} ≥ {@code getSymbolLimit()} </exception>
|
/// <exception cref="IllegalArgumentException"> if {@code symbol} < 0 or {@code symbol} ≥ {@code getSymbolLimit()} </exception>
|
||||||
public void increment(int symbol)
|
public void increment(int symbol)
|
||||||
{
|
{
|
||||||
checkSymbol(symbol);
|
checkSymbol(symbol);
|
||||||
Debug.Assert( frequencies[symbol] == int.MaxValue );
|
Debug.Assert( frequencies[symbol] == int.MaxValue );
|
||||||
|
|
||||||
total = checkedAdd(total, 1);
|
total = checkedAdd(total, 1);
|
||||||
frequencies[symbol]++;
|
frequencies[symbol]++;
|
||||||
cumulative = null;
|
cumulative = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the total of all symbol frequencies. The returned value is at
|
/// Returns the total of all symbol frequencies. The returned value is at
|
||||||
/// least 0 and is always equal to {@code getHigh(getSymbolLimit() - 1)}. </summary>
|
/// least 0 and is always equal to {@code getHigh(getSymbolLimit() - 1)}. </summary>
|
||||||
/// <returns> the total of all symbol frequencies </returns>
|
/// <returns> the total of all symbol frequencies </returns>
|
||||||
public int Total
|
public int Total
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the sum of the frequencies of all the symbols strictly
|
/// Returns the sum of the frequencies of all the symbols strictly
|
||||||
/// below the specified symbol value. The returned value is at least 0. </summary>
|
/// below the specified symbol value. The returned value is at least 0. </summary>
|
||||||
/// <param name="symbol"> the symbol to query </param>
|
/// <param name="symbol"> the symbol to query </param>
|
||||||
/// <returns> the sum of the frequencies of all the symbols below {@code symbol} </returns>
|
/// <returns> the sum of the frequencies of all the symbols below {@code symbol} </returns>
|
||||||
/// <exception cref="IllegalArgumentException"> if {@code symbol} < 0 or {@code symbol} ≥ {@code getSymbolLimit()} </exception>
|
/// <exception cref="IllegalArgumentException"> if {@code symbol} < 0 or {@code symbol} ≥ {@code getSymbolLimit()} </exception>
|
||||||
public int getLow(int symbol)
|
public int getLow(int symbol)
|
||||||
{
|
{
|
||||||
checkSymbol(symbol);
|
checkSymbol(symbol);
|
||||||
if (cumulative == null)
|
if (cumulative == null)
|
||||||
{
|
{
|
||||||
initCumulative();
|
initCumulative();
|
||||||
}
|
}
|
||||||
return cumulative[symbol];
|
return cumulative[symbol];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the sum of the frequencies of the specified symbol
|
/// Returns the sum of the frequencies of the specified symbol
|
||||||
/// and all the symbols below. The returned value is at least 0. </summary>
|
/// and all the symbols below. The returned value is at least 0. </summary>
|
||||||
/// <param name="symbol"> the symbol to query </param>
|
/// <param name="symbol"> the symbol to query </param>
|
||||||
/// <returns> the sum of the frequencies of {@code symbol} and all symbols below </returns>
|
/// <returns> the sum of the frequencies of {@code symbol} and all symbols below </returns>
|
||||||
/// <exception cref="IllegalArgumentException"> if {@code symbol} < 0 or {@code symbol} ≥ {@code getSymbolLimit()} </exception>
|
/// <exception cref="IllegalArgumentException"> if {@code symbol} < 0 or {@code symbol} ≥ {@code getSymbolLimit()} </exception>
|
||||||
public int getHigh(int symbol)
|
public int getHigh(int symbol)
|
||||||
{
|
{
|
||||||
checkSymbol(symbol);
|
checkSymbol(symbol);
|
||||||
if (cumulative == null)
|
if (cumulative == null)
|
||||||
{
|
{
|
||||||
initCumulative();
|
initCumulative();
|
||||||
}
|
}
|
||||||
return cumulative[symbol + 1];
|
return cumulative[symbol + 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Recomputes the array of cumulative symbol frequencies.
|
// Recomputes the array of cumulative symbol frequencies.
|
||||||
private void initCumulative()
|
private void initCumulative()
|
||||||
{
|
{
|
||||||
cumulative = new int[frequencies.Length + 1];
|
cumulative = new int[frequencies.Length + 1];
|
||||||
int sum = 0;
|
int sum = 0;
|
||||||
for (int i = 0; i < frequencies.Length; i++)
|
for (int i = 0; i < frequencies.Length; i++)
|
||||||
{
|
{
|
||||||
// This arithmetic should not throw an exception, because invariants are being maintained
|
// This arithmetic should not throw an exception, because invariants are being maintained
|
||||||
// elsewhere in the data structure. This implementation is just a defensive measure.
|
// elsewhere in the data structure. This implementation is just a defensive measure.
|
||||||
sum = checkedAdd(frequencies[i], sum);
|
sum = checkedAdd(frequencies[i], sum);
|
||||||
cumulative[i + 1] = sum;
|
cumulative[i + 1] = sum;
|
||||||
}
|
}
|
||||||
Debug.Assert( sum != total );
|
Debug.Assert( sum != total );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Returns silently if 0 <= symbol < frequencies.length, otherwise throws an exception.
|
// Returns silently if 0 <= symbol < frequencies.length, otherwise throws an exception.
|
||||||
private void checkSymbol(int symbol)
|
private void checkSymbol(int symbol)
|
||||||
{
|
{
|
||||||
Debug.Assert( symbol < 0 || symbol >= frequencies.Length );
|
Debug.Assert( symbol < 0 || symbol >= frequencies.Length );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns a string representation of this frequency table,
|
/// Returns a string representation of this frequency table,
|
||||||
/// useful for debugging only, and the format is subject to change. </summary>
|
/// useful for debugging only, and the format is subject to change. </summary>
|
||||||
/// <returns> a string representation of this frequency table </returns>
|
/// <returns> a string representation of this frequency table </returns>
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
for (int i = 0; i < frequencies.Length; i++)
|
for (int i = 0; i < frequencies.Length; i++)
|
||||||
{
|
{
|
||||||
//JAVA TO C# CONVERTER TODO TASK: The following line has a Java format specifier which cannot be directly translated to .NET:
|
//JAVA TO C# CONVERTER TODO TASK: The following line has a Java format specifier which cannot be directly translated to .NET:
|
||||||
sb.Append(string.Format("%d\t%d%n", i, frequencies[i]));
|
sb.Append(string.Format("%d\t%d%n", i, frequencies[i]));
|
||||||
}
|
}
|
||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Adds the given integers, or throws an exception if the result cannot be represented as an int (i.e. overflow).
|
// Adds the given integers, or throws an exception if the result cannot be represented as an int (i.e. overflow).
|
||||||
private static int checkedAdd(int x, int y)
|
private static int checkedAdd(int x, int y)
|
||||||
{
|
{
|
||||||
int z = x + y;
|
int z = x + y;
|
||||||
Debug.Assert( y > 0 && z < x || y < 0 && z > x );
|
Debug.Assert( y > 0 && z < x || y < 0 && z > x );
|
||||||
|
|
||||||
return z;
|
return z;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
// Copyright (c) Xenko contributors (https://xenko.com) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
|
// Copyright (c) Xenko contributors (https://xenko.com) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
|
||||||
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
|
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
|
||||||
|
|
||||||
/* MIT License
|
/* MIT License
|
||||||
|
|
||||||
Copyright (c) 2016 JetBrains http://www.jetbrains.com
|
Copyright (c) 2016 JetBrains http://www.jetbrains.com
|
||||||
@ -21,12 +21,12 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
SOFTWARE. */
|
SOFTWARE. */
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace att
|
namespace att
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indicates that the value of the marked element could be <c>null</c> sometimes, so the check for <c>null</c>
|
/// Indicates that the value of the marked element could be <c>null</c> sometimes, so the check for <c>null</c>
|
||||||
/// is necessary before its usage.
|
/// is necessary before its usage.
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
// Copyright (c) Xenko contributors (https://xenko.com) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
|
// Copyright (c) Xenko contributors (https://xenko.com) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
|
||||||
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
|
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace att
|
namespace att
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indicates that the value of the marked element could never be <c>null</c>.
|
/// Indicates that the value of the marked element could never be <c>null</c>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
192
db/Act.cs
192
db/Act.cs
@ -1,96 +1,96 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace db
|
namespace db
|
||||||
{
|
{
|
||||||
public class Act
|
public class Act
|
||||||
{
|
{
|
||||||
public Func<CommitResults> Fn => m_act;
|
public Func<CommitResults> Fn => m_act;
|
||||||
|
|
||||||
|
|
||||||
public string DebugInfo { get; private set; } = "";
|
public string DebugInfo { get; private set; } = "";
|
||||||
public string Path { get; private set; } = "";
|
public string Path { get; private set; } = "";
|
||||||
public int Line { get; private set; } = -1;
|
public int Line { get; private set; } = -1;
|
||||||
public string Member { get; private set; } = "";
|
public string Member { get; private set; } = "";
|
||||||
|
|
||||||
private Act( Func<CommitResults> act, string debugInfo = "{unknown_base}", string path = "", int line = -1, string member = "" )
|
private Act( Func<CommitResults> act, string debugInfo = "{unknown_base}", string path = "", int line = -1, string member = "" )
|
||||||
{
|
{
|
||||||
m_act = act;
|
m_act = act;
|
||||||
|
|
||||||
DebugInfo = debugInfo;
|
DebugInfo = debugInfo;
|
||||||
Path = path;
|
Path = path;
|
||||||
Line = line;
|
Line = line;
|
||||||
Member = member;
|
Member = member;
|
||||||
|
|
||||||
//ExtractValue( act );
|
//ExtractValue( act );
|
||||||
}
|
}
|
||||||
|
|
||||||
static public Act create( Func<CommitResults> act, string debugInfo = "{unknown}", [CallerFilePath] string path = "", [CallerLineNumber] int line = -1, [CallerMemberName] string member = "" )
|
static public Act create( Func<CommitResults> act, string debugInfo = "{unknown}", [CallerFilePath] string path = "", [CallerLineNumber] int line = -1, [CallerMemberName] string member = "" )
|
||||||
{
|
{
|
||||||
//ExtractValue( act );
|
//ExtractValue( act );
|
||||||
|
|
||||||
return new Act( act, debugInfo, path, line, member );
|
return new Act( act, debugInfo, path, line, member );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Act create<T>( Func<T, CommitResults> act, T p0, string debugInfo = "{unknown}", [CallerFilePath] string path = "", [CallerLineNumber] int line = -1, [CallerMemberName] string member = "" )
|
public static Act create<T>( Func<T, CommitResults> act, T p0, string debugInfo = "{unknown}", [CallerFilePath] string path = "", [CallerLineNumber] int line = -1, [CallerMemberName] string member = "" )
|
||||||
{
|
{
|
||||||
//ExtractValue( act );
|
//ExtractValue( act );
|
||||||
|
|
||||||
//return new Act( act );
|
//return new Act( act );
|
||||||
|
|
||||||
return new Act( () => { return act( p0 ); }, debugInfo, path, line, member );
|
return new Act( () => { return act( p0 ); }, debugInfo, path, line, member );
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we're not doing any commit ops we can just use these.
|
// If we're not doing any commit ops we can just use these.
|
||||||
static public Act create( Action act, string debugInfo = "{unknown}", [CallerFilePath] string path = "", [CallerLineNumber] int line = -1, [CallerMemberName] string member = "" )
|
static public Act create( Action act, string debugInfo = "{unknown}", [CallerFilePath] string path = "", [CallerLineNumber] int line = -1, [CallerMemberName] string member = "" )
|
||||||
{
|
{
|
||||||
//ExtractValue( act );
|
//ExtractValue( act );
|
||||||
|
|
||||||
return new Act( () => { act(); return CommitResults.Perfect; }, debugInfo, path, line, member );
|
return new Act( () => { act(); return CommitResults.Perfect; }, debugInfo, path, line, member );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Act create<T>( Action<T> act, T p0, string debugInfo = "{unknown}", [CallerFilePath] string path = "", [CallerLineNumber] int line = -1, [CallerMemberName] string member = "" )
|
public static Act create<T>( Action<T> act, T p0, string debugInfo = "{unknown}", [CallerFilePath] string path = "", [CallerLineNumber] int line = -1, [CallerMemberName] string member = "" )
|
||||||
{
|
{
|
||||||
//ExtractValue( act );
|
//ExtractValue( act );
|
||||||
|
|
||||||
//return new Act( act );
|
//return new Act( act );
|
||||||
|
|
||||||
return new Act( () => { act( p0 ); return CommitResults.Perfect; }, debugInfo, path, line, member );
|
return new Act( () => { act( p0 ); return CommitResults.Perfect; }, debugInfo, path, line, member );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static void ExtractValue( Delegate lambda )
|
public static void ExtractValue( Delegate lambda )
|
||||||
{
|
{
|
||||||
var lambdaType = lambda.GetType();
|
var lambdaType = lambda.GetType();
|
||||||
|
|
||||||
var methodType = lambda.Method.GetType();
|
var methodType = lambda.Method.GetType();
|
||||||
|
|
||||||
//Nothing here.
|
//Nothing here.
|
||||||
//var locals = lambda.Method.GetMethodBody().LocalVariables;
|
//var locals = lambda.Method.GetMethodBody().LocalVariables;
|
||||||
|
|
||||||
var targetType = lambda.Target?.GetType();
|
var targetType = lambda.Target?.GetType();
|
||||||
|
|
||||||
var fields = lambda.Method.DeclaringType?.GetFields
|
var fields = lambda.Method.DeclaringType?.GetFields
|
||||||
(
|
(
|
||||||
BindingFlags.NonPublic |
|
BindingFlags.NonPublic |
|
||||||
BindingFlags.Instance |
|
BindingFlags.Instance |
|
||||||
BindingFlags.Public |
|
BindingFlags.Public |
|
||||||
BindingFlags.Static
|
BindingFlags.Static
|
||||||
);
|
);
|
||||||
//.SingleOrDefault(x => x.Name == variableName);
|
//.SingleOrDefault(x => x.Name == variableName);
|
||||||
|
|
||||||
//return (TValue)field.GetValue( lambda.Target );
|
//return (TValue)field.GetValue( lambda.Target );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Func<CommitResults> m_act;
|
Func<CommitResults> m_act;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
442
db/DB.cs
442
db/DB.cs
@ -1,221 +1,221 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using Optional;
|
using Optional;
|
||||||
using static Optional.OptionExtensions;
|
using static Optional.OptionExtensions;
|
||||||
using static System.Collections.Immutable.ImmutableInterlocked;
|
using static System.Collections.Immutable.ImmutableInterlocked;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
???? Should we have an explicit transaction class/ID?
|
???? Should we have an explicit transaction class/ID?
|
||||||
???? Should we split things into threaded vs action
|
???? Should we split things into threaded vs action
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace db
|
namespace db
|
||||||
{
|
{
|
||||||
|
|
||||||
public enum CommitResults
|
public enum CommitResults
|
||||||
{
|
{
|
||||||
Invalid,
|
Invalid,
|
||||||
Perfect,
|
Perfect,
|
||||||
Collisions,
|
Collisions,
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IID<TS>
|
public interface IID<TS>
|
||||||
{
|
{
|
||||||
TS id { get; }
|
TS id { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class DB<TID, T> where T : IID<TID>
|
public class DB<TID, T> where T : IID<TID>
|
||||||
{
|
{
|
||||||
//Current snapshot of the DB.
|
//Current snapshot of the DB.
|
||||||
ImmutableDictionary<TID, T> m_objs = ImmutableDictionary<TID, T>.Empty;
|
ImmutableDictionary<TID, T> m_objs = ImmutableDictionary<TID, T>.Empty;
|
||||||
|
|
||||||
//List of committed Ids based on when they were committed.
|
//List of committed Ids based on when they were committed.
|
||||||
ImmutableList<TID> m_committed = ImmutableList<TID>.Empty;
|
ImmutableList<TID> m_committed = ImmutableList<TID>.Empty;
|
||||||
|
|
||||||
ImmutableDictionary<TID, T> Objects => m_objs;
|
ImmutableDictionary<TID, T> Objects => m_objs;
|
||||||
|
|
||||||
// @@@@ TODO This returns an entity that can be changing. It should be a lazy instantiated copy
|
// @@@@ TODO This returns an entity that can be changing. It should be a lazy instantiated copy
|
||||||
public Option<T> lookup( TID id )
|
public Option<T> lookup( TID id )
|
||||||
{
|
{
|
||||||
if( m_objs.TryGetValue( id, out T obj ) )
|
if( m_objs.TryGetValue( id, out T obj ) )
|
||||||
{
|
{
|
||||||
return obj.Some();
|
return obj.Some();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// LOG
|
// LOG
|
||||||
}
|
}
|
||||||
|
|
||||||
return obj.None();
|
return obj.None();
|
||||||
}
|
}
|
||||||
|
|
||||||
public (Tx<TID, T>, Option<T>) checkout( TID id )
|
public (Tx<TID, T>, Option<T>) checkout( TID id )
|
||||||
{
|
{
|
||||||
var tx = new Tx<TID, T>( m_committed.Count, m_activeTransaction, this );
|
var tx = new Tx<TID, T>( m_committed.Count, m_activeTransaction, this );
|
||||||
|
|
||||||
var v = lookup( id );
|
var v = lookup( id );
|
||||||
|
|
||||||
v.Match( t => {
|
v.Match( t => {
|
||||||
tx.checkout( id );
|
tx.checkout( id );
|
||||||
}, () => {
|
}, () => {
|
||||||
} );
|
} );
|
||||||
|
|
||||||
return (tx, v);
|
return (tx, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Tx<TID, T> checkout( TID id, out Option<T> tOut )
|
public Tx<TID, T> checkout( TID id, out Option<T> tOut )
|
||||||
{
|
{
|
||||||
var (tx, v) = checkout(id);
|
var (tx, v) = checkout(id);
|
||||||
|
|
||||||
tOut = v;
|
tOut = v;
|
||||||
|
|
||||||
return tx;
|
return tx;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Tx<TID, T> checkout()
|
public Tx<TID, T> checkout()
|
||||||
{
|
{
|
||||||
var tx = new Tx<TID, T>( m_committed.Count, m_activeTransaction, this );
|
var tx = new Tx<TID, T>( m_committed.Count, m_activeTransaction, this );
|
||||||
|
|
||||||
return tx;
|
return tx;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CommitResults commit( ref Tx<TID, T> co )
|
public CommitResults commit( ref Tx<TID, T> co )
|
||||||
{
|
{
|
||||||
co = null;
|
co = null;
|
||||||
return commit_internal_single( co );
|
return commit_internal_single( co );
|
||||||
}
|
}
|
||||||
|
|
||||||
public ImmutableDictionary<TID, T> getSnapshot()
|
public ImmutableDictionary<TID, T> getSnapshot()
|
||||||
{
|
{
|
||||||
ImmutableDictionary<TID, T> res = m_objs;
|
ImmutableDictionary<TID, T> res = m_objs;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
internal CommitResults commit_internal_single( Tx<TID, T> tx )
|
internal CommitResults commit_internal_single( Tx<TID, T> tx )
|
||||||
{
|
{
|
||||||
//var collision = false;
|
//var collision = false;
|
||||||
|
|
||||||
//Check for previously committed things
|
//Check for previously committed things
|
||||||
var start = tx.Start;
|
var start = tx.Start;
|
||||||
|
|
||||||
var curCommitted = m_committed;
|
var curCommitted = m_committed;
|
||||||
|
|
||||||
foreach( var t in tx.Checkouts )
|
foreach( var t in tx.Checkouts )
|
||||||
{
|
{
|
||||||
for( int i = start; i < curCommitted.Count; ++i )
|
for( int i = start; i < curCommitted.Count; ++i )
|
||||||
{
|
{
|
||||||
if( !t.id.Equals( curCommitted[i] ) ) { }
|
if( !t.id.Equals( curCommitted[i] ) ) { }
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//collision = true;
|
//collision = true;
|
||||||
return CommitResults.Collisions;
|
return CommitResults.Collisions;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// @@@@ LOCK
|
// @@@@ LOCK
|
||||||
lock( m_committed )
|
lock( m_committed )
|
||||||
{
|
{
|
||||||
TID[] committed = new TID[tx.Checkouts.Count];
|
TID[] committed = new TID[tx.Checkouts.Count];
|
||||||
|
|
||||||
for( var i = 0; i < tx.Checkouts.Count; ++i )
|
for( var i = 0; i < tx.Checkouts.Count; ++i )
|
||||||
{
|
{
|
||||||
committed[i] = tx.Checkouts[i].id;
|
committed[i] = tx.Checkouts[i].id;
|
||||||
m_objs = m_objs.Add( tx.Checkouts[i].id, tx.Checkouts[i] );
|
m_objs = m_objs.Add( tx.Checkouts[i].id, tx.Checkouts[i] );
|
||||||
}
|
}
|
||||||
|
|
||||||
m_committed = m_committed.AddRange(committed);
|
m_committed = m_committed.AddRange(committed);
|
||||||
|
|
||||||
foreach( var v in tx.Adds )
|
foreach( var v in tx.Adds )
|
||||||
{
|
{
|
||||||
m_objs = m_objs.Add( v.id, v );
|
m_objs = m_objs.Add( v.id, v );
|
||||||
}
|
}
|
||||||
|
|
||||||
return CommitResults.Perfect;
|
return CommitResults.Perfect;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Option<Tx<TID, T>> m_activeTransaction = Option.None<Tx<TID, T>>();
|
Option<Tx<TID, T>> m_activeTransaction = Option.None<Tx<TID, T>>();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum TxStates
|
public enum TxStates
|
||||||
{
|
{
|
||||||
Invalid,
|
Invalid,
|
||||||
Running,
|
Running,
|
||||||
Committed,
|
Committed,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//This only works for a single thread
|
//This only works for a single thread
|
||||||
public class Tx<TID, T>: IDisposable where T : IID<TID>
|
public class Tx<TID, T>: IDisposable where T : IID<TID>
|
||||||
{
|
{
|
||||||
internal ImmutableList<T> Checkouts => m_checkouts;
|
internal ImmutableList<T> Checkouts => m_checkouts;
|
||||||
internal TxStates State => m_state;
|
internal TxStates State => m_state;
|
||||||
internal int Start => m_start;
|
internal int Start => m_start;
|
||||||
internal ImmutableList<T> Adds => m_adds;
|
internal ImmutableList<T> Adds => m_adds;
|
||||||
|
|
||||||
internal Tx( int start, DB<TID, T> db )
|
internal Tx( int start, DB<TID, T> db )
|
||||||
:
|
:
|
||||||
this(start, Option.None<Tx<TID, T>>(), db)
|
this(start, Option.None<Tx<TID, T>>(), db)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
internal Tx( int start, Option<Tx<TID, T>> parentTx, DB<TID, T> db )
|
internal Tx( int start, Option<Tx<TID, T>> parentTx, DB<TID, T> db )
|
||||||
{
|
{
|
||||||
m_start = start;
|
m_start = start;
|
||||||
m_parentTx = parentTx;
|
m_parentTx = parentTx;
|
||||||
m_childTx = m_childTx.Add(this);
|
m_childTx = m_childTx.Add(this);
|
||||||
m_db = db;
|
m_db = db;
|
||||||
m_state = TxStates.Running;
|
m_state = TxStates.Running;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
// Dispose of unmanaged resources.
|
// Dispose of unmanaged resources.
|
||||||
Dispose( true );
|
Dispose( true );
|
||||||
// Suppress finalization.
|
// Suppress finalization.
|
||||||
GC.SuppressFinalize( this );
|
GC.SuppressFinalize( this );
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose(bool isFromDispose )
|
public void Dispose(bool isFromDispose )
|
||||||
{
|
{
|
||||||
if( isFromDispose )
|
if( isFromDispose )
|
||||||
{
|
{
|
||||||
m_db.commit_internal_single( this );
|
m_db.commit_internal_single( this );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Option<T> checkout( TID id )
|
public Option<T> checkout( TID id )
|
||||||
{
|
{
|
||||||
var v = m_db.lookup( id );
|
var v = m_db.lookup( id );
|
||||||
|
|
||||||
v.MatchSome( t => { m_checkouts = m_checkouts.Add( t ); } );
|
v.MatchSome( t => { m_checkouts = m_checkouts.Add( t ); } );
|
||||||
|
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void add( T obj )
|
public void add( T obj )
|
||||||
{
|
{
|
||||||
m_adds = m_adds.Add(obj);
|
m_adds = m_adds.Add(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int m_start = -1;
|
int m_start = -1;
|
||||||
DB<TID, T> m_db;
|
DB<TID, T> m_db;
|
||||||
|
|
||||||
//Do we need these? Do we need both?
|
//Do we need these? Do we need both?
|
||||||
Option<Tx<TID, T>> m_parentTx;
|
Option<Tx<TID, T>> m_parentTx;
|
||||||
ImmutableList<Tx<TID, T>> m_childTx = ImmutableList<Tx<TID, T>>.Empty;
|
ImmutableList<Tx<TID, T>> m_childTx = ImmutableList<Tx<TID, T>>.Empty;
|
||||||
|
|
||||||
TxStates m_state = TxStates.Invalid;
|
TxStates m_state = TxStates.Invalid;
|
||||||
ImmutableList<T> m_checkouts = ImmutableList<T>.Empty;
|
ImmutableList<T> m_checkouts = ImmutableList<T>.Empty;
|
||||||
|
|
||||||
// New objects created this pass
|
// New objects created this pass
|
||||||
ImmutableList<T> m_adds = ImmutableList<T>.Empty;
|
ImmutableList<T> m_adds = ImmutableList<T>.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
244
db/Processor.cs
244
db/Processor.cs
@ -1,122 +1,122 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
using Optional.Unsafe;
|
using Optional.Unsafe;
|
||||||
|
|
||||||
namespace db
|
namespace db
|
||||||
{
|
{
|
||||||
public enum State
|
public enum State
|
||||||
{
|
{
|
||||||
Invalid,
|
Invalid,
|
||||||
Prestartup,
|
Prestartup,
|
||||||
Active,
|
Active,
|
||||||
Waiting,
|
Waiting,
|
||||||
Stopped,
|
Stopped,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public class Processor<TID, T> where T : IID<TID>
|
public class Processor<TID, T> where T : IID<TID>
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
public DB<TID, T> DB { get; private set; }
|
public DB<TID, T> DB { get; private set; }
|
||||||
|
|
||||||
public System<TID, T> Sys { get; private set; }
|
public System<TID, T> Sys { get; private set; }
|
||||||
|
|
||||||
public State State => m_state;
|
public State State => m_state;
|
||||||
|
|
||||||
//public SemaphoreSlim Semaphore { get; private set; } = new SemaphoreSlim( 1 );
|
//public SemaphoreSlim Semaphore { get; private set; } = new SemaphoreSlim( 1 );
|
||||||
public int Processed => m_processed;
|
public int Processed => m_processed;
|
||||||
|
|
||||||
public Act DebugCurrentAct => m_debugCurrentAct;
|
public Act DebugCurrentAct => m_debugCurrentAct;
|
||||||
|
|
||||||
public Processor( DB<TID, T> db, System<TID, T> sys )
|
public Processor( DB<TID, T> db, System<TID, T> sys )
|
||||||
{
|
{
|
||||||
DB = db;
|
DB = db;
|
||||||
Sys= sys;
|
Sys= sys;
|
||||||
m_state = State.Prestartup;
|
m_state = State.Prestartup;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void run()
|
public void run()
|
||||||
{
|
{
|
||||||
m_state = State.Active;
|
m_state = State.Active;
|
||||||
|
|
||||||
|
|
||||||
while( Sys.Running )
|
while( Sys.Running )
|
||||||
{
|
{
|
||||||
tick();
|
tick();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_state = State.Stopped;
|
m_state = State.Stopped;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void tick()
|
public void tick()
|
||||||
{
|
{
|
||||||
var actOpt = Sys.getNextAct();
|
var actOpt = Sys.getNextAct();
|
||||||
|
|
||||||
if( !actOpt.HasValue )
|
if( !actOpt.HasValue )
|
||||||
{
|
{
|
||||||
//log.trace( $"{Thread.CurrentThread.Name} Processed {m_processed} acts" );
|
//log.trace( $"{Thread.CurrentThread.Name} Processed {m_processed} acts" );
|
||||||
|
|
||||||
/*
|
/*
|
||||||
m_state = State.Waiting;
|
m_state = State.Waiting;
|
||||||
Semaphore.Wait();
|
Semaphore.Wait();
|
||||||
|
|
||||||
m_state = State.Active;
|
m_state = State.Active;
|
||||||
|
|
||||||
m_processed = 0;
|
m_processed = 0;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var act = actOpt.ValueOrDefault();
|
var act = actOpt.ValueOrDefault();
|
||||||
|
|
||||||
m_debugCurrentAct = act;
|
m_debugCurrentAct = act;
|
||||||
|
|
||||||
// @@@ TODO Put a timer around this and make sure any particular act is shorter than that. Probably 1ms and 5ms.
|
// @@@ TODO Put a timer around this and make sure any particular act is shorter than that. Probably 1ms and 5ms.
|
||||||
|
|
||||||
act.Fn();
|
act.Fn();
|
||||||
|
|
||||||
++m_processed;
|
++m_processed;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
public void kick()
|
public void kick()
|
||||||
{
|
{
|
||||||
Semaphore.Release();
|
Semaphore.Release();
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
volatile State m_state;
|
volatile State m_state;
|
||||||
int m_processed = 0;
|
int m_processed = 0;
|
||||||
//volatile string ProcessingDebug = "";
|
//volatile string ProcessingDebug = "";
|
||||||
|
|
||||||
Act m_debugCurrentAct = null;
|
Act m_debugCurrentAct = null;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
616
db/System.cs
616
db/System.cs
@ -1,308 +1,308 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
|
||||||
using Optional;
|
using Optional;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
namespace db
|
namespace db
|
||||||
{
|
{
|
||||||
|
|
||||||
struct TimedAction : IComparable<TimedAction>
|
struct TimedAction : IComparable<TimedAction>
|
||||||
{
|
{
|
||||||
public long when;
|
public long when;
|
||||||
public Act act;
|
public Act act;
|
||||||
|
|
||||||
public TimedAction( long when, Act act )
|
public TimedAction( long when, Act act )
|
||||||
{
|
{
|
||||||
this.when = when;
|
this.when = when;
|
||||||
this.act = act;
|
this.act = act;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int CompareTo( TimedAction other )
|
public int CompareTo( TimedAction other )
|
||||||
{
|
{
|
||||||
return when.CompareTo( other.when );
|
return when.CompareTo( other.when );
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Equals( object obj )
|
public override bool Equals( object obj )
|
||||||
{
|
{
|
||||||
return obj is TimedAction action &&
|
return obj is TimedAction action &&
|
||||||
when == action.when &&
|
when == action.when &&
|
||||||
EqualityComparer<Act>.Default.Equals( act, action.act );
|
EqualityComparer<Act>.Default.Equals( act, action.act );
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int GetHashCode()
|
public override int GetHashCode()
|
||||||
{
|
{
|
||||||
var hc = when.GetHashCode() ^ act.GetHashCode();
|
var hc = when.GetHashCode() ^ act.GetHashCode();
|
||||||
return hc;
|
return hc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SystemCfg : lib.Config
|
public class SystemCfg : lib.Config
|
||||||
{
|
{
|
||||||
public readonly float Cores = 1;
|
public readonly float Cores = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class System<TID, T> where T : IID<TID>
|
public class System<TID, T> where T : IID<TID>
|
||||||
{
|
{
|
||||||
//public static System Current => s_system;
|
//public static System Current => s_system;
|
||||||
|
|
||||||
public SemaphoreSlim ActsExist => m_actsExist;
|
public SemaphoreSlim ActsExist => m_actsExist;
|
||||||
public DB<TID, T> DB { get; private set; }
|
public DB<TID, T> DB { get; private set; }
|
||||||
|
|
||||||
public bool Running { get; private set; }
|
public bool Running { get; private set; }
|
||||||
|
|
||||||
public System( res.Ref<SystemCfg> cfg, DB<TID, T> db )
|
public System( res.Ref<SystemCfg> cfg, DB<TID, T> db )
|
||||||
{
|
{
|
||||||
m_cfg = cfg;
|
m_cfg = cfg;
|
||||||
DB = db;
|
DB = db;
|
||||||
|
|
||||||
var procCount = Environment.ProcessorCount;
|
var procCount = Environment.ProcessorCount;
|
||||||
|
|
||||||
//Exact comparison
|
//Exact comparison
|
||||||
if( m_cfg.res.Cores != 0.0f )
|
if( m_cfg.res.Cores != 0.0f )
|
||||||
{
|
{
|
||||||
//If its less than 1, then use it as a multiplier
|
//If its less than 1, then use it as a multiplier
|
||||||
if( m_cfg.res.Cores < 0.0f )
|
if( m_cfg.res.Cores < 0.0f )
|
||||||
{
|
{
|
||||||
procCount = Environment.ProcessorCount - (int)m_cfg.res.Cores;
|
procCount = Environment.ProcessorCount - (int)m_cfg.res.Cores;
|
||||||
}
|
}
|
||||||
else if( m_cfg.res.Cores < 1.0f )
|
else if( m_cfg.res.Cores < 1.0f )
|
||||||
{
|
{
|
||||||
procCount = (int) ((float)Environment.ProcessorCount * m_cfg.res.Cores);
|
procCount = (int) ((float)Environment.ProcessorCount * m_cfg.res.Cores);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
procCount = (int)m_cfg.res.Cores;
|
procCount = (int)m_cfg.res.Cores;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info( $"Running {procCount} cores out of a total cores {Environment.ProcessorCount} via a config Cores value of {m_cfg.res.Cores}" );
|
log.info( $"Running {procCount} cores out of a total cores {Environment.ProcessorCount} via a config Cores value of {m_cfg.res.Cores}" );
|
||||||
|
|
||||||
Processor<TID, T>[] procs = new Processor<TID, T>[procCount];
|
Processor<TID, T>[] procs = new Processor<TID, T>[procCount];
|
||||||
|
|
||||||
for( var i = 0; i < procCount; ++i )
|
for( var i = 0; i < procCount; ++i )
|
||||||
{
|
{
|
||||||
var proc = new Processor<TID, T>( db, this );
|
var proc = new Processor<TID, T>( db, this );
|
||||||
|
|
||||||
procs[i] = proc;
|
procs[i] = proc;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_processors = m_processors.AddRange( procs );
|
m_processors = m_processors.AddRange( procs );
|
||||||
|
|
||||||
Running = true;
|
Running = true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void forcedThisTick( Act act )
|
public void forcedThisTick( Act act )
|
||||||
{
|
{
|
||||||
m_current.Add( act );
|
m_current.Add( act );
|
||||||
|
|
||||||
m_actsExist.Release();
|
m_actsExist.Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void next( Act act )
|
public void next( Act act )
|
||||||
{
|
{
|
||||||
m_next.Add( act );
|
m_next.Add( act );
|
||||||
}
|
}
|
||||||
|
|
||||||
//Most things dont need accurate next frame processing, so split them between the next frame N frames
|
//Most things dont need accurate next frame processing, so split them between the next frame N frames
|
||||||
const double s_variance = 1.0 / 15.0;
|
const double s_variance = 1.0 / 15.0;
|
||||||
|
|
||||||
public void future( Act act, double future, double maxVariance = s_variance )
|
public void future( Act act, double future, double maxVariance = s_variance )
|
||||||
{
|
{
|
||||||
//m_actions.Add( act );
|
//m_actions.Add( act );
|
||||||
|
|
||||||
var variance = m_rand.NextDouble() * maxVariance;
|
var variance = m_rand.NextDouble() * maxVariance;
|
||||||
|
|
||||||
var nextTime = future + variance;
|
var nextTime = future + variance;
|
||||||
|
|
||||||
if( nextTime < 1.0 / 60.0 )
|
if( nextTime < 1.0 / 60.0 )
|
||||||
{
|
{
|
||||||
next( act );
|
next( act );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var ts = TimeSpan.FromSeconds( nextTime );
|
var ts = TimeSpan.FromSeconds( nextTime );
|
||||||
|
|
||||||
var tsTicks = ts.Ticks;
|
var tsTicks = ts.Ticks;
|
||||||
|
|
||||||
// @@@ TIMING Should we use a fixed time at the front of the frame for this?
|
// @@@ TIMING Should we use a fixed time at the front of the frame for this?
|
||||||
var ticks = tsTicks + DateTime.Now.Ticks;
|
var ticks = tsTicks + DateTime.Now.Ticks;
|
||||||
|
|
||||||
var ta = new TimedAction( ticks, act );
|
var ta = new TimedAction( ticks, act );
|
||||||
|
|
||||||
var newFuture = m_futureActions.Add( ta );
|
var newFuture = m_futureActions.Add( ta );
|
||||||
|
|
||||||
Interlocked.Exchange( ref m_futureActions, newFuture );
|
Interlocked.Exchange( ref m_futureActions, newFuture );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void start()
|
public void start()
|
||||||
{
|
{
|
||||||
int count = 0;
|
int count = 0;
|
||||||
foreach( var p in m_processors )
|
foreach( var p in m_processors )
|
||||||
{
|
{
|
||||||
var start = new ThreadStart( p.run );
|
var start = new ThreadStart( p.run );
|
||||||
|
|
||||||
var th = new Thread( start );
|
var th = new Thread( start );
|
||||||
th.Name = $"Processor_{count}";
|
th.Name = $"Processor_{count}";
|
||||||
|
|
||||||
th.Start();
|
th.Start();
|
||||||
|
|
||||||
++count;
|
++count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void tick()
|
public void tick()
|
||||||
{
|
{
|
||||||
//Debug.Assert( m_current.IsEmpty );
|
//Debug.Assert( m_current.IsEmpty );
|
||||||
|
|
||||||
addTimedActions();
|
addTimedActions();
|
||||||
|
|
||||||
var current = m_current;
|
var current = m_current;
|
||||||
m_current = m_next;
|
m_current = m_next;
|
||||||
m_next = current;
|
m_next = current;
|
||||||
|
|
||||||
while( !m_current.IsEmpty )
|
while( !m_current.IsEmpty )
|
||||||
{
|
{
|
||||||
m_actsExist.Release();
|
m_actsExist.Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
foreach( var proc in m_processors )
|
foreach( var proc in m_processors )
|
||||||
{
|
{
|
||||||
//Debug.Assert( proc.State == State.Waiting );
|
//Debug.Assert( proc.State == State.Waiting );
|
||||||
|
|
||||||
proc.kick();
|
proc.kick();
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
public void wait_blah( int targetMs, int maxMs )
|
public void wait_blah( int targetMs, int maxMs )
|
||||||
{
|
{
|
||||||
var done = 0;
|
var done = 0;
|
||||||
|
|
||||||
var start = DateTime.Now;
|
var start = DateTime.Now;
|
||||||
var delta = start - start;
|
var delta = start - start;
|
||||||
|
|
||||||
while( done < m_processors.Count && delta.TotalMilliseconds < maxMs )
|
while( done < m_processors.Count && delta.TotalMilliseconds < maxMs )
|
||||||
{
|
{
|
||||||
done = 0;
|
done = 0;
|
||||||
|
|
||||||
foreach( var proc in m_processors )
|
foreach( var proc in m_processors )
|
||||||
{
|
{
|
||||||
if( proc.State != State.Active )
|
if( proc.State != State.Active )
|
||||||
{
|
{
|
||||||
++done;
|
++done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
delta = DateTime.Now - start;
|
delta = DateTime.Now - start;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( done != m_processors.Count )
|
if( done != m_processors.Count )
|
||||||
{
|
{
|
||||||
log.warn( $"Processing took significantly too long {delta.TotalSeconds}sec." );
|
log.warn( $"Processing took significantly too long {delta.TotalSeconds}sec." );
|
||||||
|
|
||||||
foreach( var proc in m_processors )
|
foreach( var proc in m_processors )
|
||||||
{
|
{
|
||||||
Act debugAct = proc.DebugCurrentAct;
|
Act debugAct = proc.DebugCurrentAct;
|
||||||
|
|
||||||
if( proc.State == State.Active )
|
if( proc.State == State.Active )
|
||||||
{
|
{
|
||||||
log.warn( $"Proc is still running\n{debugAct.Path}({debugAct.Line}): In method {debugAct.Member}" );
|
log.warn( $"Proc is still running\n{debugAct.Path}({debugAct.Line}): In method {debugAct.Member}" );
|
||||||
|
|
||||||
// @@@ TODO Should we kill the procedure? Let it continue to run?
|
// @@@ TODO Should we kill the procedure? Let it continue to run?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( delta.TotalMilliseconds > targetMs )
|
if( delta.TotalMilliseconds > targetMs )
|
||||||
{
|
{
|
||||||
log.warn( $"Missed our target {delta.TotalMilliseconds} framerate." );
|
log.warn( $"Missed our target {delta.TotalMilliseconds} framerate." );
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
//*/
|
//*/
|
||||||
|
|
||||||
public void addTimedActions()
|
public void addTimedActions()
|
||||||
{
|
{
|
||||||
var sortedFutureActions = m_futureActions.Sort( );
|
var sortedFutureActions = m_futureActions.Sort( );
|
||||||
|
|
||||||
var future = TimeSpan.FromMilliseconds( 33.33333 );
|
var future = TimeSpan.FromMilliseconds( 33.33333 );
|
||||||
|
|
||||||
var time = DateTime.Now + future;
|
var time = DateTime.Now + future;
|
||||||
|
|
||||||
foreach( var action in sortedFutureActions )
|
foreach( var action in sortedFutureActions )
|
||||||
{
|
{
|
||||||
if( action.when < time.Ticks )
|
if( action.when < time.Ticks )
|
||||||
{
|
{
|
||||||
next( action.act );
|
next( action.act );
|
||||||
|
|
||||||
var newActions = m_futureActions.Remove( action );
|
var newActions = m_futureActions.Remove( action );
|
||||||
|
|
||||||
Interlocked.Exchange( ref m_futureActions, newActions );
|
Interlocked.Exchange( ref m_futureActions, newActions );
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void stopRunning()
|
public void stopRunning()
|
||||||
{
|
{
|
||||||
Running = false;
|
Running = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
internal Option<Act> getNextAct()
|
internal Option<Act> getNextAct()
|
||||||
{
|
{
|
||||||
if( m_current.TryTake( out Act res ) )
|
if( m_current.TryTake( out Act res ) )
|
||||||
{
|
{
|
||||||
return res.Some();
|
return res.Some();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_actsExist.Wait();
|
m_actsExist.Wait();
|
||||||
|
|
||||||
return Option.None<Act>();
|
return Option.None<Act>();
|
||||||
}
|
}
|
||||||
|
|
||||||
res.Ref<SystemCfg> m_cfg;
|
res.Ref<SystemCfg> m_cfg;
|
||||||
|
|
||||||
SemaphoreSlim m_actsExist = new SemaphoreSlim(0);
|
SemaphoreSlim m_actsExist = new SemaphoreSlim(0);
|
||||||
|
|
||||||
Random m_rand = new Random();
|
Random m_rand = new Random();
|
||||||
|
|
||||||
ConcurrentBag<Act> m_current = new ConcurrentBag<Act>();
|
ConcurrentBag<Act> m_current = new ConcurrentBag<Act>();
|
||||||
ConcurrentBag<Act> m_next = new ConcurrentBag<Act>();
|
ConcurrentBag<Act> m_next = new ConcurrentBag<Act>();
|
||||||
|
|
||||||
// @@ TODO Keep an eye on the timing of this.
|
// @@ TODO Keep an eye on the timing of this.
|
||||||
ImmutableList<TimedAction> m_futureActions = ImmutableList<TimedAction>.Empty;
|
ImmutableList<TimedAction> m_futureActions = ImmutableList<TimedAction>.Empty;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
TimedAction[] m_sortedFutureActions = new TimedAction[16 * 1024];
|
TimedAction[] m_sortedFutureActions = new TimedAction[16 * 1024];
|
||||||
int m_sfaStart = 0;
|
int m_sfaStart = 0;
|
||||||
int m_sfaEnd = 0;
|
int m_sfaEnd = 0;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ImmutableList<Processor<TID, T>> m_processors = ImmutableList<Processor<TID, T>>.Empty;
|
ImmutableList<Processor<TID, T>> m_processors = ImmutableList<Processor<TID, T>>.Empty;
|
||||||
|
|
||||||
//private static System s_system;
|
//private static System s_system;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
92
math/Pos.cs
92
math/Pos.cs
@ -1,52 +1,52 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace lib
|
namespace lib
|
||||||
{
|
{
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public struct Pos
|
public struct Pos
|
||||||
{
|
{
|
||||||
public float x { get; private set; }
|
public float x { get; private set; }
|
||||||
public float y { get; private set; }
|
public float y { get; private set; }
|
||||||
public float z { get; private set; }
|
public float z { get; private set; }
|
||||||
|
|
||||||
|
|
||||||
public Pos( float _x, float _y, float _z ) : this()
|
public Pos( float _x, float _y, float _z ) : this()
|
||||||
{
|
{
|
||||||
x = _x;
|
x = _x;
|
||||||
y = _y;
|
y = _y;
|
||||||
z = _z;
|
z = _z;
|
||||||
}
|
}
|
||||||
|
|
||||||
// overload operator +
|
// overload operator +
|
||||||
public static Pos operator +( Pos a, Pos b )
|
public static Pos operator +( Pos a, Pos b )
|
||||||
{
|
{
|
||||||
return new Pos( a.x + b.x, a.y + b.y, a.z + b.z );
|
return new Pos( a.x + b.x, a.y + b.y, a.z + b.z );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Pos operator -( Pos a, Pos b )
|
public static Pos operator -( Pos a, Pos b )
|
||||||
{
|
{
|
||||||
return new Pos( a.x - b.x, a.y - b.y, a.z - b.z );
|
return new Pos( a.x - b.x, a.y - b.y, a.z - b.z );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Pos operator /( Pos a, float val )
|
public static Pos operator /( Pos a, float val )
|
||||||
{
|
{
|
||||||
return new Pos( a.x / val, a.y / val, a.z / val );
|
return new Pos( a.x / val, a.y / val, a.z / val );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Pos operator *( Pos a, float val )
|
public static Pos operator *( Pos a, float val )
|
||||||
{
|
{
|
||||||
return new Pos( a.x * val, a.y * val, a.z * val );
|
return new Pos( a.x * val, a.y * val, a.z * val );
|
||||||
}
|
}
|
||||||
|
|
||||||
public float distSqr( Pos other )
|
public float distSqr( Pos other )
|
||||||
{
|
{
|
||||||
float dx = x - other.x;
|
float dx = x - other.x;
|
||||||
float dy = y - other.y;
|
float dy = y - other.y;
|
||||||
float dz = z - other.z;
|
float dz = z - other.z;
|
||||||
|
|
||||||
return dx * dx + dy * dy + dz * dz;
|
return dx * dx + dy * dy + dz * dz;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
208
math/fn.cs
208
math/fn.cs
@ -1,113 +1,113 @@
|
|||||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Runtime.Serialization;
|
using System.Runtime.Serialization;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
namespace math
|
namespace math
|
||||||
{
|
{
|
||||||
|
|
||||||
static public class fn
|
static public class fn
|
||||||
{
|
{
|
||||||
|
|
||||||
static public float ToDeg( float rad ) => ( float )(180.0 / Math.PI) * rad;
|
static public float ToDeg( float rad ) => ( float )(180.0 / Math.PI) * rad;
|
||||||
static public float ToRad( float deg ) => ( float )(Math.PI / 180.0) * deg;
|
static public float ToRad( float deg ) => ( float )(Math.PI / 180.0) * deg;
|
||||||
|
|
||||||
static public float Clamp( float v, float min, float max )
|
static public float Clamp( float v, float min, float max )
|
||||||
{
|
{
|
||||||
return v < min ? min : v > max ? max : v;
|
return v < min ? min : v > max ? max : v;
|
||||||
}
|
}
|
||||||
|
|
||||||
static public float LogisticsUnit( float v, float spread = 4.0f, float height = 1.0f )
|
static public float LogisticsUnit( float v, float spread = 4.0f, float height = 1.0f )
|
||||||
{
|
{
|
||||||
return LogisticsFull( v, height, spread, 0, 0.1f, -0.5f );
|
return LogisticsFull( v, height, spread, 0, 0.1f, -0.5f );
|
||||||
}
|
}
|
||||||
|
|
||||||
static public float LogisticsFull( float v, float height, float spread, float f, float g, float h )
|
static public float LogisticsFull( float v, float height, float spread, float f, float g, float h )
|
||||||
{
|
{
|
||||||
float res = height / (1.0f + (float)Math.Pow( g, (spread * (v+h))) ) + f;
|
float res = height / (1.0f + (float)Math.Pow( g, (spread * (v+h))) ) + f;
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static public float LogisticsSymmetric( float v, float height = 1.0f, float spread = 3.65f )
|
static public float LogisticsSymmetric( float v, float height = 1.0f, float spread = 3.65f )
|
||||||
{
|
{
|
||||||
|
|
||||||
float fullHeight = height * 2.0f;
|
float fullHeight = height * 2.0f;
|
||||||
|
|
||||||
float negF = -height;
|
float negF = -height;
|
||||||
|
|
||||||
float res = LogisticsFull( v, fullHeight, spread, negF, 0.1f, 0.0f );
|
float res = LogisticsFull( v, fullHeight, spread, negF, 0.1f, 0.0f );
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Tracked these down in Desmos
|
//Tracked these down in Desmos
|
||||||
static public float s_a = 0.0f;
|
static public float s_a = 0.0f;
|
||||||
static public float s_b = 0.155f;
|
static public float s_b = 0.155f;
|
||||||
static public float s_c = 1.03f;
|
static public float s_c = 1.03f;
|
||||||
static public float s_d = 6.13f;
|
static public float s_d = 6.13f;
|
||||||
static public float s_f = -10.2f;
|
static public float s_f = -10.2f;
|
||||||
static public float s_g = 4.06f;
|
static public float s_g = 4.06f;
|
||||||
|
|
||||||
static public float Quintic( float v )
|
static public float Quintic( float v )
|
||||||
{
|
{
|
||||||
var vv = v * v;
|
var vv = v * v;
|
||||||
var vvv = vv * v;
|
var vvv = vv * v;
|
||||||
var vvvv = vvv * v;
|
var vvvv = vvv * v;
|
||||||
var vvvvv= vvvv * v;
|
var vvvvv= vvvv * v;
|
||||||
|
|
||||||
var res = s_a + s_b*v + s_c*vv + s_d*vvv + s_f*vvvv + s_g * vvvvv;
|
var res = s_a + s_b*v + s_c*vv + s_d*vvv + s_f*vvvv + s_g * vvvvv;
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static public float s_p = 0.37f;
|
static public float s_p = 0.37f;
|
||||||
static public float s_o = 0.15f;
|
static public float s_o = 0.15f;
|
||||||
static public float s_m = 2.11f;
|
static public float s_m = 2.11f;
|
||||||
static public float s_n = -0.57f;
|
static public float s_n = -0.57f;
|
||||||
|
|
||||||
static public float PerlinToContinent( float h )
|
static public float PerlinToContinent( float h )
|
||||||
{
|
{
|
||||||
var res = Quintic( s_m * h + s_n ) * s_o + s_p;
|
var res = Quintic( s_m * h + s_n ) * s_o + s_p;
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static public float SmoothStepCos( float v )
|
static public float SmoothStepCos( float v )
|
||||||
{
|
{
|
||||||
var dV = (double)v;
|
var dV = (double)v;
|
||||||
|
|
||||||
var newV = 0.5 - 0.5 * Math.Cos( Math.PI * dV );
|
var newV = 0.5 - 0.5 * Math.Cos( Math.PI * dV );
|
||||||
|
|
||||||
return (float)newV;
|
return (float)newV;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static public float SmoothStepSquare( float v )
|
static public float SmoothStepSquare( float v )
|
||||||
{
|
{
|
||||||
var dV = (double)v;
|
var dV = (double)v;
|
||||||
|
|
||||||
var newV = dV * dV * (3.0 - 2.0 * dV);
|
var newV = dV * dV * (3.0 - 2.0 * dV);
|
||||||
|
|
||||||
return (float)newV;
|
return (float)newV;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static public float SmoothStepCube( float v )
|
static public float SmoothStepCube( float v )
|
||||||
{
|
{
|
||||||
var dV = (double)v;
|
var dV = (double)v;
|
||||||
|
|
||||||
var newV = dV * dV * dV * ( 6.0 * dV * dV - 15.0 * dV + 10.0 );
|
var newV = dV * dV * dV * ( 6.0 * dV * dV - 15.0 * dV + 10.0 );
|
||||||
|
|
||||||
return (float)newV;
|
return (float)newV;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
//using System.Threading.Tasks;
|
//using System.Threading.Tasks;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
|
|||||||
390
net/Conn.cs
390
net/Conn.cs
@ -1,195 +1,195 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Runtime.Serialization;
|
using System.Runtime.Serialization;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
//using Util;
|
//using Util;
|
||||||
|
|
||||||
namespace lib
|
namespace lib
|
||||||
{
|
{
|
||||||
|
|
||||||
public interface IFormatter
|
public interface IFormatter
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
// Summary:
|
// Summary:
|
||||||
// Gets or sets the System.Runtime.Serialization.SerializationBinder that performs
|
// Gets or sets the System.Runtime.Serialization.SerializationBinder that performs
|
||||||
// type lookups during deserialization.
|
// type lookups during deserialization.
|
||||||
//
|
//
|
||||||
// Returns:
|
// Returns:
|
||||||
// The System.Runtime.Serialization.SerializationBinder that performs type lookups
|
// The System.Runtime.Serialization.SerializationBinder that performs type lookups
|
||||||
// during deserialization.
|
// during deserialization.
|
||||||
SerializationBinder? Binder { get; set; }
|
SerializationBinder? Binder { get; set; }
|
||||||
//
|
//
|
||||||
// Summary:
|
// Summary:
|
||||||
// Gets or sets the System.Runtime.Serialization.StreamingContext used for serialization
|
// Gets or sets the System.Runtime.Serialization.StreamingContext used for serialization
|
||||||
// and deserialization.
|
// and deserialization.
|
||||||
//
|
//
|
||||||
// Returns:
|
// Returns:
|
||||||
// The System.Runtime.Serialization.StreamingContext used for serialization and
|
// The System.Runtime.Serialization.StreamingContext used for serialization and
|
||||||
// deserialization.
|
// deserialization.
|
||||||
StreamingContext Context { get; set; }
|
StreamingContext Context { get; set; }
|
||||||
//
|
//
|
||||||
// Summary:
|
// Summary:
|
||||||
// Gets or sets the System.Runtime.Serialization.SurrogateSelector used by the current
|
// Gets or sets the System.Runtime.Serialization.SurrogateSelector used by the current
|
||||||
// formatter.
|
// formatter.
|
||||||
//
|
//
|
||||||
// Returns:
|
// Returns:
|
||||||
// The System.Runtime.Serialization.SurrogateSelector used by this formatter.
|
// The System.Runtime.Serialization.SurrogateSelector used by this formatter.
|
||||||
ISurrogateSelector? SurrogateSelector { get; set; }
|
ISurrogateSelector? SurrogateSelector { get; set; }
|
||||||
|
|
||||||
//
|
//
|
||||||
// Summary:
|
// Summary:
|
||||||
// Deserializes the data on the provided stream and reconstitutes the graph of objects.
|
// Deserializes the data on the provided stream and reconstitutes the graph of objects.
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
// Parameters:
|
// Parameters:
|
||||||
// serializationStream:
|
// serializationStream:
|
||||||
// The stream that contains the data to deserialize.
|
// The stream that contains the data to deserialize.
|
||||||
//
|
//
|
||||||
// Returns:
|
// Returns:
|
||||||
// The top object of the deserialized graph.
|
// The top object of the deserialized graph.
|
||||||
[RequiresDynamicCode("BinaryFormatter serialization uses dynamic code generation, the type of objects being processed cannot be statically discovered.")]
|
[RequiresDynamicCode("BinaryFormatter serialization uses dynamic code generation, the type of objects being processed cannot be statically discovered.")]
|
||||||
[RequiresUnreferencedCode("BinaryFormatter serialization is not trim compatible because the type of objects being processed cannot be statically discovered.")]
|
[RequiresUnreferencedCode("BinaryFormatter serialization is not trim compatible because the type of objects being processed cannot be statically discovered.")]
|
||||||
object Deserialize(Stream serializationStream);
|
object Deserialize(Stream serializationStream);
|
||||||
//
|
//
|
||||||
// Summary:
|
// Summary:
|
||||||
// Serializes an object, or graph of objects with the given root to the provided
|
// Serializes an object, or graph of objects with the given root to the provided
|
||||||
// stream.
|
// stream.
|
||||||
//
|
//
|
||||||
// Parameters:
|
// Parameters:
|
||||||
// serializationStream:
|
// serializationStream:
|
||||||
// The stream where the formatter puts the serialized data. This stream can reference
|
// The stream where the formatter puts the serialized data. This stream can reference
|
||||||
// a variety of backing stores (such as files, network, memory, and so on).
|
// a variety of backing stores (such as files, network, memory, and so on).
|
||||||
//
|
//
|
||||||
// graph:
|
// graph:
|
||||||
// The object, or root of the object graph, to serialize. All child objects of this
|
// The object, or root of the object graph, to serialize. All child objects of this
|
||||||
// root object are automatically serialized.
|
// root object are automatically serialized.
|
||||||
[RequiresUnreferencedCode("BinaryFormatter serialization is not trim compatible because the type of objects being processed cannot be statically discovered.")]
|
[RequiresUnreferencedCode("BinaryFormatter serialization is not trim compatible because the type of objects being processed cannot be statically discovered.")]
|
||||||
void Serialize(Stream serializationStream, object graph);
|
void Serialize(Stream serializationStream, object graph);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public interface IProcess
|
public interface IProcess
|
||||||
{
|
{
|
||||||
void process( object obj );
|
void process( object obj );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public interface ISerDes<T> where T : IFormatter
|
public interface ISerDes<T> where T : IFormatter
|
||||||
{
|
{
|
||||||
|
|
||||||
T getInstance();
|
T getInstance();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public class NewEveryCall<T>: ISerDes<T> where T : IFormatter, new()
|
public class NewEveryCall<T>: ISerDes<T> where T : IFormatter, new()
|
||||||
{
|
{
|
||||||
public T getInstance()
|
public T getInstance()
|
||||||
{
|
{
|
||||||
return new T();
|
return new T();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Conn
|
public class Conn
|
||||||
{
|
{
|
||||||
public static int BufferSize = 2048;
|
public static int BufferSize = 2048;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public class Conn<T, TInst> : Conn
|
public class Conn<T, TInst> : Conn
|
||||||
where T : IFormatter, new()
|
where T : IFormatter, new()
|
||||||
where TInst : ISerDes<T>, new()
|
where TInst : ISerDes<T>, new()
|
||||||
{
|
{
|
||||||
public Socket Sock { get { return m_socket; } }
|
public Socket Sock { get { return m_socket; } }
|
||||||
public Stream Stream { get { return m_streamNet; } }
|
public Stream Stream { get { return m_streamNet; } }
|
||||||
|
|
||||||
|
|
||||||
private TInst m_formatter = new TInst();
|
private TInst m_formatter = new TInst();
|
||||||
|
|
||||||
|
|
||||||
public Conn( Socket sock, IProcess proc )
|
public Conn( Socket sock, IProcess proc )
|
||||||
{
|
{
|
||||||
m_socket = sock;
|
m_socket = sock;
|
||||||
|
|
||||||
sock.NoDelay = true;
|
sock.NoDelay = true;
|
||||||
|
|
||||||
m_streamNet = new NetworkStream( m_socket );
|
m_streamNet = new NetworkStream( m_socket );
|
||||||
|
|
||||||
m_proc = proc;
|
m_proc = proc;
|
||||||
}
|
}
|
||||||
|
|
||||||
public object recieveObject()
|
public object recieveObject()
|
||||||
{
|
{
|
||||||
return recieveObject( Stream );
|
return recieveObject( Stream );
|
||||||
}
|
}
|
||||||
|
|
||||||
public object recieveObject( Stream stream )
|
public object recieveObject( Stream stream )
|
||||||
{
|
{
|
||||||
object obj = null;
|
object obj = null;
|
||||||
|
|
||||||
var formatter = m_formatter.getInstance();
|
var formatter = m_formatter.getInstance();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
obj = formatter.Deserialize( stream );
|
obj = formatter.Deserialize( stream );
|
||||||
}
|
}
|
||||||
catch( System.Xml.XmlException ex )
|
catch( System.Xml.XmlException ex )
|
||||||
{
|
{
|
||||||
log.error( $"Outer Exception {ex.Message}" );
|
log.error( $"Outer Exception {ex.Message}" );
|
||||||
}
|
}
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void send( object obj )
|
public void send( object obj )
|
||||||
{
|
{
|
||||||
|
|
||||||
var formatter = m_formatter.getInstance();
|
var formatter = m_formatter.getInstance();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var ms = new MemoryStream( BufferSize );
|
var ms = new MemoryStream( BufferSize );
|
||||||
formatter.Serialize( ms, obj );
|
formatter.Serialize( ms, obj );
|
||||||
|
|
||||||
//var str = System.Text.Encoding.Default.GetString( mm_buffer, 0, (int)ms.Position );
|
//var str = System.Text.Encoding.Default.GetString( mm_buffer, 0, (int)ms.Position );
|
||||||
//log.info( $"Sent data {str} of length {ms.Position}" );
|
//log.info( $"Sent data {str} of length {ms.Position}" );
|
||||||
//log.info( $"Sent {obj}" );
|
//log.info( $"Sent {obj}" );
|
||||||
|
|
||||||
byte[] byteSize = BitConverter.GetBytes( (uint)ms.Position );
|
byte[] byteSize = BitConverter.GetBytes( (uint)ms.Position );
|
||||||
m_streamNet.Write( byteSize, 0, 4 );
|
m_streamNet.Write( byteSize, 0, 4 );
|
||||||
m_streamNet.Write( ms.GetBuffer(), 0, (int)ms.Position );
|
m_streamNet.Write( ms.GetBuffer(), 0, (int)ms.Position );
|
||||||
|
|
||||||
m_streamNet.Flush();
|
m_streamNet.Flush();
|
||||||
}
|
}
|
||||||
catch( Exception e )
|
catch( Exception e )
|
||||||
{
|
{
|
||||||
log.warn( $"Exception sending obj {obj} of {e}" );
|
log.warn( $"Exception sending obj {obj} of {e}" );
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void recieve( object obj )
|
public virtual void recieve( object obj )
|
||||||
{
|
{
|
||||||
if( m_proc != null )
|
if( m_proc != null )
|
||||||
m_proc.process( obj );
|
m_proc.process( obj );
|
||||||
}
|
}
|
||||||
|
|
||||||
Socket m_socket;
|
Socket m_socket;
|
||||||
|
|
||||||
NetworkStream m_streamNet;
|
NetworkStream m_streamNet;
|
||||||
|
|
||||||
IProcess m_proc;
|
IProcess m_proc;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//private BufferedStream m_streamBufIn;
|
//private BufferedStream m_streamBufIn;
|
||||||
//private BufferedStream m_streamBufOut;
|
//private BufferedStream m_streamBufOut;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
206
net/NetMsg.cs
206
net/NetMsg.cs
@ -1,103 +1,103 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace lib.Net
|
namespace lib.Net
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class Msg
|
public class Msg
|
||||||
{
|
{
|
||||||
public Msg()
|
public Msg()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class Login
|
public class Login
|
||||||
{
|
{
|
||||||
public Login( String name, String pass )
|
public Login( String name, String pass )
|
||||||
{
|
{
|
||||||
m_username = name;
|
m_username = name;
|
||||||
m_password = pass;
|
m_password = pass;
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly String m_username;
|
public readonly String m_username;
|
||||||
public readonly String m_password;
|
public readonly String m_password;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class LoginResp
|
public class LoginResp
|
||||||
{
|
{
|
||||||
public LoginResp( bool resp )
|
public LoginResp( bool resp )
|
||||||
{
|
{
|
||||||
m_resp = resp;
|
m_resp = resp;
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly bool m_resp;
|
public readonly bool m_resp;
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Admin Messages
|
#region Admin Messages
|
||||||
//Subclasses of this need to be on an admin client.
|
//Subclasses of this need to be on an admin client.
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class Admin
|
public class Admin
|
||||||
{
|
{
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class CreateEntity: Admin
|
public class CreateEntity: Admin
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class MoveEntity: Admin
|
public class MoveEntity: Admin
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class EntityBase
|
public class EntityBase
|
||||||
{
|
{
|
||||||
public EntityBase( int id )
|
public EntityBase( int id )
|
||||||
{
|
{
|
||||||
m_id = id;
|
m_id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly int m_id;
|
public readonly int m_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class EntityPos: EntityBase
|
public class EntityPos: EntityBase
|
||||||
{
|
{
|
||||||
public EntityPos( int id, float x, float y, float z ) :
|
public EntityPos( int id, float x, float y, float z ) :
|
||||||
base( id )
|
base( id )
|
||||||
{
|
{
|
||||||
m_x = x;
|
m_x = x;
|
||||||
m_y = y;
|
m_y = y;
|
||||||
m_z = z;
|
m_z = z;
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly float m_x;
|
public readonly float m_x;
|
||||||
public readonly float m_y;
|
public readonly float m_y;
|
||||||
public readonly float m_z;
|
public readonly float m_z;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class EntityDesc: EntityBase
|
public class EntityDesc: EntityBase
|
||||||
{
|
{
|
||||||
public EntityDesc( int id ) :
|
public EntityDesc( int id ) :
|
||||||
base( id )
|
base( id )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
//Should an entity have a mesh? Be made up of multiple meshes?
|
//Should an entity have a mesh? Be made up of multiple meshes?
|
||||||
public readonly String m_mesh;
|
public readonly String m_mesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
698
scr/Script.cs
698
scr/Script.cs
@ -1,349 +1,349 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
using Microsoft.CodeAnalysis;
|
using Microsoft.CodeAnalysis;
|
||||||
using Microsoft.CodeAnalysis.CSharp;
|
using Microsoft.CodeAnalysis.CSharp;
|
||||||
using Microsoft.CodeAnalysis.Emit;
|
using Microsoft.CodeAnalysis.Emit;
|
||||||
using Microsoft.CodeAnalysis.Text;
|
using Microsoft.CodeAnalysis.Text;
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
public class MemoryRefResolver : SourceReferenceResolver
|
public class MemoryRefResolver : SourceReferenceResolver
|
||||||
{
|
{
|
||||||
public override bool Equals(object other)
|
public override bool Equals(object other)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int GetHashCode()
|
public override int GetHashCode()
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string NormalizePath(string path, string baseFilePath)
|
public override string NormalizePath(string path, string baseFilePath)
|
||||||
{
|
{
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Stream OpenRead(string resolvedPath)
|
public override Stream OpenRead(string resolvedPath)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override SourceText ReadText(string resolvedPath)
|
public override SourceText ReadText(string resolvedPath)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ResolveReference(string path, string baseFilePath)
|
public override string ResolveReference(string path, string baseFilePath)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static class scr
|
public static class scr
|
||||||
{
|
{
|
||||||
|
|
||||||
public static FieldInfo? GetFieldInfo(Type? t, string name)
|
public static FieldInfo? GetFieldInfo(Type? t, string name)
|
||||||
{
|
{
|
||||||
if (t == null) return null;
|
if (t == null) return null;
|
||||||
|
|
||||||
var fi = t.GetField(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);
|
var fi = t.GetField(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);
|
||||||
|
|
||||||
if (fi != null)
|
if (fi != null)
|
||||||
return fi;
|
return fi;
|
||||||
|
|
||||||
if (t.BaseType != null)
|
if (t.BaseType != null)
|
||||||
return GetFieldInfo(t.BaseType, name);
|
return GetFieldInfo(t.BaseType, name);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// From stack overflow
|
// From stack overflow
|
||||||
static Lazy<ISet<Type>> typeSetLazy =
|
static Lazy<ISet<Type>> typeSetLazy =
|
||||||
new Lazy<ISet<Type>>(() => {
|
new Lazy<ISet<Type>>(() => {
|
||||||
var types = AppDomain
|
var types = AppDomain
|
||||||
.CurrentDomain
|
.CurrentDomain
|
||||||
.GetAssemblies()
|
.GetAssemblies()
|
||||||
.SelectMany(a => a.GetTypes()
|
.SelectMany(a => a.GetTypes()
|
||||||
.Where(t => t.IsClass));
|
.Where(t => t.IsClass));
|
||||||
var typesAndBaseTypes = types
|
var typesAndBaseTypes = types
|
||||||
.Select(t => new { Type = t, t.BaseType })
|
.Select(t => new { Type = t, t.BaseType })
|
||||||
.ToList();
|
.ToList();
|
||||||
var typesWithSubclasses = typesAndBaseTypes
|
var typesWithSubclasses = typesAndBaseTypes
|
||||||
.Join(
|
.Join(
|
||||||
typesAndBaseTypes,
|
typesAndBaseTypes,
|
||||||
t => t.Type,
|
t => t.Type,
|
||||||
t => t.BaseType,
|
t => t.BaseType,
|
||||||
(t1, t2) => t2.BaseType);
|
(t1, t2) => t2.BaseType);
|
||||||
var typesHs = new HashSet<Type>(types);
|
var typesHs = new HashSet<Type>(types);
|
||||||
typesHs.ExceptWith(typesWithSubclasses);
|
typesHs.ExceptWith(typesWithSubclasses);
|
||||||
return typesHs;
|
return typesHs;
|
||||||
});
|
});
|
||||||
|
|
||||||
static bool IsLeafType(this Type type)
|
static bool IsLeafType(this Type type)
|
||||||
{
|
{
|
||||||
return typeSetLazy.Value.Contains(type);
|
return typeSetLazy.Value.Contains(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
static HashSet<char> s_badChars = new( new char[] { '<', '>', ' ', ',', '.', '+', '[', ']', '$', ':' } );
|
static HashSet<char> s_badChars = new( new char[] { '<', '>', ' ', ',', '.', '+', '[', ']', '$', ':' } );
|
||||||
|
|
||||||
static public string TypeToIdentifier(string typename)
|
static public string TypeToIdentifier(string typename)
|
||||||
{
|
{
|
||||||
var safeStr = new StringBuilder( typename );
|
var safeStr = new StringBuilder( typename );
|
||||||
|
|
||||||
for( int i = 0; i < safeStr.Length; ++i )
|
for( int i = 0; i < safeStr.Length; ++i )
|
||||||
{
|
{
|
||||||
if( s_badChars.Contains(safeStr[i]) ) safeStr[i] = '_';
|
if( s_badChars.Contains(safeStr[i]) ) safeStr[i] = '_';
|
||||||
}
|
}
|
||||||
|
|
||||||
return safeStr.ToString();
|
return safeStr.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
static public FileSystemWatcher s_watcher;
|
static public FileSystemWatcher s_watcher;
|
||||||
static public Action<Assembly> s_fnAss = (ass) => {
|
static public Action<Assembly> s_fnAss = (ass) => {
|
||||||
log.warn( $"Need to replace s_fnAss with custom function" );
|
log.warn( $"Need to replace s_fnAss with custom function" );
|
||||||
};
|
};
|
||||||
|
|
||||||
public static void WatchPluginDir( string dir, Action<Assembly> fnAss )
|
public static void WatchPluginDir( string dir, Action<Assembly> fnAss )
|
||||||
{
|
{
|
||||||
log.info( $"Watching {dir} for changes" );
|
log.info( $"Watching {dir} for changes" );
|
||||||
|
|
||||||
s_fnAss = fnAss;
|
s_fnAss = fnAss;
|
||||||
|
|
||||||
s_watcher = new FileSystemWatcher( dir );
|
s_watcher = new FileSystemWatcher( dir );
|
||||||
|
|
||||||
s_watcher.Created += OnCreated;
|
s_watcher.Created += OnCreated;
|
||||||
s_watcher.Deleted += OnDeleted;
|
s_watcher.Deleted += OnDeleted;
|
||||||
s_watcher.Renamed += OnRenamed;
|
s_watcher.Renamed += OnRenamed;
|
||||||
|
|
||||||
s_watcher.Filter = "*.cs";
|
s_watcher.Filter = "*.cs";
|
||||||
s_watcher.IncludeSubdirectories = true;
|
s_watcher.IncludeSubdirectories = true;
|
||||||
s_watcher.EnableRaisingEvents = true;
|
s_watcher.EnableRaisingEvents = true;
|
||||||
|
|
||||||
var existingFiles = Directory.GetFiles( dir, "*.cs", SearchOption.AllDirectories );
|
var existingFiles = Directory.GetFiles( dir, "*.cs", SearchOption.AllDirectories );
|
||||||
|
|
||||||
foreach( var filename in existingFiles )
|
foreach( var filename in existingFiles )
|
||||||
{
|
{
|
||||||
Process( filename );
|
Process( filename );
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void OnCreated( object sender, FileSystemEventArgs e )
|
static void OnCreated( object sender, FileSystemEventArgs e )
|
||||||
{
|
{
|
||||||
log.debug( $"{e.Name} got {e.ChangeType}" );
|
log.debug( $"{e.Name} got {e.ChangeType}" );
|
||||||
|
|
||||||
if( e.Name.EndsWith( ".cs" ) )
|
if( e.Name.EndsWith( ".cs" ) )
|
||||||
{
|
{
|
||||||
Process( e.FullPath );
|
Process( e.FullPath );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void OnDeleted( object sender, FileSystemEventArgs e )
|
static void OnDeleted( object sender, FileSystemEventArgs e )
|
||||||
{
|
{
|
||||||
log.debug( $"{e.Name} got {e.ChangeType}" );
|
log.debug( $"{e.Name} got {e.ChangeType}" );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void OnRenamed( object sender, FileSystemEventArgs e )
|
static void OnRenamed( object sender, FileSystemEventArgs e )
|
||||||
{
|
{
|
||||||
log.debug( $"{e.Name} got {e.ChangeType}" );
|
log.debug( $"{e.Name} got {e.ChangeType}" );
|
||||||
|
|
||||||
if( e.Name.EndsWith(".cs") )
|
if( e.Name.EndsWith(".cs") )
|
||||||
{
|
{
|
||||||
while( true )
|
while( true )
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Process( e.FullPath );
|
Process( e.FullPath );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
catch( System.IO.IOException ex )
|
catch( System.IO.IOException ex )
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
catch( Exception ex )
|
catch( Exception ex )
|
||||||
{
|
{
|
||||||
log.error( $"Got ex {ex.GetType().Name} trying to process {e.FullPath}" );
|
log.error( $"Got ex {ex.GetType().Name} trying to process {e.FullPath}" );
|
||||||
log.error( $"-> {ex.Message}" );
|
log.error( $"-> {ex.Message}" );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Thread.Sleep( 100 );
|
Thread.Sleep( 100 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Process( string filename )
|
static void Process( string filename )
|
||||||
{
|
{
|
||||||
CompileFile( filename, ( ass ) => { s_fnAss( ass ); }, ( diags ) => { } );
|
CompileFile( filename, ( ass ) => { s_fnAss( ass ); }, ( diags ) => { } );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void CompileFile( string filename, Action<Assembly> onSuccess, Action<ImmutableArray<Diagnostic>> onFailure, Platform platform = Platform.X86 )
|
public static void CompileFile( string filename, Action<Assembly> onSuccess, Action<ImmutableArray<Diagnostic>> onFailure, Platform platform = Platform.X86 )
|
||||||
{
|
{
|
||||||
var fullpath = Path.GetFullPath( filename );
|
var fullpath = Path.GetFullPath( filename );
|
||||||
|
|
||||||
var stream = File.OpenRead( fullpath );
|
var stream = File.OpenRead( fullpath );
|
||||||
|
|
||||||
var sourceText = SourceText.From( stream );
|
var sourceText = SourceText.From( stream );
|
||||||
|
|
||||||
Compile( sourceText, fullpath, onSuccess, onFailure );
|
Compile( sourceText, fullpath, onSuccess, onFailure );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Compile( string str, string uniquePath, Action<Assembly> onSuccess, Action<ImmutableArray<Diagnostic>> onFailure, Platform platform = Platform.X86 )
|
public static void Compile( string str, string uniquePath, Action<Assembly> onSuccess, Action<ImmutableArray<Diagnostic>> onFailure, Platform platform = Platform.X86 )
|
||||||
{
|
{
|
||||||
var sourceText = SourceText.From( str );
|
var sourceText = SourceText.From( str );
|
||||||
|
|
||||||
Compile( sourceText, uniquePath, onSuccess, onFailure );
|
Compile( sourceText, uniquePath, onSuccess, onFailure );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void Compile( SourceText sourceText, string uniquePath, Action<Assembly> onSuccess, Action<ImmutableArray<Diagnostic>> onFailure, Platform platform = Platform.X86 )
|
public static void Compile( SourceText sourceText, string uniquePath, Action<Assembly> onSuccess, Action<ImmutableArray<Diagnostic>> onFailure, Platform platform = Platform.X86 )
|
||||||
{
|
{
|
||||||
string assemblyName = Path.GetRandomFileName();
|
string assemblyName = Path.GetRandomFileName();
|
||||||
|
|
||||||
var options = new CSharpParseOptions(documentationMode: DocumentationMode.Diagnose, kind: SourceCodeKind.Regular);
|
var options = new CSharpParseOptions(documentationMode: DocumentationMode.Diagnose, kind: SourceCodeKind.Regular);
|
||||||
|
|
||||||
SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText( sourceText, options, uniquePath );
|
SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText( sourceText, options, uniquePath );
|
||||||
|
|
||||||
var memRef = new MemoryRefResolver();
|
var memRef = new MemoryRefResolver();
|
||||||
|
|
||||||
|
|
||||||
using (var ms = new MemoryStream())
|
using (var ms = new MemoryStream())
|
||||||
using (var pdb = new MemoryStream())
|
using (var pdb = new MemoryStream())
|
||||||
{
|
{
|
||||||
var result = CompileAndEmit(assemblyName, new[] { syntaxTree }, ms, pdb, platform);
|
var result = CompileAndEmit(assemblyName, new[] { syntaxTree }, ms, pdb, platform);
|
||||||
|
|
||||||
if (!result.Success)
|
if (!result.Success)
|
||||||
{
|
{
|
||||||
if (onFailure == null)
|
if (onFailure == null)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LogDiags( uniquePath, result.Diagnostics.Length, result.Diagnostics );
|
LogDiags( uniquePath, result.Diagnostics.Length, result.Diagnostics );
|
||||||
|
|
||||||
onFailure( result.Diagnostics );
|
onFailure( result.Diagnostics );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ms.Seek(0, SeekOrigin.Begin);
|
ms.Seek(0, SeekOrigin.Begin);
|
||||||
var assembly = Assembly.Load(ms.ToArray(), pdb.ToArray());
|
var assembly = Assembly.Load(ms.ToArray(), pdb.ToArray());
|
||||||
|
|
||||||
onSuccess( assembly );
|
onSuccess( assembly );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void LogDiags( string uniquePath, int count, IEnumerable<Diagnostic> diags )
|
public static void LogDiags( string uniquePath, int count, IEnumerable<Diagnostic> diags )
|
||||||
{
|
{
|
||||||
log.warn( $"{count} Problems building script with name {uniquePath}" );
|
log.warn( $"{count} Problems building script with name {uniquePath}" );
|
||||||
foreach( var diag in diags )
|
foreach( var diag in diags )
|
||||||
{
|
{
|
||||||
log.debug( $"{diag}" );
|
log.debug( $"{diag}" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static EmitResult CompileAndEmit(string assemblyName, SyntaxTree[] syntaxTrees, MemoryStream ms, MemoryStream pdb, Platform platform)
|
private static EmitResult CompileAndEmit(string assemblyName, SyntaxTree[] syntaxTrees, MemoryStream ms, MemoryStream pdb, Platform platform)
|
||||||
{
|
{
|
||||||
var memRef = new MemoryRefResolver();
|
var memRef = new MemoryRefResolver();
|
||||||
|
|
||||||
// @@@@ TODO :: Config release / debug
|
// @@@@ TODO :: Config release / debug
|
||||||
CSharpCompilation compilation = CSharpCompilation.Create(
|
CSharpCompilation compilation = CSharpCompilation.Create(
|
||||||
assemblyName,
|
assemblyName,
|
||||||
syntaxTrees: syntaxTrees,
|
syntaxTrees: syntaxTrees,
|
||||||
references: RefCache.References,
|
references: RefCache.References,
|
||||||
options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary,
|
options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary,
|
||||||
sourceReferenceResolver: memRef,
|
sourceReferenceResolver: memRef,
|
||||||
optimizationLevel: OptimizationLevel.Release,
|
optimizationLevel: OptimizationLevel.Release,
|
||||||
platform: platform,
|
platform: platform,
|
||||||
specificDiagnosticOptions: new Dictionary<string, ReportDiagnostic>
|
specificDiagnosticOptions: new Dictionary<string, ReportDiagnostic>
|
||||||
{
|
{
|
||||||
{ "CS1701", ReportDiagnostic.Suppress }
|
{ "CS1701", ReportDiagnostic.Suppress }
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return compilation.Emit(ms, pdb);
|
return compilation.Emit(ms, pdb);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class RefCache
|
private static class RefCache
|
||||||
{
|
{
|
||||||
// create the list of references on first use, but if two threads both *start* making the list thats fine since we'll just use whichever wins.
|
// create the list of references on first use, but if two threads both *start* making the list thats fine since we'll just use whichever wins.
|
||||||
private static readonly Lazy<ImmutableArray<MetadataReference>> lazyRef = new Lazy<ImmutableArray<MetadataReference>>(GetReferences, LazyThreadSafetyMode.PublicationOnly);
|
private static readonly Lazy<ImmutableArray<MetadataReference>> lazyRef = new Lazy<ImmutableArray<MetadataReference>>(GetReferences, LazyThreadSafetyMode.PublicationOnly);
|
||||||
|
|
||||||
public static IReadOnlyList<MetadataReference> References => lazyRef.Value;
|
public static IReadOnlyList<MetadataReference> References => lazyRef.Value;
|
||||||
|
|
||||||
private static ImmutableArray<MetadataReference> GetReferences()
|
private static ImmutableArray<MetadataReference> GetReferences()
|
||||||
{
|
{
|
||||||
var builder = ImmutableArray.CreateBuilder<MetadataReference>();
|
var builder = ImmutableArray.CreateBuilder<MetadataReference>();
|
||||||
|
|
||||||
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
|
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
|
||||||
|
|
||||||
foreach( var ass in assemblies )
|
foreach( var ass in assemblies )
|
||||||
{
|
{
|
||||||
if( ass != null && !ass.IsDynamic && ass.Location != null )
|
if( ass != null && !ass.IsDynamic && ass.Location != null )
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
builder.Add( MetadataReference.CreateFromFile( ass.Location ) );
|
builder.Add( MetadataReference.CreateFromFile( ass.Location ) );
|
||||||
}
|
}
|
||||||
catch( Exception ex )
|
catch( Exception ex )
|
||||||
{
|
{
|
||||||
log.warn( $"Got {ex.GetType().Name} sayaing {ex.Message}" );
|
log.warn( $"Got {ex.GetType().Name} sayaing {ex.Message}" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return builder.ToImmutable();
|
return builder.ToImmutable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string PrettyName( Type t )
|
public static string PrettyName( Type t )
|
||||||
{
|
{
|
||||||
if( t.GetGenericArguments().Length == 0 )
|
if( t.GetGenericArguments().Length == 0 )
|
||||||
{
|
{
|
||||||
return t.FullName.Replace( '+', '.' );
|
return t.FullName.Replace( '+', '.' );
|
||||||
}
|
}
|
||||||
var genArgs = t.GetGenericArguments();
|
var genArgs = t.GetGenericArguments();
|
||||||
var typeDef = t.FullName;
|
var typeDef = t.FullName;
|
||||||
|
|
||||||
var indexOfTick = typeDef.IndexOf("`");
|
var indexOfTick = typeDef.IndexOf("`");
|
||||||
|
|
||||||
var unmangledOuterName = typeDef.Substring(0, typeDef.IndexOf('`')).Replace('+', '.');
|
var unmangledOuterName = typeDef.Substring(0, typeDef.IndexOf('`')).Replace('+', '.');
|
||||||
|
|
||||||
var innerName = "";
|
var innerName = "";
|
||||||
|
|
||||||
//Check for inner class
|
//Check for inner class
|
||||||
if( typeDef.ElementAt( indexOfTick + 2 ) != '[' )
|
if( typeDef.ElementAt( indexOfTick + 2 ) != '[' )
|
||||||
{
|
{
|
||||||
var indexOfOpenBracket = typeDef.IndexOf('[', indexOfTick);
|
var indexOfOpenBracket = typeDef.IndexOf('[', indexOfTick);
|
||||||
|
|
||||||
innerName = typeDef.Substring( indexOfTick + 2, indexOfOpenBracket - (indexOfTick + 2) ).Replace( '+', '.' );
|
innerName = typeDef.Substring( indexOfTick + 2, indexOfOpenBracket - (indexOfTick + 2) ).Replace( '+', '.' );
|
||||||
}
|
}
|
||||||
|
|
||||||
return unmangledOuterName + "<" + String.Join( ",", genArgs.Select( PrettyName ) ) + ">" + innerName;
|
return unmangledOuterName + "<" + String.Join( ",", genArgs.Select( PrettyName ) ) + ">" + innerName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static void AddIfFirst<TKey, TValue>(IDictionary<TKey, TValue> dict, TKey key, TValue value)
|
private static void AddIfFirst<TKey, TValue>(IDictionary<TKey, TValue> dict, TKey key, TValue value)
|
||||||
{
|
{
|
||||||
if (!dict.ContainsKey(key))
|
if (!dict.ContainsKey(key))
|
||||||
{
|
{
|
||||||
dict.Add(key, value);
|
dict.Add(key, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,166 +1,166 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Xml.Serialization;
|
using System.Xml.Serialization;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
using System.Runtime.Serialization;
|
using System.Runtime.Serialization;
|
||||||
using System.Runtime.Serialization.Formatters.Binary;
|
using System.Runtime.Serialization.Formatters.Binary;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Security.Permissions;
|
using System.Security.Permissions;
|
||||||
|
|
||||||
namespace lib
|
namespace lib
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class SerializableDictionary<TKey, TVal>: Dictionary<TKey, TVal>, IXmlSerializable, ISerializable
|
public class SerializableDictionary<TKey, TVal>: Dictionary<TKey, TVal>, IXmlSerializable, ISerializable
|
||||||
{
|
{
|
||||||
#region Constants
|
#region Constants
|
||||||
private const string DictionaryNodeName = "Dictionary";
|
private const string DictionaryNodeName = "Dictionary";
|
||||||
private const string ItemNodeName = "Item";
|
private const string ItemNodeName = "Item";
|
||||||
private const string KeyNodeName = "Key";
|
private const string KeyNodeName = "Key";
|
||||||
private const string ValueNodeName = "Value";
|
private const string ValueNodeName = "Value";
|
||||||
#endregion
|
#endregion
|
||||||
#region Constructors
|
#region Constructors
|
||||||
public SerializableDictionary()
|
public SerializableDictionary()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public SerializableDictionary( IDictionary<TKey, TVal> dictionary )
|
public SerializableDictionary( IDictionary<TKey, TVal> dictionary )
|
||||||
: base( dictionary )
|
: base( dictionary )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public SerializableDictionary( IEqualityComparer<TKey> comparer )
|
public SerializableDictionary( IEqualityComparer<TKey> comparer )
|
||||||
: base( comparer )
|
: base( comparer )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public SerializableDictionary( int capacity )
|
public SerializableDictionary( int capacity )
|
||||||
: base( capacity )
|
: base( capacity )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public SerializableDictionary( IDictionary<TKey, TVal> dictionary, IEqualityComparer<TKey> comparer )
|
public SerializableDictionary( IDictionary<TKey, TVal> dictionary, IEqualityComparer<TKey> comparer )
|
||||||
: base( dictionary, comparer )
|
: base( dictionary, comparer )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public SerializableDictionary( int capacity, IEqualityComparer<TKey> comparer )
|
public SerializableDictionary( int capacity, IEqualityComparer<TKey> comparer )
|
||||||
: base( capacity, comparer )
|
: base( capacity, comparer )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
#region ISerializable Members
|
#region ISerializable Members
|
||||||
|
|
||||||
protected SerializableDictionary( SerializationInfo info, StreamingContext context )
|
protected SerializableDictionary( SerializationInfo info, StreamingContext context )
|
||||||
{
|
{
|
||||||
int itemCount = info.GetInt32("ItemCount");
|
int itemCount = info.GetInt32("ItemCount");
|
||||||
for( int i = 0; i < itemCount; i++ )
|
for( int i = 0; i < itemCount; i++ )
|
||||||
{
|
{
|
||||||
KeyValuePair<TKey, TVal> kvp = (KeyValuePair<TKey, TVal>)info.GetValue(String.Format( $"Item{i}" ), typeof(KeyValuePair<TKey, TVal>));
|
KeyValuePair<TKey, TVal> kvp = (KeyValuePair<TKey, TVal>)info.GetValue(String.Format( $"Item{i}" ), typeof(KeyValuePair<TKey, TVal>));
|
||||||
this.Add( kvp.Key, kvp.Value );
|
this.Add( kvp.Key, kvp.Value );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//[SecurityPermission( SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter )]
|
//[SecurityPermission( SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter )]
|
||||||
void ISerializable.GetObjectData( SerializationInfo info, StreamingContext context )
|
void ISerializable.GetObjectData( SerializationInfo info, StreamingContext context )
|
||||||
{
|
{
|
||||||
info.AddValue( "ItemCount", this.Count );
|
info.AddValue( "ItemCount", this.Count );
|
||||||
int itemIdx = 0;
|
int itemIdx = 0;
|
||||||
foreach( KeyValuePair<TKey, TVal> kvp in this )
|
foreach( KeyValuePair<TKey, TVal> kvp in this )
|
||||||
{
|
{
|
||||||
info.AddValue( String.Format( $"Item{itemIdx}" ), kvp, typeof( KeyValuePair<TKey, TVal> ) );
|
info.AddValue( String.Format( $"Item{itemIdx}" ), kvp, typeof( KeyValuePair<TKey, TVal> ) );
|
||||||
itemIdx++;
|
itemIdx++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
#region IXmlSerializable Members
|
#region IXmlSerializable Members
|
||||||
|
|
||||||
void IXmlSerializable.WriteXml( System.Xml.XmlWriter writer )
|
void IXmlSerializable.WriteXml( System.Xml.XmlWriter writer )
|
||||||
{
|
{
|
||||||
//writer.WriteStartElement(DictionaryNodeName);
|
//writer.WriteStartElement(DictionaryNodeName);
|
||||||
foreach( KeyValuePair<TKey, TVal> kvp in this )
|
foreach( KeyValuePair<TKey, TVal> kvp in this )
|
||||||
{
|
{
|
||||||
writer.WriteStartElement( ItemNodeName );
|
writer.WriteStartElement( ItemNodeName );
|
||||||
writer.WriteStartElement( KeyNodeName );
|
writer.WriteStartElement( KeyNodeName );
|
||||||
KeySerializer.Serialize( writer, kvp.Key );
|
KeySerializer.Serialize( writer, kvp.Key );
|
||||||
writer.WriteEndElement();
|
writer.WriteEndElement();
|
||||||
writer.WriteStartElement( ValueNodeName );
|
writer.WriteStartElement( ValueNodeName );
|
||||||
ValueSerializer.Serialize( writer, kvp.Value );
|
ValueSerializer.Serialize( writer, kvp.Value );
|
||||||
writer.WriteEndElement();
|
writer.WriteEndElement();
|
||||||
writer.WriteEndElement();
|
writer.WriteEndElement();
|
||||||
}
|
}
|
||||||
//writer.WriteEndElement();
|
//writer.WriteEndElement();
|
||||||
}
|
}
|
||||||
|
|
||||||
void IXmlSerializable.ReadXml( System.Xml.XmlReader reader )
|
void IXmlSerializable.ReadXml( System.Xml.XmlReader reader )
|
||||||
{
|
{
|
||||||
if( reader.IsEmptyElement )
|
if( reader.IsEmptyElement )
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move past container
|
// Move past container
|
||||||
if( !reader.Read() )
|
if( !reader.Read() )
|
||||||
{
|
{
|
||||||
throw new XmlException( "Error in Deserialization of Dictionary" );
|
throw new XmlException( "Error in Deserialization of Dictionary" );
|
||||||
}
|
}
|
||||||
|
|
||||||
//reader.ReadStartElement(DictionaryNodeName);
|
//reader.ReadStartElement(DictionaryNodeName);
|
||||||
while( reader.NodeType != XmlNodeType.EndElement )
|
while( reader.NodeType != XmlNodeType.EndElement )
|
||||||
{
|
{
|
||||||
reader.ReadStartElement( ItemNodeName );
|
reader.ReadStartElement( ItemNodeName );
|
||||||
reader.ReadStartElement( KeyNodeName );
|
reader.ReadStartElement( KeyNodeName );
|
||||||
TKey key = (TKey)KeySerializer.Deserialize(reader);
|
TKey key = (TKey)KeySerializer.Deserialize(reader);
|
||||||
reader.ReadEndElement();
|
reader.ReadEndElement();
|
||||||
reader.ReadStartElement( ValueNodeName );
|
reader.ReadStartElement( ValueNodeName );
|
||||||
TVal value = (TVal)ValueSerializer.Deserialize(reader);
|
TVal value = (TVal)ValueSerializer.Deserialize(reader);
|
||||||
reader.ReadEndElement();
|
reader.ReadEndElement();
|
||||||
reader.ReadEndElement();
|
reader.ReadEndElement();
|
||||||
this.Add( key, value );
|
this.Add( key, value );
|
||||||
reader.MoveToContent();
|
reader.MoveToContent();
|
||||||
}
|
}
|
||||||
//reader.ReadEndElement();
|
//reader.ReadEndElement();
|
||||||
|
|
||||||
reader.ReadEndElement(); // Read End Element to close Read of containing node
|
reader.ReadEndElement(); // Read End Element to close Read of containing node
|
||||||
}
|
}
|
||||||
|
|
||||||
System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema()
|
System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema()
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
#region Private Properties
|
#region Private Properties
|
||||||
protected XmlSerializer ValueSerializer
|
protected XmlSerializer ValueSerializer
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if( valueSerializer == null )
|
if( valueSerializer == null )
|
||||||
{
|
{
|
||||||
valueSerializer = new XmlSerializer( typeof( TVal ) );
|
valueSerializer = new XmlSerializer( typeof( TVal ) );
|
||||||
}
|
}
|
||||||
return valueSerializer;
|
return valueSerializer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private XmlSerializer KeySerializer
|
private XmlSerializer KeySerializer
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if( keySerializer == null )
|
if( keySerializer == null )
|
||||||
{
|
{
|
||||||
keySerializer = new XmlSerializer( typeof( TKey ) );
|
keySerializer = new XmlSerializer( typeof( TKey ) );
|
||||||
}
|
}
|
||||||
return keySerializer;
|
return keySerializer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
#region Private Members
|
#region Private Members
|
||||||
private XmlSerializer keySerializer = null;
|
private XmlSerializer keySerializer = null;
|
||||||
private XmlSerializer valueSerializer = null;
|
private XmlSerializer valueSerializer = null;
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
2188
ser/XmlFormatter.cs
2188
ser/XmlFormatter.cs
File diff suppressed because it is too large
Load Diff
104
time/Clock.cs
104
time/Clock.cs
@ -1,52 +1,52 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace lib
|
namespace lib
|
||||||
{
|
{
|
||||||
public class Clock
|
public class Clock
|
||||||
{
|
{
|
||||||
public Clock( long timeOffset )
|
public Clock( long timeOffset )
|
||||||
{
|
{
|
||||||
m_timer = new Timer();
|
m_timer = new Timer();
|
||||||
|
|
||||||
m_lastTime = m_timer.Current;
|
m_lastTime = m_timer.Current;
|
||||||
|
|
||||||
m_totalMillis = timeOffset;
|
m_totalMillis = timeOffset;
|
||||||
m_totalSeconds = (double)m_totalMillis / 1000.0;
|
m_totalSeconds = (double)m_totalMillis / 1000.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void tick()
|
public void tick()
|
||||||
{
|
{
|
||||||
long current = m_timer.Current;
|
long current = m_timer.Current;
|
||||||
|
|
||||||
m_dtMillis = (int)( current - m_lastTime );
|
m_dtMillis = (int)( current - m_lastTime );
|
||||||
|
|
||||||
m_dtSeconds = (double)m_dtMillis / 1000.0;
|
m_dtSeconds = (double)m_dtMillis / 1000.0;
|
||||||
|
|
||||||
m_totalMillis += m_dtMillis;
|
m_totalMillis += m_dtMillis;
|
||||||
m_totalSeconds = (double)m_totalMillis / 1000.0;
|
m_totalSeconds = (double)m_totalMillis / 1000.0;
|
||||||
|
|
||||||
m_lastTime = current;
|
m_lastTime = current;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int dtMs { get { return m_dtMillis; } }
|
public int dtMs { get { return m_dtMillis; } }
|
||||||
public double dtSec { get { return m_dtSeconds; } }
|
public double dtSec { get { return m_dtSeconds; } }
|
||||||
|
|
||||||
public long ms { get { return m_totalMillis; } }
|
public long ms { get { return m_totalMillis; } }
|
||||||
public double sec { get { return m_totalSeconds; } }
|
public double sec { get { return m_totalSeconds; } }
|
||||||
|
|
||||||
|
|
||||||
Timer m_timer;
|
Timer m_timer;
|
||||||
|
|
||||||
long m_lastTime = 0;
|
long m_lastTime = 0;
|
||||||
|
|
||||||
int m_dtMillis = 0;
|
int m_dtMillis = 0;
|
||||||
double m_dtSeconds = 0;
|
double m_dtSeconds = 0;
|
||||||
|
|
||||||
long m_totalMillis = 0;
|
long m_totalMillis = 0;
|
||||||
double m_totalSeconds = 0;
|
double m_totalSeconds = 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
754
time/Timer.cs
754
time/Timer.cs
@ -1,377 +1,377 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
namespace lib
|
namespace lib
|
||||||
{
|
{
|
||||||
|
|
||||||
public class MicroStopwatch: System.Diagnostics.Stopwatch
|
public class MicroStopwatch: System.Diagnostics.Stopwatch
|
||||||
{
|
{
|
||||||
readonly double _microSecPerTick
|
readonly double _microSecPerTick
|
||||||
= 1000000D / System.Diagnostics.Stopwatch.Frequency;
|
= 1000000D / System.Diagnostics.Stopwatch.Frequency;
|
||||||
|
|
||||||
public MicroStopwatch()
|
public MicroStopwatch()
|
||||||
{
|
{
|
||||||
if( !System.Diagnostics.Stopwatch.IsHighResolution )
|
if( !System.Diagnostics.Stopwatch.IsHighResolution )
|
||||||
{
|
{
|
||||||
throw new Exception( "On this system the high-resolution " +
|
throw new Exception( "On this system the high-resolution " +
|
||||||
"performance counter is not available" );
|
"performance counter is not available" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public long ElapsedMicroseconds
|
public long ElapsedMicroseconds
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return (long)( ElapsedTicks * _microSecPerTick );
|
return (long)( ElapsedTicks * _microSecPerTick );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// MicroTimer class
|
/// MicroTimer class
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class MicroTimer
|
public class MicroTimer
|
||||||
{
|
{
|
||||||
public delegate void MicroTimerElapsedEventHandler(
|
public delegate void MicroTimerElapsedEventHandler(
|
||||||
object sender,
|
object sender,
|
||||||
MicroTimerEventArgs timerEventArgs );
|
MicroTimerEventArgs timerEventArgs );
|
||||||
public event MicroTimerElapsedEventHandler MicroTimerElapsed;
|
public event MicroTimerElapsedEventHandler MicroTimerElapsed;
|
||||||
|
|
||||||
System.Threading.Thread _threadTimer = null;
|
System.Threading.Thread _threadTimer = null;
|
||||||
long _ignoreEventIfLateBy = long.MaxValue;
|
long _ignoreEventIfLateBy = long.MaxValue;
|
||||||
long _timerIntervalInMicroSec = 0;
|
long _timerIntervalInMicroSec = 0;
|
||||||
bool _stopTimer = true;
|
bool _stopTimer = true;
|
||||||
|
|
||||||
public MicroTimer()
|
public MicroTimer()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public MicroTimer( long timerIntervalInMicroseconds )
|
public MicroTimer( long timerIntervalInMicroseconds )
|
||||||
{
|
{
|
||||||
Interval = timerIntervalInMicroseconds;
|
Interval = timerIntervalInMicroseconds;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long Interval
|
public long Interval
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return System.Threading.Interlocked.Read(
|
return System.Threading.Interlocked.Read(
|
||||||
ref _timerIntervalInMicroSec );
|
ref _timerIntervalInMicroSec );
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
System.Threading.Interlocked.Exchange(
|
System.Threading.Interlocked.Exchange(
|
||||||
ref _timerIntervalInMicroSec, value );
|
ref _timerIntervalInMicroSec, value );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public long IgnoreEventIfLateBy
|
public long IgnoreEventIfLateBy
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return System.Threading.Interlocked.Read(
|
return System.Threading.Interlocked.Read(
|
||||||
ref _ignoreEventIfLateBy );
|
ref _ignoreEventIfLateBy );
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
System.Threading.Interlocked.Exchange(
|
System.Threading.Interlocked.Exchange(
|
||||||
ref _ignoreEventIfLateBy, value <= 0 ? long.MaxValue : value );
|
ref _ignoreEventIfLateBy, value <= 0 ? long.MaxValue : value );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Enabled
|
public bool Enabled
|
||||||
{
|
{
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if( value )
|
if( value )
|
||||||
{
|
{
|
||||||
Start();
|
Start();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Stop();
|
Stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return ( _threadTimer != null && _threadTimer.IsAlive );
|
return ( _threadTimer != null && _threadTimer.IsAlive );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Start()
|
public void Start()
|
||||||
{
|
{
|
||||||
if( Enabled || Interval <= 0 )
|
if( Enabled || Interval <= 0 )
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_stopTimer = false;
|
_stopTimer = false;
|
||||||
|
|
||||||
System.Threading.ThreadStart threadStart = delegate()
|
System.Threading.ThreadStart threadStart = delegate()
|
||||||
{
|
{
|
||||||
NotificationTimer(ref _timerIntervalInMicroSec,
|
NotificationTimer(ref _timerIntervalInMicroSec,
|
||||||
ref _ignoreEventIfLateBy,
|
ref _ignoreEventIfLateBy,
|
||||||
ref _stopTimer);
|
ref _stopTimer);
|
||||||
};
|
};
|
||||||
|
|
||||||
_threadTimer = new System.Threading.Thread( threadStart );
|
_threadTimer = new System.Threading.Thread( threadStart );
|
||||||
_threadTimer.Priority = System.Threading.ThreadPriority.Highest;
|
_threadTimer.Priority = System.Threading.ThreadPriority.Highest;
|
||||||
_threadTimer.Start();
|
_threadTimer.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Stop()
|
public void Stop()
|
||||||
{
|
{
|
||||||
_stopTimer = true;
|
_stopTimer = true;
|
||||||
|
|
||||||
if( _threadTimer != null && _threadTimer.ManagedThreadId ==
|
if( _threadTimer != null && _threadTimer.ManagedThreadId ==
|
||||||
System.Threading.Thread.CurrentThread.ManagedThreadId )
|
System.Threading.Thread.CurrentThread.ManagedThreadId )
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
while( Enabled )
|
while( Enabled )
|
||||||
{
|
{
|
||||||
System.Threading.Thread.SpinWait( 10 );
|
System.Threading.Thread.SpinWait( 10 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NotificationTimer( ref long timerIntervalInMicroSec,
|
void NotificationTimer( ref long timerIntervalInMicroSec,
|
||||||
ref long ignoreEventIfLateBy,
|
ref long ignoreEventIfLateBy,
|
||||||
ref bool stopTimer )
|
ref bool stopTimer )
|
||||||
{
|
{
|
||||||
int timerCount = 0;
|
int timerCount = 0;
|
||||||
long nextNotification = 0;
|
long nextNotification = 0;
|
||||||
|
|
||||||
MicroStopwatch microStopwatch = new MicroStopwatch();
|
MicroStopwatch microStopwatch = new MicroStopwatch();
|
||||||
microStopwatch.Start();
|
microStopwatch.Start();
|
||||||
|
|
||||||
while( !stopTimer )
|
while( !stopTimer )
|
||||||
{
|
{
|
||||||
long callbackFunctionExecutionTime =
|
long callbackFunctionExecutionTime =
|
||||||
microStopwatch.ElapsedMicroseconds - nextNotification;
|
microStopwatch.ElapsedMicroseconds - nextNotification;
|
||||||
|
|
||||||
long timerIntervalInMicroSecCurrent =
|
long timerIntervalInMicroSecCurrent =
|
||||||
System.Threading.Interlocked.Read(ref timerIntervalInMicroSec);
|
System.Threading.Interlocked.Read(ref timerIntervalInMicroSec);
|
||||||
long ignoreEventIfLateByCurrent =
|
long ignoreEventIfLateByCurrent =
|
||||||
System.Threading.Interlocked.Read(ref ignoreEventIfLateBy);
|
System.Threading.Interlocked.Read(ref ignoreEventIfLateBy);
|
||||||
|
|
||||||
nextNotification += timerIntervalInMicroSecCurrent;
|
nextNotification += timerIntervalInMicroSecCurrent;
|
||||||
timerCount++;
|
timerCount++;
|
||||||
long elapsedMicroseconds = 0;
|
long elapsedMicroseconds = 0;
|
||||||
|
|
||||||
while( ( elapsedMicroseconds = microStopwatch.ElapsedMicroseconds )
|
while( ( elapsedMicroseconds = microStopwatch.ElapsedMicroseconds )
|
||||||
< nextNotification )
|
< nextNotification )
|
||||||
{
|
{
|
||||||
System.Threading.Thread.SpinWait( 10 );
|
System.Threading.Thread.SpinWait( 10 );
|
||||||
}
|
}
|
||||||
|
|
||||||
long timerLateBy = elapsedMicroseconds - nextNotification;
|
long timerLateBy = elapsedMicroseconds - nextNotification;
|
||||||
|
|
||||||
if( timerLateBy >= ignoreEventIfLateByCurrent )
|
if( timerLateBy >= ignoreEventIfLateByCurrent )
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
MicroTimerEventArgs microTimerEventArgs =
|
MicroTimerEventArgs microTimerEventArgs =
|
||||||
new MicroTimerEventArgs(timerCount,
|
new MicroTimerEventArgs(timerCount,
|
||||||
elapsedMicroseconds,
|
elapsedMicroseconds,
|
||||||
timerLateBy,
|
timerLateBy,
|
||||||
callbackFunctionExecutionTime);
|
callbackFunctionExecutionTime);
|
||||||
MicroTimerElapsed( this, microTimerEventArgs );
|
MicroTimerElapsed( this, microTimerEventArgs );
|
||||||
}
|
}
|
||||||
|
|
||||||
microStopwatch.Stop();
|
microStopwatch.Stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// MicroTimer Event Argument class
|
/// MicroTimer Event Argument class
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class MicroTimerEventArgs: EventArgs
|
public class MicroTimerEventArgs: EventArgs
|
||||||
{
|
{
|
||||||
// Simple counter, number times timed event (callback function) executed
|
// Simple counter, number times timed event (callback function) executed
|
||||||
public int TimerCount { get; private set; }
|
public int TimerCount { get; private set; }
|
||||||
|
|
||||||
// Time when timed event was called since timer started
|
// Time when timed event was called since timer started
|
||||||
public long ElapsedMicroseconds { get; private set; }
|
public long ElapsedMicroseconds { get; private set; }
|
||||||
|
|
||||||
// How late the timer was compared to when it should have been called
|
// How late the timer was compared to when it should have been called
|
||||||
public long TimerLateBy { get; private set; }
|
public long TimerLateBy { get; private set; }
|
||||||
|
|
||||||
// Time it took to execute previous call to callback function (OnTimedEvent)
|
// Time it took to execute previous call to callback function (OnTimedEvent)
|
||||||
public long CallbackFunctionExecutionTime { get; private set; }
|
public long CallbackFunctionExecutionTime { get; private set; }
|
||||||
|
|
||||||
public MicroTimerEventArgs( int timerCount,
|
public MicroTimerEventArgs( int timerCount,
|
||||||
long elapsedMicroseconds,
|
long elapsedMicroseconds,
|
||||||
long timerLateBy,
|
long timerLateBy,
|
||||||
long callbackFunctionExecutionTime )
|
long callbackFunctionExecutionTime )
|
||||||
{
|
{
|
||||||
TimerCount = timerCount;
|
TimerCount = timerCount;
|
||||||
ElapsedMicroseconds = elapsedMicroseconds;
|
ElapsedMicroseconds = elapsedMicroseconds;
|
||||||
TimerLateBy = timerLateBy;
|
TimerLateBy = timerLateBy;
|
||||||
CallbackFunctionExecutionTime = callbackFunctionExecutionTime;
|
CallbackFunctionExecutionTime = callbackFunctionExecutionTime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public class Timer
|
public class Timer
|
||||||
{
|
{
|
||||||
MicroStopwatch m_watch;
|
MicroStopwatch m_watch;
|
||||||
private long startTime;
|
private long startTime;
|
||||||
private long stopTime;
|
private long stopTime;
|
||||||
private long freq;
|
private long freq;
|
||||||
private long freq_millis;
|
private long freq_millis;
|
||||||
|
|
||||||
public Timer()
|
public Timer()
|
||||||
{
|
{
|
||||||
m_watch = new MicroStopwatch();
|
m_watch = new MicroStopwatch();
|
||||||
//startTime = m_watch.ElapsedMicroseconds;
|
//startTime = m_watch.ElapsedMicroseconds;
|
||||||
//stopTime = m_watch.ElapsedMicroseconds;
|
//stopTime = m_watch.ElapsedMicroseconds;
|
||||||
freq = 1000 * 1000;
|
freq = 1000 * 1000;
|
||||||
freq_millis = freq / 1000;
|
freq_millis = freq / 1000;
|
||||||
|
|
||||||
Start();
|
Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start the timer
|
// Start the timer
|
||||||
|
|
||||||
public Timer Start()
|
public Timer Start()
|
||||||
{
|
{
|
||||||
m_watch.Start();
|
m_watch.Start();
|
||||||
startTime = m_watch.ElapsedMicroseconds;
|
startTime = m_watch.ElapsedMicroseconds;
|
||||||
stopTime = m_watch.ElapsedMicroseconds;
|
stopTime = m_watch.ElapsedMicroseconds;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop the timer
|
// Stop the timer
|
||||||
|
|
||||||
public Timer Stop()
|
public Timer Stop()
|
||||||
{
|
{
|
||||||
m_watch.Stop();
|
m_watch.Stop();
|
||||||
stopTime = m_watch.ElapsedMicroseconds;
|
stopTime = m_watch.ElapsedMicroseconds;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public double Seconds
|
public double Seconds
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
long current = m_watch.ElapsedMicroseconds;
|
long current = m_watch.ElapsedMicroseconds;
|
||||||
return (double)( current - startTime ) / freq;
|
return (double)( current - startTime ) / freq;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public long Current
|
public long Current
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
long current = m_watch.ElapsedMicroseconds;
|
long current = m_watch.ElapsedMicroseconds;
|
||||||
return ( current - startTime ) / freq_millis;
|
return ( current - startTime ) / freq_millis;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public double Duration
|
public double Duration
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return (double)( stopTime - startTime ) / (double)freq;
|
return (double)( stopTime - startTime ) / (double)freq;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public long DurationMS
|
public long DurationMS
|
||||||
{
|
{
|
||||||
get { return ( stopTime - startTime ) / freq_millis; }
|
get { return ( stopTime - startTime ) / freq_millis; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public class TimerWin
|
public class TimerWin
|
||||||
{
|
{
|
||||||
[DllImport( "Kernel32.dll" )]
|
[DllImport( "Kernel32.dll" )]
|
||||||
private static extern bool QueryPerformanceCounter(
|
private static extern bool QueryPerformanceCounter(
|
||||||
out long lpPerformanceCount );
|
out long lpPerformanceCount );
|
||||||
|
|
||||||
[DllImport( "Kernel32.dll" )]
|
[DllImport( "Kernel32.dll" )]
|
||||||
private static extern bool QueryPerformanceFrequency(
|
private static extern bool QueryPerformanceFrequency(
|
||||||
out long lpFrequency );
|
out long lpFrequency );
|
||||||
|
|
||||||
private long startTime;
|
private long startTime;
|
||||||
private long stopTime;
|
private long stopTime;
|
||||||
private long freq;
|
private long freq;
|
||||||
private long freq_millis;
|
private long freq_millis;
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
|
|
||||||
public TimerWin()
|
public TimerWin()
|
||||||
{
|
{
|
||||||
startTime = 0;
|
startTime = 0;
|
||||||
stopTime = 0;
|
stopTime = 0;
|
||||||
|
|
||||||
if( QueryPerformanceFrequency( out freq ) == false )
|
if( QueryPerformanceFrequency( out freq ) == false )
|
||||||
{
|
{
|
||||||
// high-performance counter not supported
|
// high-performance counter not supported
|
||||||
throw new Win32Exception();
|
throw new Win32Exception();
|
||||||
}
|
}
|
||||||
|
|
||||||
freq_millis = freq / 1000;
|
freq_millis = freq / 1000;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start the timer
|
// Start the timer
|
||||||
|
|
||||||
public void Start()
|
public void Start()
|
||||||
{
|
{
|
||||||
// lets do the waiting threads there work
|
// lets do the waiting threads there work
|
||||||
|
|
||||||
//Thread.Sleep(0);
|
//Thread.Sleep(0);
|
||||||
|
|
||||||
QueryPerformanceCounter( out startTime );
|
QueryPerformanceCounter( out startTime );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop the timer
|
// Stop the timer
|
||||||
|
|
||||||
public void Stop()
|
public void Stop()
|
||||||
{
|
{
|
||||||
QueryPerformanceCounter( out stopTime );
|
QueryPerformanceCounter( out stopTime );
|
||||||
}
|
}
|
||||||
|
|
||||||
public double Seconds
|
public double Seconds
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
long current;
|
long current;
|
||||||
|
|
||||||
QueryPerformanceCounter( out current );
|
QueryPerformanceCounter( out current );
|
||||||
|
|
||||||
return (double)( current - startTime ) / freq;
|
return (double)( current - startTime ) / freq;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public long Current
|
public long Current
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
long current;
|
long current;
|
||||||
|
|
||||||
QueryPerformanceCounter( out current );
|
QueryPerformanceCounter( out current );
|
||||||
|
|
||||||
return ( current - startTime ) / freq_millis;
|
return ( current - startTime ) / freq_millis;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public double Duration
|
public double Duration
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return (double)( stopTime - startTime ) / (double)freq;
|
return (double)( stopTime - startTime ) / (double)freq;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public long DurationMS
|
public long DurationMS
|
||||||
{
|
{
|
||||||
get { return ( stopTime - startTime ) / freq_millis; }
|
get { return ( stopTime - startTime ) / freq_millis; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user