/**
 * @file      sys.Mutex.hpp
 * @author    Sergey Baigudin, sergey@baigudin.software
 * @copyright 2022, Sergey Baigudin, Baigudin Software
 */
#ifndef SYS_MUTEX_HPP_
#define SYS_MUTEX_HPP_

#include "sys.NonCopyable.hpp"
#include "api.Mutex.hpp"

namespace eoos
{
namespace sys
{

/**
 * @class Mutex.
 * @brief Mutex class.
 */
class Mutex : public NonCopyable, public api::Mutex
{
    using Parent = NonCopyable;

public:

    /**
     * @brief Constructor.
     */
    Mutex() noexcept 
        : NonCopyable()
        , api::Mutex() {
        bool_t const isConstructed{ construct() };
        setConstructed( isConstructed );
    }

    /**
     * @brief Destructor.
     */
    ~Mutex() noexcept override
    {
        ::DeleteCriticalSection(pcs_);
    }

    /**
     * @copydoc eoos::api::Object::isConstructed()
     */
    bool_t isConstructed() const noexcept override ///< SCA AUTOSAR-C++14 Defected Rule A10-2-1
    {
        return Parent::isConstructed();
    }
    
    /**
     * @copydoc eoos::api::Mutex::tryLock()
     */
    bool_t tryLock() noexcept override try
    {
        bool_t res{ false };
        if( isConstructed() )
        {
            res = ::TryEnterCriticalSection(pcs_) != 0;
        }
        return res;
    } catch (...) { ///< UT Justified Branch: OS dependency
        return false;
    }    

    /**
     * @copydoc eoos::api::Mutex::lock()
     */
    bool_t lock() noexcept override try
    {
        bool_t res{ false };
        if( isConstructed() )
        {
            ::EnterCriticalSection(pcs_);
            res = true;
        }
        return res;
    } catch (...) { ///< UT Justified Branch: OS dependency
        return false;
    }

    /**
     * @copydoc eoos::api::Mutex::unlock()
     */
    void unlock() noexcept override try
    {
        if( isConstructed() )
        {
            ::LeaveCriticalSection(pcs_);
        }
    } catch (...) { ///< UT Justified Branch: OS dependency
        return;
    }

private:

    /**
     * @brief Constructor.
     *
     * @return True if object has been constructed successfully.
     */
    bool_t construct() const noexcept try
    {
        bool_t res{ false };
        while(true)
        {   
            if( !isConstructed() )
            {   ///< UT Justified Branch: HW dependency
                break;
            }
            ::DWORD const spinCount{ 4000U };
            ::BOOL const isInitialize{ ::InitializeCriticalSectionAndSpinCount(pcs_, spinCount) };
            if(isInitialize == 0)
            {   ///< UT Justified Branch: OS dependency
                break;
            }
            res = true;
            break;
        }
        return res;
    } catch (...) { ///< UT Justified Branch: OS dependency
        return false;
    }
    
    /**
     * @copydoc eoos::Object::Object(Object const&)
     */
    Mutex(Mutex const&) noexcept = delete;
    
    /**
     * @copydoc eoos::Object::operator=(Object const&)
     */       
    Mutex& operator=(Mutex const&) noexcept = delete;   

    /**
     * @copydoc eoos::Object::Object(Object&&)
     */       
    Mutex(Mutex&&) noexcept = delete;
    
    /**
     * @copydoc eoos::Object::operator=(Object&&)
     */
    Mutex& operator=(Mutex&&) & noexcept = delete;        

    /**
     * @brief Windows critical section object.
     */    
    ::CRITICAL_SECTION cs_{};    

    /**
     * @brief Pointer to Windows critical section object.
     */    
    ::LPCRITICAL_SECTION const pcs_{ &cs_ };    

};

} // namespace sys
} // namespace eoos
#endif // SYS_MUTEX_HPP_

Generated by OpenCppCoverage (Version: 0.9.9.0)