//\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
// UserRTX.NET satellite library | Author: Sergei Y.Kitáev
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
using System;
using System.Threading;

#if !WASM
namespace user_rtx { using u = user_rtx;
#else
namespace user_rtx.wasm { using u = user_rtx.wasm;
#endif

/// <summary>
/// Helpers for “System.IntPtr” value type
/// </summary>
public static class iptr {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

public static readonly IntPtr
   Minus1Value = (IntPtr)(-1);

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

public static bool IsZero( IntPtr value ) =>
   value == IntPtr.Zero;

public static bool IsMinus1( IntPtr value ) =>
   value == Minus1Value;

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

public static IntPtr Exchange( [u.volatile_access] ref IntPtr location, IntPtr value )
{
   IntPtr prev = Thread.VolatileRead( ref location );
   Thread.VolatileWrite( ref location, value );
   return prev;
}

public static IntPtr ZeroValueExchange( [u.volatile_access] ref IntPtr location ) =>
   Exchange( ref location, IntPtr.Zero );

public static IntPtr Minus1ValueExchange( [u.volatile_access] ref IntPtr location ) =>
   Exchange( ref location, Minus1Value );

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

public static void Swap( [u.volatile_access] ref IntPtr location_1,
                         [u.volatile_access] ref IntPtr location_2 )
{
   IntPtr temp = Thread.VolatileRead( ref location_1 );
   Thread.VolatileWrite( ref location_1, Thread.VolatileRead(ref location_2) );
   Thread.VolatileWrite( ref location_2, temp );
}

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

public static IntPtr ZeroValueSubstitution( IntPtr value, IntPtr subst ) =>
   Substitution( value, IntPtr.Zero, subst );

public static IntPtr SubstiteZeroValue( [u.volatile_access] ref IntPtr location, IntPtr subst ) =>
   Replace( ref location, IntPtr.Zero, subst );

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

public static IntPtr Minus1ValueSubstitution( IntPtr value, IntPtr subst ) =>
   Substitution( value, Minus1Value, subst );

public static IntPtr ReplaceMinus1Value( [u.volatile_access] ref IntPtr location, IntPtr subst ) =>
   Replace( ref location, Minus1Value, subst );

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

public static IntPtr Substitution( IntPtr value, IntPtr comparand, IntPtr subst ) =>
   u.val.ValueSubst( value, comparand, subst );

public static IntPtr Replace( [u.volatile_access] ref IntPtr location,
                              IntPtr comparand, IntPtr subst )
{
   IntPtr op = Thread.VolatileRead( ref location );
   if ( op == comparand )
      return op;
   return u.volat.Write( ref location, subst );
}

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

/// <exception cref="PlatformNotSupportedException" />
public static string ToNormalStr( IntPtr value )
{
   switch ( platform.Bitness )
   {
   case 32: return u.int32.ToNormalStr( (Int32)value );
   case 64: return u.int64.ToNormalStr( (Int64)value );
   default: throw u.platform_errors.NOT_SUPPORTED_Auto( typeof(iptr) );
   } // switch
}

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

public static IntPtr InterlockedZeroExchange( [u.interlocked_access] ref IntPtr location ) =>
   Interlocked.Exchange( ref location, IntPtr.Zero );

public static IntPtr InterlockedMinusOneExchange( [u.interlocked_access] ref IntPtr location ) =>
   Interlocked.Exchange( ref location, Minus1Value );

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
} // iptr

} // user_rtx (.wasm)
