// RuntimeForStatic base library | C+- (SysRoutine) | Author: Sergei Y.Kitáev
#include "Precompiled.h"
#include "SharedIncludes.h"
namespace RuntimeForStatic {
//==================================================================================================

void $TLS::Allocate($A,DWORD volatile* pIndex $out) $fatal_error_on_failure
{
   if ( !AllocateNS($ci, pIndex ) )
      $FATAL_ERROR_LAST_SYSTEM();
}
bool $TLS::AllocateNS($A,DWORD volatile* pIndex $out) $last_error
{
   $$VERIFY_POINTER_ARG( pIndex );
   DWORD index = ::TlsAlloc();
   return $Interlocked::Write($ci, pIndex, index ) != TLS_OUT_OF_INDEXES ?
      $SUCCEED_LE() : $SET_FROM_SYSTEM_LE();
}

void $TLS::Free($A, DWORD volatile* pIndex $out $optional_through(TLS_OUT_OF_INDEXES) )
                    $fatal_error_on_failure
{
   $$VERIFY_POINTER_ARG( pIndex );
   DWORD index = $Interlocked::Read($ci, pIndex );
   if ( index != TLS_OUT_OF_INDEXES && !::TlsFree( index ) )
      $FATAL_ERROR_LAST_SYSTEM();
}

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

PVOID $TLS::GetPointer($A,DWORD volatile* pIndex)
{
   $$VERIFY_POINTER_ARG( pIndex );
   PVOID pointer = ::TlsGetValue( VerifyIndexArgument($ci, L"*pIndex", pIndex) );
   if ( !pointer && ::GetLastError() )
      $FATAL_ERROR_LAST_SYSTEM();
   return pointer;
}
PVOID $TLS::StrictGetPointer($A,DWORD volatile* pIndex) $not_null
{
   PVOID pointer = GetPointer($ci, pIndex );
   $$VERIFY_POINTER( pointer );
   return pointer;
}

PVOID $TLS::SetPointer($A,DWORD volatile* pIndex,PVOID pointer $optional) $ret_target
{
   $$VERIFY_POINTER_ARG( pIndex );
   if ( !::TlsSetValue( VerifyIndexArgument($ci, L"*pIndex", pIndex), pointer ) )
      $FATAL_ERROR_LAST_SYSTEM();
   return pointer;
}

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

int $TLS::GetInt32($A,DWORD volatile* pIndex)
{
   return $tls::GetValue<int>($ci, pIndex );
}
int $TLS::SetInt32($A,DWORD volatile* pIndex,int value) $ret_target
{
   return $tls::SetValue<int>($ci, pIndex, value );
}

unsigned int $TLS::GetUInt32($A,DWORD volatile* pIndex)
{
   return $tls::GetValue<unsigned int>($ci, pIndex );
}
unsigned int $TLS::SetUInt32($A,DWORD volatile* pIndex,unsigned int value) $ret_target
{
   return $tls::SetValue<unsigned int>($ci, pIndex, value );
}

bool $TLS::GetAsBool($A,DWORD volatile* pIndex)
{
   return $BOOL( GetPointer($ci, pIndex ) );
}
bool $TLS::SetAsBool($A,DWORD volatile* pIndex,bool value) $ret_target
{
   return $BOOL( SetPointer($ci, pIndex, (PVOID)$BOOL( value )) );
}

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

bool $TLS::IsInitialized($A,DWORD volatile* pIndex)
{
   $$VERIFY_POINTER_ARG( pIndex );
   return $Interlocked::Read($ci, pIndex ) != TLS_OUT_OF_INDEXES;
}

PVOID $TLS::GetPointerIfInitialized($A,DWORD volatile* pIndex) $or_null
{
   $$VERIFY_POINTER_ARG( pIndex );
   DWORD slotIndex = $Interlocked::Read($ci, pIndex );
   if ( slotIndex == TLS_OUT_OF_INDEXES )
      return nullptr;
   PVOID pointer = ::TlsGetValue( slotIndex );
   if ( !pointer && ::GetLastError() )
      $FATAL_ERROR_LAST_SYSTEM();
   return pointer;
}
int $TLS::GetInt32IfInitialized($A,DWORD volatile* pIndex) $or_zero
{
   return $tls::GetValueIfInitialized<int>($ci, pIndex );
}
unsigned int $TLS::GetUInt32IfInitialized($A,DWORD volatile* pIndex) $or_zero
{
   return $tls::GetValueIfInitialized<unsigned int>($ci, pIndex );
}
bool $TLS::GetAsBoolIfInitialized($A,DWORD volatile* pIndex) $or_zero
{
   return $BOOL( GetPointerIfInitialized($ci, pIndex ) );
}

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

DWORD $TLS::VerifyIndexArgument($A,PCWSTR argumentVarName,DWORD volatile* pIndex)
{
   $$VERIFY_POINTER_ARG( argumentVarName );
   return VerifyIndexValue($ci, argumentVarName, $Interlocked::Read($ci, pIndex ) );
}

DWORD $TLS::VerifyIndexValue($A,PCWSTR argumentVarName,DWORD slotIndex)
{
   if ( slotIndex == TLS_OUT_OF_INDEXES )
      $FatalError::RaiseIncorrectArgumentWithMessageFmt($$CI, argumentVarName, $TEXT(
         L"Incorrect TLS-index value: TLS_OUT_OF_INDEXES (0x%.8X).",
         L"Некорректное значение индекса “TLS”: TLS_OUT_OF_INDEXES (0x%.8X)." ),
         slotIndex );
   return slotIndex;
}

//==================================================================================================
} // RuntimeForStatic
