}
FCIMPLEND
-
-void COMDecimal::DecimalToNumber(DECIMAL* value, NUMBER* number)
-{
- WRAPPER_NO_CONTRACT
- _ASSERTE(number != NULL);
- _ASSERTE(value != NULL);
-
- wchar_t buffer[DECIMAL_PRECISION+1];
- DECIMAL d = *value;
- number->precision = DECIMAL_PRECISION;
- number->sign = DECIMAL_SIGN(d)? 1: 0;
- wchar_t* p = buffer + DECIMAL_PRECISION;
- while (DECIMAL_MID32(d) | DECIMAL_HI32(d)) {
- p = COMNumber::Int32ToDecChars(p, DecDivMod1E9(&d), 9);
- _ASSERTE(p != NULL);
- }
- p = COMNumber::Int32ToDecChars(p, DECIMAL_LO32(d), 0);
- _ASSERTE(p != NULL);
- int i = (int) (buffer + DECIMAL_PRECISION - p);
- number->scale = i - DECIMAL_SCALE(d);
- wchar_t* dst = number->digits;
- _ASSERTE(dst != NULL);
- while (--i >= 0) *dst++ = *p++;
- *dst = 0;
-
-}
-
int COMDecimal::NumberToDecimal(NUMBER* number, DECIMAL* value)
{
WRAPPER_NO_CONTRACT
static FCDECL1(INT32, ToInt32, FC_DECIMAL d);
static FCDECL1(Object*, ToString, FC_DECIMAL d);
- static void DecimalToNumber(DECIMAL* value, NUMBER* number);
static int NumberToDecimal(NUMBER* number, DECIMAL* value);
#pragma warning(pop)
#endif
-FCIMPL3_VII(Object*, COMNumber::FormatDecimal, FC_DECIMAL value, StringObject* formatUNSAFE, NumberFormatInfo* numfmtUNSAFE)
-{
- FCALL_CONTRACT;
-
- NUMBER number;
-
- wchar fmt;
- int digits;
-
- STRINGREF refRetVal = NULL;
- HELPER_METHOD_FRAME_BEGIN_RET_1(refRetVal);
-
- struct _gc
- {
- STRINGREF format;
- NUMFMTREF numfmt;
- } gc;
-
- gc.format = (STRINGREF) formatUNSAFE;
- gc.numfmt = (NUMFMTREF) numfmtUNSAFE;
-
- if (gc.numfmt == 0)
- COMPlusThrowArgumentNull(W("NumberFormatInfo"));
-
- COMDecimal::DecimalToNumber(&value, &number);
-
- fmt = ParseFormatSpecifier(gc.format, &digits);
- if (fmt != 0) {
- refRetVal = NumberToString(&number, fmt, digits, gc.numfmt, TRUE);
- } else {
- refRetVal = NumberToStringFormat(&number, gc.format, gc.numfmt);
- }
-
- HELPER_METHOD_FRAME_END();
-
- return OBJECTREFToObject(refRetVal);
-}
-FCIMPLEND
-
FCIMPL3_VII(Object*, COMNumber::FormatDouble, double value, StringObject* formatUNSAFE, NumberFormatInfo* numfmtUNSAFE)
{
FCALL_CONTRACT;
class COMNumber
{
public:
- static FCDECL3_VII(Object*, FormatDecimal, FC_DECIMAL value, StringObject* formatUNSAFE, NumberFormatInfo* numfmtUNSAFE);
static FCDECL3_VII(Object*, FormatDouble, double value, StringObject* formatUNSAFE, NumberFormatInfo* numfmtUNSAFE);
static FCDECL3_VII(Object*, FormatSingle, float value, StringObject* formatUNSAFE, NumberFormatInfo* numfmtUNSAFE);
static FCDECL2(FC_BOOL_RET, NumberBufferToDecimal, BYTE* number, DECIMAL* value);
<Compile Include="$(BclSourcesRoot)\System\Buffer.cs" />
<Compile Include="$(BclSourcesRoot)\System\Currency.cs" />
<Compile Include="$(BclSourcesRoot)\System\Decimal.cs" />
+ <Compile Include="$(BclSourcesRoot)\System\Decimal.DecCalc.cs" />
<Compile Include="$(BclSourcesRoot)\System\DefaultBinder.CanConvert.cs" />
<Compile Include="$(BclSourcesRoot)\System\Empty.cs" />
<Compile Include="$(BclSourcesRoot)\System\Enum.cs" />
"(#)", "-#", "- #", "#-", "# -",
};
+ public static string FormatDecimal(decimal value, string format, NumberFormatInfo info)
+ {
+ char fmt = ParseFormatSpecifier(format, out int digits);
+
+ NumberBuffer number = default;
+ DecimalToNumber(value, ref number);
+
+ ValueStringBuilder sb;
+ unsafe
+ {
+ char* stackPtr = stackalloc char[CharStackBufferSize];
+ sb = new ValueStringBuilder(new Span<char>(stackPtr, CharStackBufferSize));
+ }
+
+ if (fmt != 0)
+ {
+ NumberToString(ref sb, ref number, fmt, digits, info, isDecimal:true);
+ }
+ else
+ {
+ NumberToStringFormat(ref sb, ref number, format, info);
+ }
+
+ return sb.GetString();
+ }
+
+ public static bool TryFormatDecimal(decimal value, string format, NumberFormatInfo info, Span<char> destination, out int charsWritten)
+ {
+ char fmt = ParseFormatSpecifier(format, out int digits);
+
+ NumberBuffer number = default;
+ DecimalToNumber(value, ref number);
+
+ ValueStringBuilder sb;
+ unsafe
+ {
+ char* stackPtr = stackalloc char[CharStackBufferSize];
+ sb = new ValueStringBuilder(new Span<char>(stackPtr, CharStackBufferSize));
+ }
+
+ if (fmt != 0)
+ {
+ NumberToString(ref sb, ref number, fmt, digits, info, isDecimal: true);
+ }
+ else
+ {
+ NumberToStringFormat(ref sb, ref number, format, info);
+ }
+
+ return sb.TryCopyTo(destination, out charsWritten);
+ }
+
+#if PROJECTN
+ [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoOptimization)]
+#endif
+ private static unsafe void DecimalToNumber(decimal value, ref NumberBuffer number)
+ {
+ decimal d = value;
+
+ char* buffer = number.digits;
+ number.precision = DecimalPrecision;
+ number.sign = d.IsNegative;
+
+ char* p = buffer + DecimalPrecision;
+ while ((d.Mid | d.High) != 0)
+ {
+ p = UInt32ToDecChars(p, decimal.DecDivMod1E9(ref d), 9);
+ }
+ p = UInt32ToDecChars(p, d.Low, 0);
+
+ int i = (int)(buffer + DecimalPrecision - p);
+ number.scale = i - d.Scale;
+
+ char* dst = number.digits;
+ while (--i >= 0)
+ {
+ *dst++ = *p++;
+ }
+ *dst = '\0';
+ }
+
public static string FormatInt32(int value, string format, NumberFormatInfo info)
{
int digits;
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.CompilerServices;
+
+namespace System
+{
+ public partial struct Decimal
+ {
+ internal static uint DecDivMod1E9(ref decimal value)
+ {
+ return D32DivMod1E9(D32DivMod1E9(D32DivMod1E9(0,
+ ref Unsafe.As<int, uint>(ref value.hi)),
+ ref Unsafe.As<int, uint>(ref value.mid)),
+ ref Unsafe.As<int, uint>(ref value.lo));
+
+ uint D32DivMod1E9(uint hi32, ref uint lo32)
+ {
+ ulong n = (ulong)hi32 << 32 | lo32;
+ lo32 = (uint)(n / 1000000000);
+ return (uint)(n % 1000000000);
+ }
+ }
+ }
+}
[Serializable]
[System.Runtime.Versioning.NonVersionable] // This only applies to field layout
[System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
- public struct Decimal : IFormattable, IComparable, IConvertible, IComparable<Decimal>, IEquatable<Decimal>, IDeserializationCallback
+ public partial struct Decimal : IFormattable, IComparable, IConvertible, IComparable<Decimal>, IEquatable<Decimal>, IDeserializationCallback
{
// Sign mask for the flags field. A value of zero in this bit indicates a
// positive Decimal value, and a value of one in this bit indicates a
private int lo;
private int mid;
+ internal uint High => (uint)hi;
+ internal uint Low => (uint)lo;
+ internal uint Mid => (uint)mid;
// Constructs a zero Decimal.
//public Decimal() {
return d1;
}
+ internal bool IsNegative => (flags & SignMask) != 0;
+
+ internal int Scale => (byte)((uint)flags >> ScaleShift);
+
// FCallAddSub adds or subtracts two decimal values. On return, d1 contains the result
// of the operation. Passing in DECIMAL_ADD or DECIMAL_NEG for bSign indicates
// addition or subtraction, respectively.
return Number.FormatDecimal(this, format, NumberFormatInfo.GetInstance(provider));
}
+ public bool TryFormat(Span<char> destination, out int charsWritten, string format = null, IFormatProvider provider = null)
+ {
+ return Number.TryFormatDecimal(this, format, NumberFormatInfo.GetInstance(provider), destination, out charsWritten);
+ }
// Converts a string to a Decimal. The string must consist of an optional
// minus sign ("-") followed by a sequence of digits ("0" - "9"). The
internal static partial class Number
{
[MethodImpl(MethodImplOptions.InternalCall)]
- public static extern string FormatDecimal(decimal value, string format, NumberFormatInfo info);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
public static extern string FormatDouble(double value, string format, NumberFormatInfo info);
[MethodImpl(MethodImplOptions.InternalCall)]
FCFuncEnd()
FCFuncStart(gNumberFuncs)
- FCFuncElement("FormatDecimal", COMNumber::FormatDecimal)
FCFuncElement("FormatDouble", COMNumber::FormatDouble)
FCFuncElement("FormatSingle", COMNumber::FormatSingle)
FCFuncElement("NumberBufferToDecimal", COMNumber::NumberBufferToDecimal)