Added an interface for the scheduler service (this might be once candidate for replacement by different implementations); added a new helper class for the StringBuilder that allows garbage-free appending of integers and floats; added unit tests for most of the code
git-svn-id: file:///srv/devel/repo-conversion/nusu@188 d2e56fa2-650e-0410-a79f-9358c0239efd
This commit is contained in:
		
							parent
							
								
									66f0ae9b34
								
							
						
					
					
						commit
						237fb57fc8
					
				
					 8 changed files with 468 additions and 3 deletions
				
			
		| 
						 | 
					@ -145,6 +145,7 @@
 | 
				
			||||||
    <Compile Include="Source\Scheduling\GenericTimeSource.Test.cs">
 | 
					    <Compile Include="Source\Scheduling\GenericTimeSource.Test.cs">
 | 
				
			||||||
      <DependentUpon>GenericTimeSource.cs</DependentUpon>
 | 
					      <DependentUpon>GenericTimeSource.cs</DependentUpon>
 | 
				
			||||||
    </Compile>
 | 
					    </Compile>
 | 
				
			||||||
 | 
					    <Compile Include="Source\Scheduling\ISchedulerService.cs" />
 | 
				
			||||||
    <Compile Include="Source\Scheduling\ITimeSource.cs" />
 | 
					    <Compile Include="Source\Scheduling\ITimeSource.cs" />
 | 
				
			||||||
    <Compile Include="Source\Scheduling\Scheduler.cs" />
 | 
					    <Compile Include="Source\Scheduling\Scheduler.cs" />
 | 
				
			||||||
    <Compile Include="Source\Scheduling\GenericTimeSource.cs" />
 | 
					    <Compile Include="Source\Scheduling\GenericTimeSource.cs" />
 | 
				
			||||||
| 
						 | 
					@ -305,6 +306,10 @@
 | 
				
			||||||
    <Compile Include="Source\IO\ChainStream.Test.cs">
 | 
					    <Compile Include="Source\IO\ChainStream.Test.cs">
 | 
				
			||||||
      <DependentUpon>ChainStream.cs</DependentUpon>
 | 
					      <DependentUpon>ChainStream.cs</DependentUpon>
 | 
				
			||||||
    </Compile>
 | 
					    </Compile>
 | 
				
			||||||
 | 
					    <Compile Include="Source\StringBuilderHelper.cs" />
 | 
				
			||||||
 | 
					    <Compile Include="Source\StringBuilderHelper.Test.cs">
 | 
				
			||||||
 | 
					      <DependentUpon>StringBuilderHelper.cs</DependentUpon>
 | 
				
			||||||
 | 
					    </Compile>
 | 
				
			||||||
    <Compile Include="Source\StringHelper.cs" />
 | 
					    <Compile Include="Source\StringHelper.cs" />
 | 
				
			||||||
    <Compile Include="Source\StringHelper.Test.cs">
 | 
					    <Compile Include="Source\StringHelper.Test.cs">
 | 
				
			||||||
      <DependentUpon>StringHelper.cs</DependentUpon>
 | 
					      <DependentUpon>StringHelper.cs</DependentUpon>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -131,6 +131,7 @@
 | 
				
			||||||
    <Compile Include="Source\Scheduling\GenericTimeSource.Test.cs">
 | 
					    <Compile Include="Source\Scheduling\GenericTimeSource.Test.cs">
 | 
				
			||||||
      <DependentUpon>GenericTimeSource.cs</DependentUpon>
 | 
					      <DependentUpon>GenericTimeSource.cs</DependentUpon>
 | 
				
			||||||
    </Compile>
 | 
					    </Compile>
 | 
				
			||||||
 | 
					    <Compile Include="Source\Scheduling\ISchedulerService.cs" />
 | 
				
			||||||
    <Compile Include="Source\Scheduling\ITimeSource.cs" />
 | 
					    <Compile Include="Source\Scheduling\ITimeSource.cs" />
 | 
				
			||||||
    <Compile Include="Source\Scheduling\Scheduler.cs" />
 | 
					    <Compile Include="Source\Scheduling\Scheduler.cs" />
 | 
				
			||||||
    <Compile Include="Source\Scheduling\GenericTimeSource.cs" />
 | 
					    <Compile Include="Source\Scheduling\GenericTimeSource.cs" />
 | 
				
			||||||
| 
						 | 
					@ -291,6 +292,10 @@
 | 
				
			||||||
    <Compile Include="Source\IO\ChainStream.Test.cs">
 | 
					    <Compile Include="Source\IO\ChainStream.Test.cs">
 | 
				
			||||||
      <DependentUpon>ChainStream.cs</DependentUpon>
 | 
					      <DependentUpon>ChainStream.cs</DependentUpon>
 | 
				
			||||||
    </Compile>
 | 
					    </Compile>
 | 
				
			||||||
 | 
					    <Compile Include="Source\StringBuilderHelper.cs" />
 | 
				
			||||||
 | 
					    <Compile Include="Source\StringBuilderHelper.Test.cs">
 | 
				
			||||||
 | 
					      <DependentUpon>StringBuilderHelper.cs</DependentUpon>
 | 
				
			||||||
 | 
					    </Compile>
 | 
				
			||||||
    <Compile Include="Source\StringHelper.cs" />
 | 
					    <Compile Include="Source\StringHelper.cs" />
 | 
				
			||||||
    <Compile Include="Source\StringHelper.Test.cs">
 | 
					    <Compile Include="Source\StringHelper.Test.cs">
 | 
				
			||||||
      <DependentUpon>StringHelper.cs</DependentUpon>
 | 
					      <DependentUpon>StringHelper.cs</DependentUpon>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,11 +18,11 @@ License along with this library
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
#endregion
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if UNITTEST
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using System;
 | 
					using System;
 | 
				
			||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if UNITTEST
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
using NUnit.Framework;
 | 
					using NUnit.Framework;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace Nuclex.Support {
 | 
					namespace Nuclex.Support {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										101
									
								
								Source/Scheduling/ISchedulerService.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								Source/Scheduling/ISchedulerService.cs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,101 @@
 | 
				
			||||||
 | 
					#region CPL License
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					Nuclex Framework
 | 
				
			||||||
 | 
					Copyright (C) 2002-2009 Nuclex Development Labs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This library is free software; you can redistribute it and/or
 | 
				
			||||||
 | 
					modify it under the terms of the IBM Common Public License as
 | 
				
			||||||
 | 
					published by the IBM Corporation; either version 1.0 of the
 | 
				
			||||||
 | 
					License, or (at your option) any later version.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This library is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 | 
				
			||||||
 | 
					IBM Common Public License for more details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					You should have received a copy of the IBM Common Public
 | 
				
			||||||
 | 
					License along with this library
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Threading;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nuclex.Support.Scheduling {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /// <summary>Service that allows the scheduled invocation of tasks</summary>
 | 
				
			||||||
 | 
					  public interface ISchedulerService {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>Schedules a notification at the specified absolute time</summary>
 | 
				
			||||||
 | 
					    /// <param name="notificationTime">
 | 
				
			||||||
 | 
					    ///   Absolute time at which the notification will occur
 | 
				
			||||||
 | 
					    /// </param>
 | 
				
			||||||
 | 
					    /// <param name="callback">
 | 
				
			||||||
 | 
					    ///   Callback that will be invoked when the notification is due
 | 
				
			||||||
 | 
					    /// </param>
 | 
				
			||||||
 | 
					    /// <returns>A handle that can be used to cancel the notification</returns>
 | 
				
			||||||
 | 
					    /// <remarks>
 | 
				
			||||||
 | 
					    ///   The notification is scheduled for the indicated absolute time. If the system
 | 
				
			||||||
 | 
					    ///   enters/leaves daylight saving time or the date/time is changed (for example
 | 
				
			||||||
 | 
					    ///   when the system synchronizes with an NTP server), this will affect
 | 
				
			||||||
 | 
					    ///   the notification. So if you need to be notified after a fixed time, use
 | 
				
			||||||
 | 
					    ///   the NotifyIn() method instead.
 | 
				
			||||||
 | 
					    /// </remarks>
 | 
				
			||||||
 | 
					    object NotifyAt(DateTime notificationTime, WaitCallback callback);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    ///   Schedules a recurring notification after the specified amount of milliseconds
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <param name="delayMilliseconds">
 | 
				
			||||||
 | 
					    ///   Milliseconds after which the first notification will occur
 | 
				
			||||||
 | 
					    /// </param>
 | 
				
			||||||
 | 
					    /// <param name="intervalMilliseconds">
 | 
				
			||||||
 | 
					    ///   Interval in milliseconds at which the notification will be repeated
 | 
				
			||||||
 | 
					    /// </param>
 | 
				
			||||||
 | 
					    /// <param name="callback">
 | 
				
			||||||
 | 
					    ///   Callback that will be invoked when the notification is due
 | 
				
			||||||
 | 
					    /// </param>
 | 
				
			||||||
 | 
					    /// <returns>A handle that can be used to cancel the notification</returns>
 | 
				
			||||||
 | 
					    object NotifyEach(int delayMilliseconds, int intervalMilliseconds, WaitCallback callback);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    ///   Schedules a recurring notification after the specified time span
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <param name="delay">Delay after which the first notification will occur</param>
 | 
				
			||||||
 | 
					    /// <param name="interval">Interval at which the notification will be repeated</param>
 | 
				
			||||||
 | 
					    /// <param name="callback">
 | 
				
			||||||
 | 
					    ///   Callback that will be invoked when the notification is due
 | 
				
			||||||
 | 
					    /// </param>
 | 
				
			||||||
 | 
					    /// <returns>A handle that can be used to cancel the notification</returns>
 | 
				
			||||||
 | 
					    object NotifyEach(TimeSpan delay, TimeSpan interval, WaitCallback callback);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    ///   Schedules a notification after the specified amount of milliseconds
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <param name="delayMilliseconds">
 | 
				
			||||||
 | 
					    ///   Number of milliseconds after which the notification will occur
 | 
				
			||||||
 | 
					    /// </param>
 | 
				
			||||||
 | 
					    /// <param name="callback">
 | 
				
			||||||
 | 
					    ///   Callback that will be invoked when the notification is due
 | 
				
			||||||
 | 
					    /// </param>
 | 
				
			||||||
 | 
					    /// <returns>A handle that can be used to cancel the notification</returns>
 | 
				
			||||||
 | 
					    object NotifyIn(int delayMilliseconds, WaitCallback callback);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>Schedules a notification after the specified time span</summary>
 | 
				
			||||||
 | 
					    /// <param name="delay">Delay after which the notification will occur</param>
 | 
				
			||||||
 | 
					    /// <param name="callback">
 | 
				
			||||||
 | 
					    ///   Callback that will be invoked when the notification is due
 | 
				
			||||||
 | 
					    /// </param>
 | 
				
			||||||
 | 
					    /// <returns>A handle that can be used to cancel the notification</returns>
 | 
				
			||||||
 | 
					    object NotifyIn(TimeSpan delay, WaitCallback callback);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>Cancels a scheduled notification</summary>
 | 
				
			||||||
 | 
					    /// <param name="notificationHandle">
 | 
				
			||||||
 | 
					    ///   Handle of the notification that will be cancelled
 | 
				
			||||||
 | 
					    /// </param>
 | 
				
			||||||
 | 
					    void Cancel(object notificationHandle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace Nuclex.Support.Scheduling
 | 
				
			||||||
| 
						 | 
					@ -28,7 +28,7 @@ using Nuclex.Support.Collections;
 | 
				
			||||||
namespace Nuclex.Support.Scheduling {
 | 
					namespace Nuclex.Support.Scheduling {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /// <summary>Schedules actions for execution at a future point in time</summary>
 | 
					  /// <summary>Schedules actions for execution at a future point in time</summary>
 | 
				
			||||||
  public class Scheduler : IDisposable {
 | 
					  public class Scheduler : ISchedulerService, IDisposable {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// <summary>One tick is 100 ns, meaning 10000 ticks equal 1 ms</summary>
 | 
					    /// <summary>One tick is 100 ns, meaning 10000 ticks equal 1 ms</summary>
 | 
				
			||||||
    private const long TicksPerMillisecond = 10000;
 | 
					    private const long TicksPerMillisecond = 10000;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										151
									
								
								Source/StringBuilderHelper.Test.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										151
									
								
								Source/StringBuilderHelper.Test.cs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,151 @@
 | 
				
			||||||
 | 
					#region CPL License
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					Nuclex Framework
 | 
				
			||||||
 | 
					Copyright (C) 2002-2009 Nuclex Development Labs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This library is free software; you can redistribute it and/or
 | 
				
			||||||
 | 
					modify it under the terms of the IBM Common Public License as
 | 
				
			||||||
 | 
					published by the IBM Corporation; either version 1.0 of the
 | 
				
			||||||
 | 
					License, or (at your option) any later version.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This library is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 | 
				
			||||||
 | 
					IBM Common Public License for more details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					You should have received a copy of the IBM Common Public
 | 
				
			||||||
 | 
					License along with this library
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if UNITTEST
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using NUnit.Framework;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nuclex.Support {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /// <summary>
 | 
				
			||||||
 | 
					  ///   Unit test for the helper class to .NET's string builder
 | 
				
			||||||
 | 
					  /// </summary>
 | 
				
			||||||
 | 
					  [TestFixture]
 | 
				
			||||||
 | 
					  public class StringBuilderHelperTest {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    ///   Verifies that bytes are correctly appended to a string builder
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    [Test]
 | 
				
			||||||
 | 
					    public void TestAppendByte() {
 | 
				
			||||||
 | 
					      StringBuilder builder = new StringBuilder();
 | 
				
			||||||
 | 
					      StringBuilderHelper.Append(builder, (byte)255);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      Assert.AreEqual("255", builder.ToString());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    ///   Verifies that a byte with value 0 is correctly appended to a string builder
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    [Test]
 | 
				
			||||||
 | 
					    public void TestAppendNullByte() {
 | 
				
			||||||
 | 
					      StringBuilder builder = new StringBuilder();
 | 
				
			||||||
 | 
					      StringBuilderHelper.Append(builder, (byte)0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      Assert.AreEqual("0", builder.ToString());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    ///   Verifies that a positive integer is correctly appended to a string builder
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    [Test]
 | 
				
			||||||
 | 
					    public void TestAppendPositiveInteger() {
 | 
				
			||||||
 | 
					      StringBuilder builder = new StringBuilder();
 | 
				
			||||||
 | 
					      StringBuilderHelper.Append(builder, 12345);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      Assert.AreEqual("12345", builder.ToString());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    ///   Verifies that an integer with value 0 is correctly appended to a string builder
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    [Test]
 | 
				
			||||||
 | 
					    public void TestAppendNullInteger() {
 | 
				
			||||||
 | 
					      StringBuilder builder = new StringBuilder();
 | 
				
			||||||
 | 
					      StringBuilderHelper.Append(builder, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      Assert.AreEqual("0", builder.ToString());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    ///   Verifies that a negative integer is correctly appended to a string builder
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    [Test]
 | 
				
			||||||
 | 
					    public void TestAppendNegativeInteger() {
 | 
				
			||||||
 | 
					      StringBuilder builder = new StringBuilder();
 | 
				
			||||||
 | 
					      StringBuilderHelper.Append(builder, -12345);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      Assert.AreEqual("-12345", builder.ToString());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    ///   Verifies that negative floating point values are correctly converted
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    [Test]
 | 
				
			||||||
 | 
					    public void TestAppendNegativeFloat() {
 | 
				
			||||||
 | 
					      StringBuilder builder = new StringBuilder();
 | 
				
			||||||
 | 
					      StringBuilderHelper.Append(builder, -32.015625f);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      Assert.AreEqual("-32.015625", builder.ToString());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    ///   Verifies that positive floating point values are correctly converted
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    [Test]
 | 
				
			||||||
 | 
					    public void TestAppendPositiveFloat() {
 | 
				
			||||||
 | 
					      StringBuilder builder = new StringBuilder();
 | 
				
			||||||
 | 
					      StringBuilderHelper.Append(builder, 10.0625f);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      Assert.AreEqual("10.0625", builder.ToString());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    ///   Verifies that very small floating point values are correctly converted
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    [Test]
 | 
				
			||||||
 | 
					    public void TestAppendSmallFloat() {
 | 
				
			||||||
 | 
					      StringBuilder builder = new StringBuilder();
 | 
				
			||||||
 | 
					      StringBuilderHelper.Append(builder, 0.00390625f);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      Assert.AreEqual("0.00390625", builder.ToString());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    ///   Verifies that very large floating point values are correctly converted
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    [Test]
 | 
				
			||||||
 | 
					    public void TestAppendHugeFloat() {
 | 
				
			||||||
 | 
					      StringBuilder builder = new StringBuilder();
 | 
				
			||||||
 | 
					      StringBuilderHelper.Append(builder, 1000000000.0f);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      Assert.AreEqual("1000000000.0", builder.ToString());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    ///   Verifies that the contents of a string builder can be cleared
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    [Test]
 | 
				
			||||||
 | 
					    public void TestClear() {
 | 
				
			||||||
 | 
					      StringBuilder builder = new StringBuilder("Hello World");
 | 
				
			||||||
 | 
					      StringBuilderHelper.Clear(builder);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      Assert.AreEqual(string.Empty, builder.ToString());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace Nuclex.Support
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // UNITTEST
 | 
				
			||||||
							
								
								
									
										202
									
								
								Source/StringBuilderHelper.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										202
									
								
								Source/StringBuilderHelper.cs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,202 @@
 | 
				
			||||||
 | 
					#region CPL License
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					Nuclex Framework
 | 
				
			||||||
 | 
					Copyright (C) 2002-2009 Nuclex Development Labs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This library is free software; you can redistribute it and/or
 | 
				
			||||||
 | 
					modify it under the terms of the IBM Common Public License as
 | 
				
			||||||
 | 
					published by the IBM Corporation; either version 1.0 of the
 | 
				
			||||||
 | 
					License, or (at your option) any later version.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This library is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 | 
				
			||||||
 | 
					IBM Common Public License for more details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					You should have received a copy of the IBM Common Public
 | 
				
			||||||
 | 
					License along with this library
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					#endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					using System.Diagnostics;
 | 
				
			||||||
 | 
					using System.Text;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Nuclex.Support {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /// <summary>Contains helper methods for the string builder class</summary>
 | 
				
			||||||
 | 
					  public class StringBuilderHelper {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>Predefined unicode characters for the numbers 0 to 9</summary>
 | 
				
			||||||
 | 
					    private static readonly char[] numbers = new char[] {
 | 
				
			||||||
 | 
					      '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>Clears the contents of a string builder</summary>
 | 
				
			||||||
 | 
					    /// <param name="builder">String builder that will be cleared</param>
 | 
				
			||||||
 | 
					    public static void Clear(StringBuilder builder) {
 | 
				
			||||||
 | 
					      builder.Remove(0, builder.Length);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    ///   Appends an integer to a string builder without generating garbage
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <param name="builder">String builder to which an integer will be appended</param>
 | 
				
			||||||
 | 
					    /// <param name="value">Byte that will be appended to the string builder</param>
 | 
				
			||||||
 | 
					    /// <remarks>
 | 
				
			||||||
 | 
					    ///   The normal StringBuilder.Append() method generates garbage when converting
 | 
				
			||||||
 | 
					    ///   integer arguments whereas this method will avoid any garbage, albeit probably
 | 
				
			||||||
 | 
					    ///   with a small performance impact compared to the built-in method.
 | 
				
			||||||
 | 
					    /// </remarks>
 | 
				
			||||||
 | 
					    public static void Append(StringBuilder builder, byte value) {
 | 
				
			||||||
 | 
					      recursiveAppend(builder, value);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    ///   Appends an integer to a string builder without generating garbage
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <param name="builder">String builder to which an integer will be appended</param>
 | 
				
			||||||
 | 
					    /// <param name="value">Integer that will be appended to the string builder</param>
 | 
				
			||||||
 | 
					    /// <remarks>
 | 
				
			||||||
 | 
					    ///   The normal StringBuilder.Append() method generates garbage when converting
 | 
				
			||||||
 | 
					    ///   integer arguments whereas this method will avoid any garbage, albeit probably
 | 
				
			||||||
 | 
					    ///   with a small performance impact compared to the built-in method.
 | 
				
			||||||
 | 
					    /// </remarks>
 | 
				
			||||||
 | 
					    public static void Append(StringBuilder builder, int value) {
 | 
				
			||||||
 | 
					      if(value < 0) {
 | 
				
			||||||
 | 
					        builder.Append('-');
 | 
				
			||||||
 | 
					        recursiveAppend(builder, -value);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        recursiveAppend(builder, value);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    ///   Appends an long integer to a string builder without generating garbage
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <param name="builder">String builder to which an integer will be appended</param>
 | 
				
			||||||
 | 
					    /// <param name="value">Long integer that will be appended to the string builder</param>
 | 
				
			||||||
 | 
					    /// <remarks>
 | 
				
			||||||
 | 
					    ///   The normal StringBuilder.Append() method generates garbage when converting
 | 
				
			||||||
 | 
					    ///   integer arguments whereas this method will avoid any garbage, albeit probably
 | 
				
			||||||
 | 
					    ///   with a small performance impact compared to the built-in method.
 | 
				
			||||||
 | 
					    /// </remarks>
 | 
				
			||||||
 | 
					    public static void Append(StringBuilder builder, long value) {
 | 
				
			||||||
 | 
					      if(value < 0) {
 | 
				
			||||||
 | 
					        builder.Append('-');
 | 
				
			||||||
 | 
					        recursiveAppend(builder, -value);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        recursiveAppend(builder, value);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>
 | 
				
			||||||
 | 
					    ///   Appends a floating point value to a string builder without generating garbage
 | 
				
			||||||
 | 
					    /// </summary>
 | 
				
			||||||
 | 
					    /// <param name="builder">String builder the value will be appended to</param>
 | 
				
			||||||
 | 
					    /// <param name="value">Value that will be appended to the string builder</param>
 | 
				
			||||||
 | 
					    public static void Append(StringBuilder builder, float value) {
 | 
				
			||||||
 | 
					      const int ExponentBits = 0xFF; // Bit mask for the exponent bits
 | 
				
			||||||
 | 
					      const int FractionalBitCount = 23; // Number of bits for fractional part
 | 
				
			||||||
 | 
					      const int ExponentBias = 127; // Bias subtraced from exponent
 | 
				
			||||||
 | 
					      const int NumericBitCount = 31; // Bits without sign
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					      // You do not modify these as they're calculated based on the 
 | 
				
			||||||
 | 
					      const int FractionalBits = (2 << FractionalBitCount) - 1;
 | 
				
			||||||
 | 
					      const int HighestFractionalBit = (1 << FractionalBitCount);
 | 
				
			||||||
 | 
					      const int FractionalBitCountPlusOne = FractionalBitCount + 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      int intValue = FloatHelper.ReinterpretAsInt(value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      int exponent = ((intValue >> FractionalBitCount) & ExponentBits) - ExponentBias;
 | 
				
			||||||
 | 
					      int mantissa = (intValue & FractionalBits) | HighestFractionalBit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      int integral;
 | 
				
			||||||
 | 
					      int fractional;
 | 
				
			||||||
 | 
					      if(exponent >= 0) {
 | 
				
			||||||
 | 
					        if(exponent >= FractionalBitCount) {
 | 
				
			||||||
 | 
					          Debug.Assert(exponent < NumericBitCount);
 | 
				
			||||||
 | 
					          integral = mantissa << (exponent - FractionalBitCount);
 | 
				
			||||||
 | 
					          fractional = 0;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          integral = mantissa >> (FractionalBitCount - exponent);
 | 
				
			||||||
 | 
					          fractional = (mantissa << (exponent + 1)) & FractionalBits;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        Debug.Assert(exponent >= -FractionalBitCount);
 | 
				
			||||||
 | 
					        integral = 0;
 | 
				
			||||||
 | 
					        fractional = (mantissa & FractionalBits) >> -(exponent + 1);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					/*      
 | 
				
			||||||
 | 
					      if(exponent >= NumericBitCount) {
 | 
				
			||||||
 | 
					        throw new ArgumentException("Value too large", "value");
 | 
				
			||||||
 | 
					      } else if(exponent < -FractionalBitCount) {
 | 
				
			||||||
 | 
					        throw new ArgumentException("Value too small", "value");
 | 
				
			||||||
 | 
					      } else if(exponent >= FractionalBitCount) {
 | 
				
			||||||
 | 
					        integral = mantissa << (exponent - FractionalBitCount);
 | 
				
			||||||
 | 
					        fractional = 0;
 | 
				
			||||||
 | 
					      } else if(exponent >= 0) {
 | 
				
			||||||
 | 
					        integral = mantissa >> (FractionalBitCount - exponent);
 | 
				
			||||||
 | 
					        fractional = (mantissa << (exponent + 1)) & FractionalBits;
 | 
				
			||||||
 | 
					      } else { // exp2 < 0
 | 
				
			||||||
 | 
					        integral = 0;
 | 
				
			||||||
 | 
					        fractional = (mantissa & FractionalBits) >> -(exponent + 1);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					      // Build the integral part      
 | 
				
			||||||
 | 
					      if(intValue < 0) {
 | 
				
			||||||
 | 
					        builder.Append('-');
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if(integral == 0) {
 | 
				
			||||||
 | 
					        builder.Append('0');
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        recursiveAppend(builder, integral);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      builder.Append('.');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // Build the fractional part
 | 
				
			||||||
 | 
					      if(fractional == 0) {
 | 
				
			||||||
 | 
					        builder.Append('0');
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        while(fractional != 0) {
 | 
				
			||||||
 | 
					          fractional *= 10;
 | 
				
			||||||
 | 
					          int digit = (fractional >> FractionalBitCountPlusOne);
 | 
				
			||||||
 | 
					          builder.Append(numbers[digit]);
 | 
				
			||||||
 | 
					          fractional &= FractionalBits;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>Recursively appends a number's characters to a string builder</summary>
 | 
				
			||||||
 | 
					    /// <param name="builder">String builder the number will be appended to</param>
 | 
				
			||||||
 | 
					    /// <param name="remaining">Remaining digits that will be recursively processed</param>
 | 
				
			||||||
 | 
					    private static void recursiveAppend(StringBuilder builder, int remaining) {
 | 
				
			||||||
 | 
					      int digit;
 | 
				
			||||||
 | 
					      int tenth = Math.DivRem(remaining, 10, out digit);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if(tenth > 0) {
 | 
				
			||||||
 | 
					        recursiveAppend(builder, tenth);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      builder.Append(numbers[digit]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// <summary>Recursively appends a number's characters to a string builder</summary>
 | 
				
			||||||
 | 
					    /// <param name="builder">String builder the number will be appended to</param>
 | 
				
			||||||
 | 
					    /// <param name="remaining">Remaining digits that will be recursively processed</param>
 | 
				
			||||||
 | 
					    private static void recursiveAppend(StringBuilder builder, long remaining) {
 | 
				
			||||||
 | 
					      long digit;
 | 
				
			||||||
 | 
					      long tenth = Math.DivRem(remaining, 10, out digit);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if(tenth > 0) {
 | 
				
			||||||
 | 
					        recursiveAppend(builder, tenth);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      builder.Append(numbers[digit]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace Nuclex.Support
 | 
				
			||||||
| 
						 | 
					@ -165,3 +165,4 @@ namespace Nuclex.Support {
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // namespace Nuclex.Support
 | 
					} // namespace Nuclex.Support
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue