//\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
// CommonHelpers satellite library | Author: Sergei Y.Kitáev
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
using System;
using System.ComponentModel;

namespace CommonHelpers {

//**************************************************************************************************
partial class HMemory {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

public static int ElementSize<T>() where T: struct
{
   return HMarshal.SizeOf( typeof(T) );
}

public static int CountToSize<T>(int count) where T: struct
{
   if (count<0)
      throw new ArgumentOutOfRangeException(
         null, "Incorrect memory elements count." );
   return ElementSize<T>()*count;
}

//==================================================================================================

public static IntPtr Clear<T>([HOut] IntPtr ptrDestinationElements) where T: struct
{
   return Clear( ptrDestinationElements, 1 );
}

public static IntPtr Clear<T>([HOut] IntPtr ptrDestinationElements,int? count) where T: struct
{
   return Clear( ptrDestinationElements,
      ElementSize<T>()*(count ?? GetAllocatedCapacity<T>(ptrDestinationElements)) );
}

//--------------------------------------------------------------------------------------------------

public static IntPtr Copy<T>( [HIn] IntPtr ptrSourceElements,
                              [HOut] IntPtr ptrDestinationElements,
                              int count ) where T: struct
{
   return Copy( ptrSourceElements, ptrDestinationElements, CountToSize<T>(count) );
}

//==================================================================================================

public unsafe static T[] ToArray<T>([HIn] IntPtr ptrSourceElements,int count) where T: struct
{
   return HUnsafeMemory.ToArray<T>( (void*)ptrSourceElements, count );
}

//==================================================================================================

/// <exception cref="HOperationFailedException" />
public static IntPtr Allocate<T>() where T: struct
{
   return Allocate( 1 );
}

/// <exception cref="HOperationFailedException" />
public static IntPtr Allocate<T>(int capacity) where T: struct
{
   return Allocate( CountToSize<T>(capacity) );
}

/// <exception cref="HOperationFailedException" />
public static IntPtr ReAllocate<T>( [HIn] IntPtr ptrAllocatedBuffer,
                                    int newCapacity ) where T: struct
{
   return ReAllocate( ptrAllocatedBuffer, CountToSize<T>(newCapacity) );
}

/// <exception cref="HOperationFailedException" />
public static IntPtr ReAllocate<T>( [HIn][HVolatileAccess] ref IntPtr ptrAllocatedBuffer,
                                    int newCapacity ) where T: struct
{
   return ReAllocate( ref ptrAllocatedBuffer, CountToSize<T>(newCapacity) );
}

/// <exception cref="HOperationFailedException" />
public static IntPtr Duplicate<T>([HIn] IntPtr ptrAllocatedBuffer) where T: struct
{
   VerifyAllocatedBufferSize<T>( ptrAllocatedBuffer );
   return Duplicate( ptrAllocatedBuffer );
}

//--------------------------------------------------------------------------------------------------

/// <exception cref="HOperationFailedException" />
public static int GetAllocatedCapacity<T>(IntPtr ptrAllocatedBuffer) where T: struct
{
   int size = GetAllocatedSize( ptrAllocatedBuffer );
   VerifyAllocatedBufferSize<T>( size );
   return size/ElementSize<T>();
}

//--------------------------------------------------------------------------------------------------

/// <exception cref="Win32Exception" />
public static bool Free<T>([HOptional] IntPtr ptrAllocatedBuffer) where T: struct
{
   if ( ptrAllocatedBuffer == IntPtr.Zero )
      return false;
   VerifyAllocatedBufferSize<T>( ptrAllocatedBuffer );
   return Free( ptrAllocatedBuffer );
}

/// <exception cref="Win32Exception" />
public static bool Free<T>( [HOptional][HInterlockedAccess]
                            ref IntPtr ptrAllocatedBuffer ) where T: struct
{
   return Free( HPointer.InterlockedNullValueExchange(ref ptrAllocatedBuffer) );
}

//==================================================================================================

/// <exception cref="ArgumentException" />
static void VerifyAllocatedBufferSize<T>(int sizeInBytes) where T: struct
{
   if ( sizeInBytes < ElementSize<T>() ||
        sizeInBytes % ElementSize<T>() != 0 )
      throw new ArgumentException(
         "Incorrect size of previously allocated structured memory buffer." );
}

/// <exception cref="ArgumentException" />
static void VerifyAllocatedBufferSize<T>(IntPtr ptrAllocatedBuffer) where T: struct
{
   VerifyAllocatedBufferSize<T>(
      GetAllocatedSize( ptrAllocatedBuffer ) );
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
} // HMemory
//**************************************************************************************************

} // CommonHelpers
