-1

In my application I using SKPoinI as a key to store some small objects in Dictionary. SkiaSharp already used in this project for drawing and not need to be referred to only to allow SKPointI to be used as a key.

At first look, it's a good and simple solution, but I not sure because as I presume that the SkiaSharp library primarily optimized for graphics.

Maybe better create a structure that has two Int32 as coordinates and implementation of IEqitable, or create combined Int64 via BitConverter to be used as the key

key = BitConverter.ToInt64(BitConverter.GetBytes(x).Concat(BitConverter.GetBytes(y)).ToArray)

and get x and y from a key with code like:

With BitConverter.GetBytes(key)
    x = BitConverter.ToInt32(.Take(4).ToArray)
    y = BitConverter.ToInt32(.Skip(4).ToArray)
End With

What way is better if the application will add objects only once on the initial stage and then accesses them frequently?

I already using the key for 3D-storage:

Public Structure Adr3D
    Implements IEquatable(Of Adr3D)

#Region "Public Constructors"

Public Sub New(x As Integer, y As Integer, z As Integer)
    Me.X = x
    Me.Y = y
    Me.Z = z
End Sub

#End Region

#Region "Public Properties"

Public ReadOnly Property X As Integer

Public ReadOnly Property Y As Integer

Public ReadOnly Property Z As Integer

#End Region

#Region "Public Methods"

Public Shared Operator <>(left As Adr3D, right As Adr3D) As Boolean
    Return Not left.Equals(right)
End Operator

Public Shared Operator =(left As Adr3D, right As Adr3D) As Boolean
    Return left.Equals(right)
End Operator

Public Overrides Function Equals(obj As Object) As Boolean
    Return TypeOf obj Is Adr3D AndAlso Equals(DirectCast(obj, Adr3D))
End Function

Public Overloads Function Equals(other As Adr3D) As Boolean Implements IEquatable(Of Adr3D).Equals
    Return X = other.X AndAlso Y = other.Y AndAlso Z = other.Z
End Function

Public Overrides Function GetHashCode() As Integer
    Return HashCode.Combine(X, Y, Z)
End Function

Public Overrides Function ToString() As String
    Return $"{{X = {X}, Y = {Y}, Z = {Z}}}"
End Function

#End Region

End Structure

In fact, it is not a question of "How to implement?", but "What is more efficient?"

Thanks for any advice!

1 Answers1

0

Finally, I created a benchmark-program and find out the most efficient (fastest) implementation:

Module Program
    Const Length = 1024 * 16
    Const IterLim = 1024 * 1024 * 2
    ReadOnly Rand As New Random
    Structure Adr2D
        Implements IEquatable(Of Adr2D)
        Public Sub New(x As Integer, y As Integer)
            Me.X = x
            Me.Y = y
        End Sub
        Public ReadOnly Property X As Integer
        Public ReadOnly Property Y As Integer
        Public Shared Operator <>(left As Adr2D, right As Adr2D) As Boolean
            Return Not left.Equals(right)
        End Operator
        Public Shared Operator =(left As Adr2D, right As Adr2D) As Boolean
            Return left.Equals(right)
        End Operator
        Public Overrides Function Equals(obj As Object) As Boolean
            Return TypeOf obj Is Adr2D AndAlso Equals(DirectCast(obj, Adr2D))
        End Function
        Public Overloads Function Equals(other As Adr2D) As Boolean Implements IEquatable(Of Adr2D).Equals
            Return X = other.X AndAlso Y = other.Y
        End Function
        Public Overrides Function GetHashCode() As Integer
            Return HashCode.Combine(X, Y)
        End Function
        Public Overrides Function ToString() As String
            Return $"{{X = {X}, Y = {Y}}}"
        End Function
    End Structure
    Sub Main(args As String())
        Console.WriteLine($"    SKPointI: {FormatNumber(BenchSKPointI, 3)} s.")
        Console.WriteLine($"       Adr2D: {FormatNumber(BenchAdr2D, 3)} s.")
        Console.WriteLine($"Long (Int64): {FormatNumber(BenchLong, 3)} s.")
        Do
        Loop Until Console.KeyAvailable
        Console.ReadKey()
    End Sub
    Function BenchSKPointI() As Double
        Dim objSW = Stopwatch.StartNew
        Dim dicTest = New Dictionary(Of SkiaSharp.SKPointI, Double)
        For i = 1 To Length
            Dim stKey As SkiaSharp.SKPointI
            Do
                stKey = New SkiaSharp.SKPointI(Rand.Next, Rand.Next)
            Loop While dicTest.ContainsKey(stKey)
            dicTest.Add(stKey, Rand.NextDouble)
        Next
        Dim dSum As Double
        For i = 1 To IterLim
            dSum += dicTest(dicTest.Keys(Rand.Next(Length)))
        Next
        Return objSW.Elapsed.TotalSeconds
    End Function
    Function BenchAdr2D() As Double
        Dim objSW = Stopwatch.StartNew
        Dim dicTest = New Dictionary(Of Adr2D, Double)
        For i = 1 To Length
            Dim stKey As Adr2D
            Do
                stKey = New Adr2D(Rand.Next, Rand.Next)
            Loop While dicTest.ContainsKey(stKey)
            dicTest.Add(stKey, Rand.NextDouble)
        Next
        Dim dSum As Double
        For i = 1 To IterLim
            dSum += dicTest(dicTest.Keys(Rand.Next(Length)))
        Next
        Return objSW.Elapsed.TotalSeconds
    End Function
    Function BenchLong() As Double
        Dim objSW = Stopwatch.StartNew
        Dim dicTest = New Dictionary(Of Long, Double)
        For i = 1 To Length
            Dim lKey As Long
            Do
                lKey = BitConverter.ToInt64(BitConverter.GetBytes(Rand.Next).Concat(BitConverter.GetBytes(Rand.Next)).ToArray)
            Loop While dicTest.ContainsKey(lKey)
            dicTest.Add(lKey, Rand.NextDouble)
        Next
        Dim dSum As Double
        For i = 1 To IterLim
            dSum += dicTest(dicTest.Keys(Rand.Next(Length)))
        Next
        Return objSW.Elapsed.TotalSeconds
    End Function
End Module

The program gives the next output:

    SKPointI: 62,400 s.
       Adr2D: 56,954 s.
Long (Int64): 60,531 s.

According to program output, the fastest are own Structure that implements IEquatable (Adr2D).