2

In C# I can do the following:

decimal v = 123.456M;
            
var span = new ReadOnlySpan<int>(&v, 4);

var flags = span[0];
var hi32 = span[1];
var lo32 = span[2];
var mi32 = span[3];

Is there a way to do the same in F# 5.0?

Context: I’m trying to port the Decimal.IsCanonical method from .NET 7 to .NET Framework 4.7.2 and F# 5.0. So I need to access the internal representation of a decimal number. The method will be used on a hot path, so I want to avoid using the Decimal.GetBits() method since it allocates an array.

1 Answers1

3

It's possible to create span from pointer and length, but availability of public constructor varies on target framework version

open System
open System.Runtime.CompilerServices
open System.Runtime.InteropServices

let newer (d:decimal) = // netstandard2.1 and newer (net core 3.1, net5.0)
    let span = ReadOnlySpan<int>(Unsafe.AsPointer(&Unsafe.AsRef &d), 4)
    let flags = span.[0]
    let hi32 = span.[1]
    let lo32 = span.[2]
    let mi32 = span.[3]
    ()
    
let older (d:decimal) = // before span ctor become public (net framework and netstandard2.0)
    let span = MemoryMarshal.CreateSpan(&Unsafe.As<_, int>(&Unsafe.AsRef &d), 4)
    let flags = span.[0]
    let hi32 = span.[1]
    let lo32 = span.[2]
    let mi32 = span.[3]
    ()

Note: System.Runtime.CompilerServices.Unsafe must be installed as nuget package if targeting older frameworks

JL0PD
  • 3,698
  • 2
  • 15
  • 23
  • The first, newer, variant is working on .NET Framework 4.7.2 with the latest Systme.Memory NuGet package installed. Thank you! – Andrew Rybka Dec 24 '22 at 21:20