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

$AutoFreePtr::$AutoFreePtr()
{
   ResetSuperstructure();
   ValidateDisposable($$);
}
$AutoFreePtr::$AutoFreePtr($A, PVOID pointer )
: $AutoFreePtr($ci, pointer, nullptr )
{}
$AutoFreePtr::$AutoFreePtr($A, PVOID pointer,
                               $MemFreeRoutine specialFreeRoutine $optional )
{
   $$VERIFY_POINTER_ARG( pointer );
   ResetSuperstructure();
   _Pointer_ = pointer;
   _SpecialFreeRoutine_ = specialFreeRoutine;
   ValidateDisposable($$);
}

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

$AutoFreePtr& $AutoFreePtr::operator = ($AutoFreePtr& predecessor) $owner_transfer
{
   $memory::Copy($, &predecessor, this );
   if ( predecessor.IsValidDisposable )
   {
      predecessor._Pointer_ = nullptr;
      predecessor.Dispose();
   }
   return *this;
}

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

void $AutoFreePtr::DoDispose($CI_REF)
{
   Free();
}

void $AutoFreePtr::ResetSuperstructure()
{
   _Pointer_ = nullptr;
   _SpecialFreeRoutine_ = nullptr;
}

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

PVOID $AutoFreePtr::P($O) const $alias("Pointer") $strict_result
{
   $$VERIFY_VALID_DISPOSABLE();
   VerifyHasPointer($ci);
   return _Pointer_;
}

bool $AutoFreePtr::GetHasPointer() const
{
   return IsValidDisposable && $BOOL( _Pointer_ );
}

void $AutoFreePtr::VerifyHasPointer($O) const $fatal_error_on_failure
{
   $$VERIFY_VALID_DISPOSABLE();
   if ( !HasPointer )
      $INVALID_OPERATION_WITH_MESSAGE( $TEXT(
         L"Pointer is not attached ($AutoFreePtr).",
         L"Указатель не подключен ($AutoFreePtr)." ));
}

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

PVOID $AutoFreePtr::AttachPointer($OA, PVOID pointer )
                                       $imaginary_param("freePrevious",true)
                                       $ret_target
{
   return AttachPointer($ci, true, pointer );
}
PVOID $AutoFreePtr::AttachPointer($OA, PVOID pointer,
                                       $MemFreeRoutine specialFreeRoutine $optional )
                                       $imaginary_param("freePrevious",true)
                                       $ret_target
{
   return AttachPointer($ci, true, pointer, specialFreeRoutine );
}

PVOID $AutoFreePtr::AttachPointer($OA, bool freePrevious, PVOID pointer $optional ) $ret_target
{
   return AttachPointer($ci, freePrevious, pointer, nullptr );
}
PVOID $AutoFreePtr::AttachPointer($OA, bool freePrevious, PVOID pointer $optional,
                                       $MemFreeRoutine specialFreeRoutine $optional ) $ret_target
{
   $$VERIFY_VALID_DISPOSABLE();
   if ( freePrevious )
      Free();
   else
      ResetSuperstructure();
   _Pointer_ = pointer;
   _SpecialFreeRoutine_ = specialFreeRoutine;
   return pointer;
}

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

PVOID $AutoFreePtr::DetachPointer() $or_null $ret_previous
{
   if ( !HasPointer )
      return nullptr;
   PVOID pointer = _Pointer_;
   ResetSuperstructure();
   return pointer;
}

PVOID $AutoFreePtr::TakePointerOwnership($O) $not_null $ret_previous $needs_free
{
   VerifyHasPointer($$CI);
   return DetachPointer();
}

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

void $AutoFreePtr::Free()
{
   if ( !IsValidDisposable )
      return;
   PVOID pointer = _Pointer_;
   if ( pointer )
   {
      auto specialFreeRoutine = _SpecialFreeRoutine_;
      ResetSuperstructure();
      InvalidateDisposable();
      if ( specialFreeRoutine )
         specialFreeRoutine( pointer );
      else
         $Memory::Free( pointer );
   }
}

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