Some cosmetic changes; all methods in the StringBuilderHelper are now extension methods; added GarbagePolicy enumeration for StringBuilder helper methods; custom Semaphore is not internal in Windows builds to avoid ambiguous symbols

git-svn-id: file:///srv/devel/repo-conversion/nusu@263 d2e56fa2-650e-0410-a79f-9358c0239efd
This commit is contained in:
Markus Ewald 2012-03-03 12:45:49 +00:00
parent 1a05bf9d63
commit 07a9de6283
13 changed files with 495 additions and 103 deletions

View file

@ -194,6 +194,35 @@ namespace Nuclex.Support.Collections {
Assert.IsFalse(set2.IsSubsetOf(set1));
}
/// <summary>
/// Verifies that a set can determine if another set overlaps with it
/// </summary>
[Test]
public void CanDetermineOverlap() {
var set1 = new ObservableSet<int>() { 1, 3, 5 };
var set2 = new ObservableSet<int>() { 3 };
Assert.IsTrue(set1.Overlaps(set2));
Assert.IsTrue(set2.Overlaps(set1));
}
/// <summary>
/// Verifies that a set can determine if another set contains the same elements
/// </summary>
[Test]
public void CanDetermineSetEquality() {
var set1 = new ObservableSet<int>() { 1, 3, 5 };
var set2 = new ObservableSet<int>() { 3, 1, 5 };
Assert.IsTrue(set1.SetEquals(set2));
Assert.IsTrue(set2.SetEquals(set1));
set1.Add(7);
Assert.IsFalse(set1.SetEquals(set2));
Assert.IsFalse(set2.SetEquals(set1));
}
/// <summary>Creates mock object for the test</summary>
private MockFactory mockFactory;
/// <summary>Observable set being tested</summary>

View file

@ -37,9 +37,9 @@ namespace Nuclex.Support.Collections {
ISet<TItem>,
ICollection<TItem>,
#if !NO_SPECIALIZED_COLLECTIONS
INotifyCollectionChanged,
INotifyCollectionChanged,
#endif
IObservableCollection<TItem> {
IObservableCollection<TItem> {
/// <summary>Raised when an item has been added to the collection</summary>
public event EventHandler<ItemEventArgs<TItem>> ItemAdded;

View file

@ -29,22 +29,22 @@ namespace Nuclex.Support {
public static class EnumHelper {
/// <summary>Returns the highest value encountered in an enumeration</summary>
/// <typeparam name="EnumType">
/// <typeparam name="TEnum">
/// Enumeration of which the highest value will be returned
/// </typeparam>
/// <returns>The highest value in the enumeration</returns>
public static EnumType GetHighestValue<EnumType>() where EnumType : IComparable {
EnumType[] values = GetValues<EnumType>();
public static TEnum GetHighestValue<TEnum>() where TEnum : IComparable {
TEnum[] values = GetValues<TEnum>();
// If the enumeration is empty, return nothing
if(values.Length == 0) {
return default(EnumType);
return default(TEnum);
}
// Look for the highest value in the enumeration. We initialize the highest value
// to the first enumeration value so we don't have to use some arbitrary starting
// value which might actually appear in the enumeration.
EnumType highestValue = values[0];
TEnum highestValue = values[0];
for(int index = 1; index < values.Length; ++index) {
if(values[index].CompareTo(highestValue) > 0) {
highestValue = values[index];
@ -81,7 +81,7 @@ namespace Nuclex.Support {
}
/// <summary>Retrieves a list of all values contained in an enumeration</summary>
/// <typeparam name="EnumType">
/// <typeparam name="TEnum">
/// Type of the enumeration whose values will be returned
/// </typeparam>
/// <returns>All values contained in the specified enumeration</returns>
@ -89,21 +89,21 @@ namespace Nuclex.Support {
/// This method produces collectable garbage so it's best to only call it once
/// and cache the result.
/// </remarks>
public static EnumType[] GetValues<EnumType>() {
public static TEnum[] GetValues<TEnum>() {
#if XBOX360 || WINDOWS_PHONE
return GetValuesXbox360<EnumType>();
return GetValuesXbox360<TEnum>();
#else
return (EnumType[])Enum.GetValues(typeof(EnumType));
return (TEnum[])Enum.GetValues(typeof(TEnum));
#endif
}
/// <summary>Retrieves a list of all values contained in an enumeration</summary>
/// <typeparam name="EnumType">
/// <typeparam name="TEnum">
/// Type of the enumeration whose values will be returned
/// </typeparam>
/// <returns>All values contained in the specified enumeration</returns>
internal static EnumType[] GetValuesXbox360<EnumType>() {
Type enumType = typeof(EnumType);
internal static TEnum[] GetValuesXbox360<TEnum>() {
Type enumType = typeof(TEnum);
if(!enumType.IsEnum) {
throw new ArgumentException(
"The provided type needs to be an enumeration", "EnumType"
@ -117,9 +117,9 @@ namespace Nuclex.Support {
// Create an array to hold the enumeration values and copy them over from
// the fields we just retrieved
EnumType[] values = new EnumType[fieldInfos.Length];
TEnum[] values = new TEnum[fieldInfos.Length];
for(int index = 0; index < fieldInfos.Length; ++index) {
values[index] = (EnumType)fieldInfos[index].GetValue(null);
values[index] = (TEnum)fieldInfos[index].GetValue(null);
}
return values;

33
Source/GarbagePolicy.cs Normal file
View file

@ -0,0 +1,33 @@
#region CPL License
/*
Nuclex Framework
Copyright (C) 2002-2012 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;
namespace Nuclex.Support {
/// <summary>How to behave in in respect to the garbage collector</summary>
public enum GarbagePolicy {
/// <summary>Avoid feeding the garbage collector whenever possible</summary>
Avoid,
/// <summary>Accept garbage production</summary>
Accept
}
} // namespace Nuclex.Support

View file

@ -175,9 +175,6 @@ namespace Nuclex.Support {
/// <summary>
/// Determines whether the property change affects the specified property
/// </summary>
/// <typeparam name="TValue">
/// Type of the property that will be tested for being affected
/// </typeparam>
/// <param name="arguments">
/// Property change that has been reported by the observed object
/// </param>

View file

@ -56,10 +56,12 @@ namespace Nuclex.Support {
/// become eligible for execution.
/// </para>
/// </remarks>
#if !(XBOX360 || WINDOWS_PHONE)
#if WINDOWS
[Obsolete("Prefer the normal semaphore on Windows builds.")]
#endif
internal class Semaphore : WaitHandle {
#else
public class Semaphore : WaitHandle {
#endif
/// <summary>Initializes a new semaphore</summary>
public Semaphore() {

View file

@ -24,13 +24,13 @@ using System.Diagnostics;
namespace Nuclex.Support {
/// <summary>Manages a globally shared instance of the given Type</summary>
/// <typeparam name="SharedType">
/// <typeparam name="TShared">
/// Type of which a globally shared instance will be provided
/// </typeparam>
public static class Shared<SharedType> where SharedType : new() {
public static class Shared<TShared> where TShared : new() {
/// <summary>Returns the global instance of the class</summary>
public static SharedType Instance {
public static TShared Instance {
[DebuggerStepThrough]
get {
return instance;
@ -38,7 +38,7 @@ namespace Nuclex.Support {
}
/// <summary>Stored the globally shared instance</summary>
private static readonly SharedType instance = new SharedType();
private static readonly TShared instance = new TShared();
}

View file

@ -40,8 +40,13 @@ namespace Nuclex.Support {
[Test]
public void TestAppendByte() {
StringBuilder builder = new StringBuilder();
StringBuilderHelper.Append(builder, (byte)255);
builder.Append((byte)255, GarbagePolicy.Avoid);
Assert.AreEqual("255", builder.ToString());
builder.Clear();
builder.Append((byte)255, GarbagePolicy.Accept);
Assert.AreEqual("255", builder.ToString());
}
@ -51,8 +56,13 @@ namespace Nuclex.Support {
[Test]
public void TestAppendNullByte() {
StringBuilder builder = new StringBuilder();
StringBuilderHelper.Append(builder, (byte)0);
builder.Append((byte)0, GarbagePolicy.Avoid);
Assert.AreEqual("0", builder.ToString());
builder.Clear();
builder.Append((byte)0, GarbagePolicy.Accept);
Assert.AreEqual("0", builder.ToString());
}
@ -62,8 +72,13 @@ namespace Nuclex.Support {
[Test]
public void TestAppendPositiveInteger() {
StringBuilder builder = new StringBuilder();
StringBuilderHelper.Append(builder, 12345);
builder.Append(12345, GarbagePolicy.Avoid);
Assert.AreEqual("12345", builder.ToString());
builder.Clear();
builder.Append(12345, GarbagePolicy.Accept);
Assert.AreEqual("12345", builder.ToString());
}
@ -73,8 +88,13 @@ namespace Nuclex.Support {
[Test]
public void TestAppendNullInteger() {
StringBuilder builder = new StringBuilder();
StringBuilderHelper.Append(builder, 0);
builder.Append(0, GarbagePolicy.Avoid);
Assert.AreEqual("0", builder.ToString());
builder.Clear();
builder.Append(0, GarbagePolicy.Accept);
Assert.AreEqual("0", builder.ToString());
}
@ -84,8 +104,13 @@ namespace Nuclex.Support {
[Test]
public void TestAppendNegativeInteger() {
StringBuilder builder = new StringBuilder();
StringBuilderHelper.Append(builder, -12345);
builder.Append(-12345, GarbagePolicy.Avoid);
Assert.AreEqual("-12345", builder.ToString());
builder.Clear();
builder.Append(-12345, GarbagePolicy.Accept);
Assert.AreEqual("-12345", builder.ToString());
}
@ -95,8 +120,13 @@ namespace Nuclex.Support {
[Test]
public void TestAppendPositiveLong() {
StringBuilder builder = new StringBuilder();
StringBuilderHelper.Append(builder, 12345L);
builder.Append(12345L, GarbagePolicy.Avoid);
Assert.AreEqual("12345", builder.ToString());
builder.Clear();
builder.Append(12345L, GarbagePolicy.Accept);
Assert.AreEqual("12345", builder.ToString());
}
@ -106,8 +136,13 @@ namespace Nuclex.Support {
[Test]
public void TestAppendNullLong() {
StringBuilder builder = new StringBuilder();
StringBuilderHelper.Append(builder, 0L);
builder.Append(0L, GarbagePolicy.Avoid);
Assert.AreEqual("0", builder.ToString());
builder.Clear();
builder.Append(0L, GarbagePolicy.Accept);
Assert.AreEqual("0", builder.ToString());
}
@ -117,8 +152,13 @@ namespace Nuclex.Support {
[Test]
public void TestAppendNegativeLong() {
StringBuilder builder = new StringBuilder();
StringBuilderHelper.Append(builder, -12345L);
builder.Append(-12345L, GarbagePolicy.Avoid);
Assert.AreEqual("-12345", builder.ToString());
builder.Clear();
builder.Append(-12345L, GarbagePolicy.Accept);
Assert.AreEqual("-12345", builder.ToString());
}
@ -128,9 +168,14 @@ namespace Nuclex.Support {
[Test]
public void TestAppendNegativeFloat() {
StringBuilder builder = new StringBuilder();
StringBuilderHelper.Append(builder, -32.015625f);
Assert.AreEqual("-32.015625", builder.ToString());
builder.Append(-0.125f, GarbagePolicy.Avoid);
Assert.AreEqual("-0.125", builder.ToString());
builder.Clear();
builder.Append(-0.125f, GarbagePolicy.Accept);
Assert.AreEqual("-0.125", builder.ToString());
}
/// <summary>
@ -139,8 +184,13 @@ namespace Nuclex.Support {
[Test]
public void TestAppendPositiveFloat() {
StringBuilder builder = new StringBuilder();
StringBuilderHelper.Append(builder, 10.0625f);
builder.Append(10.0625f, GarbagePolicy.Avoid);
Assert.AreEqual("10.0625", builder.ToString());
builder.Clear();
builder.Append(10.0625f, GarbagePolicy.Accept);
Assert.AreEqual("10.0625", builder.ToString());
}
@ -150,8 +200,13 @@ namespace Nuclex.Support {
[Test]
public void TestAppendSmallFloat() {
StringBuilder builder = new StringBuilder();
StringBuilderHelper.Append(builder, 0.00390625f);
builder.Append(0.00390625f, GarbagePolicy.Avoid);
Assert.AreEqual("0.00390625", builder.ToString());
builder.Clear();
builder.Append(0.00390625f, GarbagePolicy.Accept);
Assert.AreEqual("0.00390625", builder.ToString());
}
@ -161,17 +216,21 @@ namespace Nuclex.Support {
[Test]
public void TestAppendHugeFloat() {
StringBuilder builder = new StringBuilder();
StringBuilderHelper.Append(builder, 1000000000.0f);
builder.Append(1000000000.0f, GarbagePolicy.Avoid);
Assert.AreEqual("1000000000.0", builder.ToString());
builder.Clear();
builder.Append(1000000000.0f, GarbagePolicy.Accept);
Assert.AreEqual("1E+09", builder.ToString());
}
/// <summary>Tests whether the number of decimal places can be restricted</summary>
[Test]
public void TestAppendFloatLimitDecimalPlaces() {
StringBuilder builder = new StringBuilder();
StringBuilderHelper.Append(builder, 0.00390625f, 3);
builder.Append(0.00390625f, 3);
Assert.AreEqual("0.003", builder.ToString());
}
@ -181,8 +240,7 @@ namespace Nuclex.Support {
[Test]
public void TestAppendFloatWithoutDecimalPlaces() {
StringBuilder builder = new StringBuilder();
StringBuilderHelper.Append(builder, 0.00390625f, 0);
builder.Append(0.00390625f, 0);
Assert.AreEqual("0", builder.ToString()); // Note: no rounding!
}
@ -192,10 +250,10 @@ namespace Nuclex.Support {
[Test]
public void TestAppendOutOfRangeFloat() {
StringBuilder builder = new StringBuilder();
Assert.IsFalse(StringBuilderHelper.Append(builder, float.PositiveInfinity));
Assert.IsFalse(StringBuilderHelper.Append(builder, float.NegativeInfinity));
Assert.IsFalse(StringBuilderHelper.Append(builder, float.NaN));
Assert.IsFalse(StringBuilderHelper.Append(builder, 0.000000059604644775390625f));
Assert.IsFalse(builder.Append(float.PositiveInfinity, GarbagePolicy.Avoid));
Assert.IsFalse(builder.Append(float.NegativeInfinity, GarbagePolicy.Avoid));
Assert.IsFalse(builder.Append(float.NaN, GarbagePolicy.Avoid));
Assert.IsFalse(builder.Append(0.000000059604644775390625f, GarbagePolicy.Avoid));
}
/// <summary>
@ -205,8 +263,13 @@ namespace Nuclex.Support {
[Test]
public void TestAppendNegativeDouble() {
StringBuilder builder = new StringBuilder();
StringBuilderHelper.Append(builder, -32.015625);
builder.Append(-32.015625, GarbagePolicy.Avoid);
Assert.AreEqual("-32.015625", builder.ToString());
builder.Clear();
builder.Append(-32.015625, GarbagePolicy.Accept);
Assert.AreEqual("-32.015625", builder.ToString());
}
@ -217,8 +280,13 @@ namespace Nuclex.Support {
[Test]
public void TestAppendPositiveDouble() {
StringBuilder builder = new StringBuilder();
StringBuilderHelper.Append(builder, 10.0625);
builder.Append(10.0625, GarbagePolicy.Avoid);
Assert.AreEqual("10.0625", builder.ToString());
builder.Clear();
builder.Append(10.0625, GarbagePolicy.Accept);
Assert.AreEqual("10.0625", builder.ToString());
}
@ -229,8 +297,13 @@ namespace Nuclex.Support {
[Test]
public void TestAppendSmallDouble() {
StringBuilder builder = new StringBuilder();
StringBuilderHelper.Append(builder, 0.00390625);
builder.Append(0.00390625, GarbagePolicy.Avoid);
Assert.AreEqual("0.00390625", builder.ToString());
builder.Clear();
builder.Append(0.00390625, GarbagePolicy.Accept);
Assert.AreEqual("0.00390625", builder.ToString());
}
@ -241,9 +314,14 @@ namespace Nuclex.Support {
[Test]
public void TestAppendHugeDouble() {
StringBuilder builder = new StringBuilder();
StringBuilderHelper.Append(builder, 1000000000000000000.0);
builder.Append(1000000000000000000.0, GarbagePolicy.Avoid);
Assert.AreEqual("1000000000000000000.0", builder.ToString());
builder.Clear();
builder.Append(1000000000000000000.0, GarbagePolicy.Accept);
Assert.AreEqual("1E+18", builder.ToString());
}
/// <summary>Tests whether the number of decimal places can be restricted</summary>
@ -273,12 +351,10 @@ namespace Nuclex.Support {
[Test]
public void TestAppendOutOfRangeDouble() {
StringBuilder builder = new StringBuilder();
Assert.IsFalse(StringBuilderHelper.Append(builder, double.PositiveInfinity));
Assert.IsFalse(StringBuilderHelper.Append(builder, double.NegativeInfinity));
Assert.IsFalse(StringBuilderHelper.Append(builder, double.NaN));
Assert.IsFalse(
StringBuilderHelper.Append(builder, 1.1102230246251565404236316680908e-16)
);
Assert.IsFalse(builder.Append(double.PositiveInfinity, GarbagePolicy.Avoid));
Assert.IsFalse(builder.Append(double.NegativeInfinity, GarbagePolicy.Avoid));
Assert.IsFalse(builder.Append(double.NaN, GarbagePolicy.Avoid));
Assert.IsFalse(builder.Append(1.1102230246251565404236316680908e-16, GarbagePolicy.Avoid));
}
/// <summary>
@ -291,7 +367,7 @@ namespace Nuclex.Support {
Assert.AreEqual(string.Empty, builder.ToString());
}
}
} // namespace Nuclex.Support

View file

@ -25,12 +25,6 @@ using System.Text;
namespace Nuclex.Support {
/*
public enum Garbage {
Avoid,
Accept
}
*/
/// <summary>Contains helper methods for the string builder class</summary>
public static class StringBuilderHelper {
@ -50,13 +44,20 @@ namespace Nuclex.Support {
/// </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>
/// <param name="garbagePolicy">How to behave regarding the garbage collector</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);
public static void Append(
this StringBuilder builder, byte value, GarbagePolicy garbagePolicy
) {
if(garbagePolicy == GarbagePolicy.Avoid) {
recursiveAppend(builder, value);
} else {
builder.Append((int)value);
}
}
/// <summary>
@ -64,17 +65,24 @@ namespace Nuclex.Support {
/// </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>
/// <param name="garbagePolicy">How to behave regarding the garbage collector</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);
public static void Append(
this StringBuilder builder, int value, GarbagePolicy garbagePolicy
) {
if(garbagePolicy == GarbagePolicy.Avoid) {
if(value < 0) {
builder.Append('-');
recursiveAppend(builder, -value);
} else {
recursiveAppend(builder, value);
}
} else {
recursiveAppend(builder, value);
builder.Append(value);
}
}
@ -83,17 +91,24 @@ namespace Nuclex.Support {
/// </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>
/// <param name="garbagePolicy">How to behave regarding the garbage collector</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);
public static void Append(
this StringBuilder builder, long value, GarbagePolicy garbagePolicy
) {
if(garbagePolicy == GarbagePolicy.Avoid) {
if(value < 0) {
builder.Append('-');
recursiveAppend(builder, -value);
} else {
recursiveAppend(builder, value);
}
} else {
recursiveAppend(builder, value);
builder.Append(value);
}
}
@ -102,14 +117,22 @@ namespace Nuclex.Support {
/// </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>
/// <param name="garbagePolicy">How to behave regarding the garbage collector</param>
/// <returns>Whether the value was inside the algorithm's supported range</returns>
/// <remarks>
/// Uses an algorithm that covers the sane range of possible values but will
/// fail to render extreme values, NaNs and infinity. In these cases, false
/// is returned and the traditional double.ToString() method can be used.
/// </remarks>
public static bool Append(StringBuilder builder, float value) {
return Append(builder, value, int.MaxValue);
public static bool Append(
this StringBuilder builder, float value, GarbagePolicy garbagePolicy
) {
if(garbagePolicy == GarbagePolicy.Avoid) {
return Append(builder, value, int.MaxValue);
} else {
builder.Append(value);
return true;
}
}
/// <summary>
@ -124,7 +147,7 @@ namespace Nuclex.Support {
/// fail to render extreme values, NaNs and infinity. In these cases, false
/// is returned and the traditional double.ToString() method can be used.
/// </remarks>
public static bool Append(StringBuilder builder, float value, int decimalPlaces) {
public static bool Append(this StringBuilder builder, float value, int decimalPlaces) {
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
@ -142,9 +165,9 @@ namespace Nuclex.Support {
int integral;
int fractional;
if (exponent >= 0) {
if (exponent >= FractionalBitCount) {
if (exponent >= NumericBitCount) {
if(exponent >= 0) {
if(exponent >= FractionalBitCount) {
if(exponent >= NumericBitCount) {
return false;
}
integral = mantissa << (exponent - FractionalBitCount);
@ -154,7 +177,7 @@ namespace Nuclex.Support {
fractional = (mantissa << (exponent + 1)) & FractionalBits;
}
} else {
if (exponent < -FractionalBitCount) {
if(exponent < -FractionalBitCount) {
return false;
}
integral = 0;
@ -162,30 +185,30 @@ namespace Nuclex.Support {
}
// Build the integral part
if (intValue < 0) {
if(intValue < 0) {
builder.Append('-');
}
if (integral == 0) {
if(integral == 0) {
builder.Append('0');
} else {
recursiveAppend(builder, integral);
}
if (decimalPlaces > 0) {
if(decimalPlaces > 0) {
builder.Append('.');
// Build the fractional part
if (fractional == 0) {
if(fractional == 0) {
builder.Append('0');
} else {
while (fractional != 0) {
while(fractional != 0) {
fractional *= 10;
int digit = (fractional >> FractionalBitCountPlusOne);
builder.Append(numbers[digit]);
fractional &= FractionalBits;
--decimalPlaces;
if (decimalPlaces == 0) {
if(decimalPlaces == 0) {
break;
}
}
@ -201,14 +224,22 @@ namespace Nuclex.Support {
/// </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>
/// <param name="garbagePolicy">How to behave regarding the garbage collector</param>
/// <returns>Whether the value was inside the algorithm's supported range</returns>
/// <remarks>
/// Uses an algorithm that covers the sane range of possible values but will
/// fail to render extreme values, NaNs and infinity. In these cases, false
/// is returned and the traditional double.ToString() method can be used.
/// </remarks>
public static bool Append(StringBuilder builder, double value) {
return Append(builder, value, int.MaxValue);
public static bool Append(
this StringBuilder builder, double value, GarbagePolicy garbagePolicy
) {
if(garbagePolicy == GarbagePolicy.Avoid) {
return Append(builder, value, int.MaxValue);
} else {
builder.Append(value);
return true;
}
}
/// <summary>
@ -224,7 +255,7 @@ namespace Nuclex.Support {
/// fail to render extreme values, NaNs and infinity. In these cases, false
/// is returned and the traditional double.ToString() method can be used.
/// </remarks>
public static bool Append(StringBuilder builder, double value, int decimalPlaces) {
public static bool Append(this StringBuilder builder, double value, int decimalPlaces) {
const long ExponentBits = 0x7FF; // Bit mask for the exponent bits
const int FractionalBitCount = 52; // Number of bits for fractional part
const int ExponentBias = 1023; // Bias subtraced from exponent
@ -242,9 +273,9 @@ namespace Nuclex.Support {
long integral;
long fractional;
if (exponent >= 0) {
if (exponent >= FractionalBitCount) {
if (exponent >= NumericBitCount) {
if(exponent >= 0) {
if(exponent >= FractionalBitCount) {
if(exponent >= NumericBitCount) {
return false;
}
integral = mantissa << (int)(exponent - FractionalBitCount);
@ -254,7 +285,7 @@ namespace Nuclex.Support {
fractional = (mantissa << (int)(exponent + 1)) & FractionalBits;
}
} else {
if (exponent < -FractionalBitCount) {
if(exponent < -FractionalBitCount) {
return false;
}
integral = 0;
@ -262,30 +293,30 @@ namespace Nuclex.Support {
}
// Build the integral part
if (longValue < 0) {
if(longValue < 0) {
builder.Append('-');
}
if (integral == 0) {
if(integral == 0) {
builder.Append('0');
} else {
recursiveAppend(builder, integral);
}
if (decimalPlaces > 0) {
if(decimalPlaces > 0) {
builder.Append('.');
// Build the fractional part
if (fractional == 0) {
if(fractional == 0) {
builder.Append('0');
} else {
while (fractional != 0) {
while(fractional != 0) {
fractional *= 10;
long digit = (fractional >> FractionalBitCountPlusOne);
builder.Append(numbers[digit]);
fractional &= FractionalBits;
--decimalPlaces;
if (decimalPlaces == 0) {
if(decimalPlaces == 0) {
break;
}
}
@ -307,7 +338,7 @@ namespace Nuclex.Support {
int tenth = remaining / 10;
#endif
if (tenth > 0) {
if(tenth > 0) {
recursiveAppend(builder, tenth);
}
@ -326,7 +357,7 @@ namespace Nuclex.Support {
long tenth = remaining / 10;
#endif
if (tenth > 0) {
if(tenth > 0) {
recursiveAppend(builder, tenth);
}