<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p10/procedures/hwp/corecache/p10_hcd_core_stopgrid.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2018,2021                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file  p10_hcd_core_stopgrid.C
/// @brief
///

// *HWP HWP Owner          : David Du         <daviddu@us.ibm.com>
// *HWP Backup HWP Owner   : Greg Still       <stillgs@us.ibm.com>
// *HWP FW Owner           : Prem Shanker Jha <premjha2@in.ibm.com>
// *HWP Team               : PM
// *HWP Consumed by        : SBE:QME
// *HWP Level              : 2
///
// EKB-Mirror-To: hw/ppe

//------------------------------------------------------------------------------
// Includes
//------------------------------------------------------------------------------

#include "p10_hcd_core_stopgrid.H"
#include "p10_hcd_mma_stopclocks.H"
#include "p10_hcd_mma_poweroff.H"
#include "p10_hcd_common.H"

#ifdef __PPE_QME
    #include "p10_ppe_eq.H"
    #include "p10_ppe_c.H"
    using namespace scomt::ppe_eq;
    using namespace scomt::ppe_c;
#else
    #include "p10_scom_eq.H"
    #include "p10_scom_c.H"
    using namespace scomt::eq;
    using namespace scomt::c;
#endif

//------------------------------------------------------------------------------
// Constant Definitions
//------------------------------------------------------------------------------

enum P10_HCD_CORE_STOPGRID_CONSTANTS
{
    HCD_ECL2_CLK_SYNC_DROP_POLL_TIMEOUT_HW_NS                   = 10000,   // 10^4ns = 10us timeout
    HCD_ECL2_CLK_SYNC_DROP_POLL_DELAY_HW_NS                     = 100,     // 100ns poll loop delay
    HCD_ECL2_CLK_SYNC_DROP_POLL_DELAY_SIM_CYCLE                 = 3200,    // 3.2k sim cycle delay
    HCD_CORE_CHANGE_DONE_RESCLK_ENTRY_POLL_TIMEOUT_HW_NS        = 100000000, // 10^4ns = 10us timeout
    HCD_CORE_CHANGE_DONE_RESCLK_ENTRY_POLL_DELAY_HW_NS          = 100,     // 100ns poll loop delay
    HCD_CORE_CHANGE_DONE_RESCLK_ENTRY_POLL_DELAY_SIM_CYCLE      = 3200,    // 3.2k sim cycle delay
};

//------------------------------------------------------------------------------
// Procedure: p10_hcd_core_stopgrid
//------------------------------------------------------------------------------

fapi2::ReturnCode
p10_hcd_core_stopgrid(
    const fapi2::Target < fapi2::TARGET_TYPE_CORE | fapi2::TARGET_TYPE_MULTICAST, fapi2::MULTICAST_AND > & i_target)
{
    fapi2::Target < fapi2::TARGET_TYPE_EQ | fapi2::TARGET_TYPE_MULTICAST, fapi2::MULTICAST_AND > eq_target =
        i_target.getParent < fapi2::TARGET_TYPE_EQ | fapi2::TARGET_TYPE_MULTICAST > ();
    fapi2::buffer<buffer_t> l_mmioData = 0;
    fapi2::buffer<uint64_t> l_scomData = 0;
    uint32_t                l_timeout  = 0;
    uint32_t                l_core_change_done = 0;
    uint32_t                l_regions  = i_target.getCoreSelect();
    fapi2::Target < fapi2::TARGET_TYPE_SYSTEM > l_sys;
    fapi2::ATTR_RUNN_MODE_Type                  l_attr_runn_mode;
    FAPI_TRY( FAPI_ATTR_GET( fapi2::ATTR_RUNN_MODE, l_sys, l_attr_runn_mode ) );

    FAPI_INF(">>p10_hcd_core_stopgrid");

    // also stop mma clocks after/with core clocks
    // not part of core_stopclocks for its pure usage at p10_stopclocks
    // shared with both stop11 and stop3 path
    FAPI_TRY( p10_hcd_mma_stopclocks( i_target ) );

    //also shutdown mma power here as for WOF benefit
    //always turn off MMA if it becomes unavailable
    FAPI_TRY( p10_hcd_mma_poweroff( i_target ) );

    FAPI_DBG("Disable ECL2 Skewadjust via CPMS_CGCSR_[1:CL2_CLK_SYNC_ENABLE]");
    FAPI_TRY( HCD_PUTMMIO_S( i_target, CPMS_CGCSR_WO_CLEAR, BIT64(1) ) );

    FAPI_DBG("Check ECL2 Skewadjust Removed via CPMS_CGCSR[33:CL2_CLK_SYNC_DONE]");
    l_timeout = HCD_ECL2_CLK_SYNC_DROP_POLL_TIMEOUT_HW_NS /
                HCD_ECL2_CLK_SYNC_DROP_POLL_DELAY_HW_NS;

    do
    {
        FAPI_TRY( HCD_GETMMIO_S( i_target, CPMS_CGCSR, l_scomData ) );

        // use multicastOR to check 0
        if( ( !l_attr_runn_mode ) &&
            ( SCOM_GET(33) == 0 ) )
        {
            break;
        }

        fapi2::delay(HCD_ECL2_CLK_SYNC_DROP_POLL_DELAY_HW_NS,
                     HCD_ECL2_CLK_SYNC_DROP_POLL_DELAY_SIM_CYCLE);
    }
    while( (--l_timeout) != 0 );

    FAPI_ASSERT( ( l_attr_runn_mode ? ( SCOM_GET(33) == 0 ) : (l_timeout != 0) ),
                 fapi2::ECL2_CLK_SYNC_DROP_TIMEOUT()
                 .set_ECL2_CLK_SYNC_DROP_POLL_TIMEOUT_HW_NS(HCD_ECL2_CLK_SYNC_DROP_POLL_TIMEOUT_HW_NS)
                 .set_CPMS_CGCSR(l_scomData)
                 .set_CORE_TARGET(i_target),
                 "ERROR: ECL2 Clock Sync Drop Timeout");

    FAPI_DBG("Assert CORE_OFF_REQ[0:3] of Resonent Clocking via RCSCR[0:3]");
    FAPI_TRY( HCD_PUTMMIO_Q( eq_target, QME_RCSCR_WO_OR, MMIO_LOAD32H( ( l_regions << SHIFT32(3) ) ) ) );

    FAPI_DBG("Poll for CORE_CHANGE_DONE in RCSR[4:7]");
    l_timeout = HCD_CORE_CHANGE_DONE_RESCLK_ENTRY_POLL_TIMEOUT_HW_NS /
                HCD_CORE_CHANGE_DONE_RESCLK_ENTRY_POLL_DELAY_HW_NS;

    do
    {
        FAPI_TRY( HCD_GETMMIO_Q( eq_target, QME_RCSCR, l_mmioData ) );

        MMIO_EXTRACT(4, 4, l_core_change_done);

        if( ( !l_attr_runn_mode ) &&
            ( (l_core_change_done & l_regions) == l_regions) )
        {
            break;
        }

        fapi2::delay(HCD_CORE_CHANGE_DONE_RESCLK_ENTRY_POLL_DELAY_HW_NS,
                     HCD_CORE_CHANGE_DONE_RESCLK_ENTRY_POLL_DELAY_SIM_CYCLE);
    }
    while( (--l_timeout) != 0 );

    FAPI_ASSERT( ( l_attr_runn_mode ? ((l_core_change_done & l_regions) == l_regions) : (l_timeout != 0)),
                 fapi2::CORE_CHANGE_DONE_RESCLK_ENTRY_TIMEOUT()
                 .set_CORE_CHANGE_DONE_RESCLK_ENTRY_POLL_TIMEOUT_HW_NS(HCD_CORE_CHANGE_DONE_RESCLK_ENTRY_POLL_TIMEOUT_HW_NS)
                 .set_CORE_CHANGE_DONE(l_core_change_done)
                 .set_CORE_SELECT(l_regions)
                 .set_CORE_TARGET(i_target),
                 "ERROR: Core Resclk Change Done Entry Timeout");

    FAPI_DBG("Switch glsmux to refclk to save clock grid power via CPMS_CGCSR[11]");
    FAPI_TRY( HCD_PUTMMIO_S( i_target, CPMS_CGCSR_WO_CLEAR, BIT64(11) ) );

fapi_try_exit:

    FAPI_INF("<<p10_hcd_core_stopgrid");

    return fapi2::current_err;

}
<commit_msg>QME: improve stop2 latency<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p10/procedures/hwp/corecache/p10_hcd_core_stopgrid.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2018,2021                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file  p10_hcd_core_stopgrid.C
/// @brief
///

// *HWP HWP Owner          : David Du         <daviddu@us.ibm.com>
// *HWP Backup HWP Owner   : Greg Still       <stillgs@us.ibm.com>
// *HWP FW Owner           : Prem Shanker Jha <premjha2@in.ibm.com>
// *HWP Team               : PM
// *HWP Consumed by        : SBE:QME
// *HWP Level              : 2
///
// EKB-Mirror-To: hw/ppe

//------------------------------------------------------------------------------
// Includes
//------------------------------------------------------------------------------

#include "p10_hcd_core_stopgrid.H"
#include "p10_hcd_mma_stopclocks.H"
#include "p10_hcd_mma_poweroff.H"
#include "p10_hcd_common.H"

#ifdef __PPE_QME
    #include "p10_ppe_eq.H"
    #include "p10_ppe_c.H"
    using namespace scomt::ppe_eq;
    using namespace scomt::ppe_c;
#else
    #include "p10_scom_eq.H"
    #include "p10_scom_c.H"
    using namespace scomt::eq;
    using namespace scomt::c;
#endif

//------------------------------------------------------------------------------
// Constant Definitions
//------------------------------------------------------------------------------

enum P10_HCD_CORE_STOPGRID_CONSTANTS
{
    HCD_ECL2_CLK_SYNC_DROP_POLL_TIMEOUT_HW_NS                   = 10000,   // 10^4ns = 10us timeout
    HCD_ECL2_CLK_SYNC_DROP_POLL_DELAY_HW_NS                     = 100,     // 100ns poll loop delay
    HCD_ECL2_CLK_SYNC_DROP_POLL_DELAY_SIM_CYCLE                 = 3200,    // 3.2k sim cycle delay
    HCD_CORE_CHANGE_DONE_RESCLK_ENTRY_POLL_TIMEOUT_HW_NS        = 100000000, // 10^4ns = 10us timeout
    HCD_CORE_CHANGE_DONE_RESCLK_ENTRY_POLL_DELAY_HW_NS          = 100,     // 100ns poll loop delay
    HCD_CORE_CHANGE_DONE_RESCLK_ENTRY_POLL_DELAY_SIM_CYCLE      = 3200,    // 3.2k sim cycle delay
};

//------------------------------------------------------------------------------
// Procedure: p10_hcd_core_stopgrid
//------------------------------------------------------------------------------

fapi2::ReturnCode
p10_hcd_core_stopgrid(
    const fapi2::Target < fapi2::TARGET_TYPE_CORE | fapi2::TARGET_TYPE_MULTICAST, fapi2::MULTICAST_AND > & i_target)
{
    fapi2::Target < fapi2::TARGET_TYPE_EQ | fapi2::TARGET_TYPE_MULTICAST, fapi2::MULTICAST_AND > eq_target =
        i_target.getParent < fapi2::TARGET_TYPE_EQ | fapi2::TARGET_TYPE_MULTICAST > ();
    fapi2::buffer<buffer_t> l_mmioData = 0;
    fapi2::buffer<uint64_t> l_scomData = 0;
    uint32_t                l_timeout  = 0;
    uint32_t                l_core_change_done = 0;
    uint32_t                l_regions  = i_target.getCoreSelect();
    uint8_t                 l_attr_mma_poweroff_disable = 0;
    fapi2::Target < fapi2::TARGET_TYPE_SYSTEM > l_sys;
    fapi2::ATTR_RUNN_MODE_Type                  l_attr_runn_mode;
    FAPI_TRY( FAPI_ATTR_GET( fapi2::ATTR_RUNN_MODE, l_sys, l_attr_runn_mode ) );
    FAPI_TRY( FAPI_ATTR_GET( fapi2::ATTR_SYSTEM_MMA_POWEROFF_DISABLE, l_sys, l_attr_mma_poweroff_disable ) );

    FAPI_INF(">>p10_hcd_core_stopgrid");

    // Also stop mma clocks after/with core clocks
    // not part of core_stopclocks for its pure usage at p10_stopclocks
    // this hwp is shared stop2,3,11 path
    FAPI_TRY( p10_hcd_mma_stopclocks( i_target ) );

    if( !l_attr_mma_poweroff_disable )
    {
        //also shutdown mma power here as for WOF benefit
        //only do so when dynamic mode is enabled
        FAPI_TRY( p10_hcd_mma_poweroff( i_target ) );
    }

    FAPI_DBG("Disable ECL2 Skewadjust via CPMS_CGCSR_[1:CL2_CLK_SYNC_ENABLE]");
    FAPI_TRY( HCD_PUTMMIO_S( i_target, CPMS_CGCSR_WO_CLEAR, BIT64(1) ) );

    FAPI_DBG("Check ECL2 Skewadjust Removed via CPMS_CGCSR[33:CL2_CLK_SYNC_DONE]");
    l_timeout = HCD_ECL2_CLK_SYNC_DROP_POLL_TIMEOUT_HW_NS /
                HCD_ECL2_CLK_SYNC_DROP_POLL_DELAY_HW_NS;

    do
    {
        FAPI_TRY( HCD_GETMMIO_S( i_target, CPMS_CGCSR, l_scomData ) );

        // use multicastOR to check 0
        if( ( !l_attr_runn_mode ) &&
            ( SCOM_GET(33) == 0 ) )
        {
            break;
        }

        fapi2::delay(HCD_ECL2_CLK_SYNC_DROP_POLL_DELAY_HW_NS,
                     HCD_ECL2_CLK_SYNC_DROP_POLL_DELAY_SIM_CYCLE);
    }
    while( (--l_timeout) != 0 );

    FAPI_ASSERT( ( l_attr_runn_mode ? ( SCOM_GET(33) == 0 ) : (l_timeout != 0) ),
                 fapi2::ECL2_CLK_SYNC_DROP_TIMEOUT()
                 .set_ECL2_CLK_SYNC_DROP_POLL_TIMEOUT_HW_NS(HCD_ECL2_CLK_SYNC_DROP_POLL_TIMEOUT_HW_NS)
                 .set_CPMS_CGCSR(l_scomData)
                 .set_CORE_TARGET(i_target),
                 "ERROR: ECL2 Clock Sync Drop Timeout");

    FAPI_DBG("Assert CORE_OFF_REQ[0:3] of Resonent Clocking via RCSCR[0:3]");
    FAPI_TRY( HCD_PUTMMIO_Q( eq_target, QME_RCSCR_WO_OR, MMIO_LOAD32H( ( l_regions << SHIFT32(3) ) ) ) );

    FAPI_DBG("Poll for CORE_CHANGE_DONE in RCSR[4:7]");
    l_timeout = HCD_CORE_CHANGE_DONE_RESCLK_ENTRY_POLL_TIMEOUT_HW_NS /
                HCD_CORE_CHANGE_DONE_RESCLK_ENTRY_POLL_DELAY_HW_NS;

    do
    {
        FAPI_TRY( HCD_GETMMIO_Q( eq_target, QME_RCSCR, l_mmioData ) );

        MMIO_EXTRACT(4, 4, l_core_change_done);

        if( ( !l_attr_runn_mode ) &&
            ( (l_core_change_done & l_regions) == l_regions) )
        {
            break;
        }

        fapi2::delay(HCD_CORE_CHANGE_DONE_RESCLK_ENTRY_POLL_DELAY_HW_NS,
                     HCD_CORE_CHANGE_DONE_RESCLK_ENTRY_POLL_DELAY_SIM_CYCLE);
    }
    while( (--l_timeout) != 0 );

    FAPI_ASSERT( ( l_attr_runn_mode ? ((l_core_change_done & l_regions) == l_regions) : (l_timeout != 0)),
                 fapi2::CORE_CHANGE_DONE_RESCLK_ENTRY_TIMEOUT()
                 .set_CORE_CHANGE_DONE_RESCLK_ENTRY_POLL_TIMEOUT_HW_NS(HCD_CORE_CHANGE_DONE_RESCLK_ENTRY_POLL_TIMEOUT_HW_NS)
                 .set_CORE_CHANGE_DONE(l_core_change_done)
                 .set_CORE_SELECT(l_regions)
                 .set_CORE_TARGET(i_target),
                 "ERROR: Core Resclk Change Done Entry Timeout");

    FAPI_DBG("Switch glsmux to refclk to save clock grid power via CPMS_CGCSR[11]");
    FAPI_TRY( HCD_PUTMMIO_S( i_target, CPMS_CGCSR_WO_CLEAR, BIT64(11) ) );

fapi_try_exit:

    FAPI_INF("<<p10_hcd_core_stopgrid");

    return fapi2::current_err;

}
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p10/procedures/hwp/corecache/p10_hcd_core_stopgrid.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2018,2021                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file  p10_hcd_core_stopgrid.C
/// @brief
///

// *HWP HWP Owner          : David Du         <daviddu@us.ibm.com>
// *HWP Backup HWP Owner   : Greg Still       <stillgs@us.ibm.com>
// *HWP FW Owner           : Prem Shanker Jha <premjha2@in.ibm.com>
// *HWP Team               : PM
// *HWP Consumed by        : SBE:QME
// *HWP Level              : 2
///
// EKB-Mirror-To: hw/ppe

//------------------------------------------------------------------------------
// Includes
//------------------------------------------------------------------------------

#include "p10_hcd_core_stopgrid.H"
#include "p10_hcd_mma_stopclocks.H"
#include "p10_hcd_mma_poweroff.H"
#include "p10_hcd_common.H"

#ifdef __PPE_QME
    #include "p10_ppe_eq.H"
    #include "p10_ppe_c.H"
    using namespace scomt::ppe_eq;
    using namespace scomt::ppe_c;
#else
    #include "p10_scom_eq.H"
    #include "p10_scom_c.H"
    using namespace scomt::eq;
    using namespace scomt::c;
#endif

//------------------------------------------------------------------------------
// Constant Definitions
//------------------------------------------------------------------------------

enum P10_HCD_CORE_STOPGRID_CONSTANTS
{
    HCD_ECL2_CLK_SYNC_DROP_POLL_TIMEOUT_HW_NS                   = 10000,   // 10^4ns = 10us timeout
    HCD_ECL2_CLK_SYNC_DROP_POLL_DELAY_HW_NS                     = 100,     // 100ns poll loop delay
    HCD_ECL2_CLK_SYNC_DROP_POLL_DELAY_SIM_CYCLE                 = 3200,    // 3.2k sim cycle delay
    HCD_CORE_CHANGE_DONE_RESCLK_ENTRY_POLL_TIMEOUT_HW_NS        = 100000000, // 10^4ns = 10us timeout
    HCD_CORE_CHANGE_DONE_RESCLK_ENTRY_POLL_DELAY_HW_NS          = 100,     // 100ns poll loop delay
    HCD_CORE_CHANGE_DONE_RESCLK_ENTRY_POLL_DELAY_SIM_CYCLE      = 3200,    // 3.2k sim cycle delay
};

//------------------------------------------------------------------------------
// Procedure: p10_hcd_core_stopgrid
//------------------------------------------------------------------------------

fapi2::ReturnCode
p10_hcd_core_stopgrid(
    const fapi2::Target < fapi2::TARGET_TYPE_CORE | fapi2::TARGET_TYPE_MULTICAST, fapi2::MULTICAST_AND > & i_target)
{
    fapi2::Target < fapi2::TARGET_TYPE_EQ | fapi2::TARGET_TYPE_MULTICAST, fapi2::MULTICAST_AND > eq_target =
        i_target.getParent < fapi2::TARGET_TYPE_EQ | fapi2::TARGET_TYPE_MULTICAST > ();
    fapi2::buffer<buffer_t> l_mmioData = 0;
    fapi2::buffer<uint64_t> l_scomData = 0;
    uint32_t                l_timeout  = 0;
    uint32_t                l_core_change_done = 0;
    uint32_t                l_regions  = i_target.getCoreSelect();
    uint8_t                 l_attr_mma_poweroff_disable = 0;
    fapi2::Target < fapi2::TARGET_TYPE_SYSTEM > l_sys;
    FAPI_TRY( FAPI_ATTR_GET( fapi2::ATTR_SYSTEM_MMA_POWEROFF_DISABLE, l_sys, l_attr_mma_poweroff_disable ) );
#ifdef USE_RUNN
    fapi2::ATTR_RUNN_MODE_Type                  l_attr_runn_mode;
    FAPI_TRY( FAPI_ATTR_GET( fapi2::ATTR_RUNN_MODE, l_sys, l_attr_runn_mode ) );
#endif

    FAPI_INF(">>p10_hcd_core_stopgrid");

    // Also stop mma clocks after/with core clocks
    // not part of core_stopclocks for its pure usage at p10_stopclocks
    // this hwp is shared stop2,3,11 path
    FAPI_TRY( p10_hcd_mma_stopclocks( i_target ) );

    // PowerON_Dis = 0 and PowerOFF_Dis = 0 do poweroff mma     as in dynamic
    // PowerON_Dis = 0 and PowerOFF_Dis = 1 do not poweroff mma as not in dynamic
    // PowerON_Dis = 1 and PowerOFF_Dis = 0 do poweroff mma     as in dynamic
    // PowerON_Dis = 1 and PowerOFF_Dis = 1 do not poweroff mma as not in dynamic
    if( !l_attr_mma_poweroff_disable )
    {
        //also shutdown mma power here as for WOF benefit
        //only do so when dynamic mode is enabled
        //
        //yes dynamic mode turn off mma power in stop2
        //no need to power off mma in either mma off mode(already off)
        //or static mma mode, as mma needs to remain alive
        //or in sync with stop in such case stop2 only stopclock mma above
        FAPI_TRY( p10_hcd_mma_poweroff( i_target ) );
    }

    FAPI_DBG("Disable ECL2 Skewadjust via CPMS_CGCSR_[1:CL2_CLK_SYNC_ENABLE]");
    FAPI_TRY( HCD_PUTMMIO_S( i_target, CPMS_CGCSR_WO_CLEAR, BIT64(1) ) );

    FAPI_DBG("Check ECL2 Skewadjust Removed via CPMS_CGCSR[33:CL2_CLK_SYNC_DONE]");
    l_timeout = HCD_ECL2_CLK_SYNC_DROP_POLL_TIMEOUT_HW_NS /
                HCD_ECL2_CLK_SYNC_DROP_POLL_DELAY_HW_NS;

    do
    {
        FAPI_TRY( HCD_GETMMIO_S( i_target, CPMS_CGCSR, l_scomData ) );

        // use multicastOR to check 0
        if(
#ifdef USE_RUNN
            ( !l_attr_runn_mode ) &&
#endif
            ( SCOM_GET(33) == 0 ) )
        {
            break;
        }

        fapi2::delay(HCD_ECL2_CLK_SYNC_DROP_POLL_DELAY_HW_NS,
                     HCD_ECL2_CLK_SYNC_DROP_POLL_DELAY_SIM_CYCLE);
    }
    while( (--l_timeout) != 0 );

    HCD_ASSERT4( (
#ifdef USE_RUNN
                     l_attr_runn_mode ? ( SCOM_GET(33) == 0 ) :
#endif
                     (l_timeout != 0) ),
                 ECL2_CLK_SYNC_DROP_TIMEOUT,
                 set_ECL2_CLK_SYNC_DROP_POLL_TIMEOUT_HW_NS, HCD_ECL2_CLK_SYNC_DROP_POLL_TIMEOUT_HW_NS,
                 set_CPMS_CGCSR, l_scomData,
                 set_MC_CORE_TARGET, i_target,
                 set_CORE_SELECT, i_target.getCoreSelect(),
                 "ERROR: ECL2 Clock Sync Drop Timeout");

    FAPI_DBG("Assert CORE_OFF_REQ[0:3] of Resonent Clocking via RCSCR[0:3]");
    FAPI_TRY( HCD_PUTMMIO_Q( eq_target, QME_RCSCR_WO_OR, MMIO_LOAD32H( ( l_regions << SHIFT32(3) ) ) ) );

    FAPI_DBG("Poll for CORE_CHANGE_DONE in RCSR[4:7]");
    l_timeout = HCD_CORE_CHANGE_DONE_RESCLK_ENTRY_POLL_TIMEOUT_HW_NS /
                HCD_CORE_CHANGE_DONE_RESCLK_ENTRY_POLL_DELAY_HW_NS;

    do
    {
        FAPI_TRY( HCD_GETMMIO_Q( eq_target, QME_RCSCR, l_mmioData ) );

        MMIO_EXTRACT(4, 4, l_core_change_done);

        if(
#ifdef USE_RUNN
            ( !l_attr_runn_mode ) &&
#endif
            ( (l_core_change_done & l_regions) == l_regions) )
        {
            break;
        }

        fapi2::delay(HCD_CORE_CHANGE_DONE_RESCLK_ENTRY_POLL_DELAY_HW_NS,
                     HCD_CORE_CHANGE_DONE_RESCLK_ENTRY_POLL_DELAY_SIM_CYCLE);
    }
    while( (--l_timeout) != 0 );

    HCD_ASSERT4( (
#ifdef USE_RUNN
                     l_attr_runn_mode ? ((l_core_change_done & l_regions) == l_regions) :
#endif
                     (l_timeout != 0) ),
                 CORE_CHANGE_DONE_RESCLK_ENTRY_TIMEOUT,
                 set_CORE_CHANGE_DONE_RESCLK_ENTRY_POLL_TIMEOUT_HW_NS, HCD_CORE_CHANGE_DONE_RESCLK_ENTRY_POLL_TIMEOUT_HW_NS,
                 set_CORE_CHANGE_DONE, l_core_change_done,
                 set_MC_CORE_TARGET, i_target,
                 set_CORE_SELECT, i_target.getCoreSelect(),
                 "ERROR: Core Resclk Change Done Entry Timeout");

    FAPI_DBG("Switch glsmux to refclk to save clock grid power via CPMS_CGCSR[11]");
    FAPI_TRY( HCD_PUTMMIO_S( i_target, CPMS_CGCSR_WO_CLEAR, BIT64(11) ) );

fapi_try_exit:

    FAPI_INF("<<p10_hcd_core_stopgrid");

    return fapi2::current_err;

}
<commit_msg>skip stopgrid execution on zero core IOSCM chips<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p10/procedures/hwp/corecache/p10_hcd_core_stopgrid.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2018,2022                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file  p10_hcd_core_stopgrid.C
/// @brief
///

// *HWP HWP Owner          : David Du         <daviddu@us.ibm.com>
// *HWP Backup HWP Owner   : Greg Still       <stillgs@us.ibm.com>
// *HWP FW Owner           : Prem Shanker Jha <premjha2@in.ibm.com>
// *HWP Team               : PM
// *HWP Consumed by        : SBE:QME
// *HWP Level              : 2
///
// EKB-Mirror-To: hw/ppe

//------------------------------------------------------------------------------
// Includes
//------------------------------------------------------------------------------

#include "p10_hcd_core_stopgrid.H"
#include "p10_hcd_mma_stopclocks.H"
#include "p10_hcd_mma_poweroff.H"
#include "p10_hcd_common.H"

#ifdef __PPE_QME
    #include "p10_ppe_eq.H"
    #include "p10_ppe_c.H"
    using namespace scomt::ppe_eq;
    using namespace scomt::ppe_c;
#else
    #include "p10_scom_eq.H"
    #include "p10_scom_c.H"
    using namespace scomt::eq;
    using namespace scomt::c;
#endif

//------------------------------------------------------------------------------
// Constant Definitions
//------------------------------------------------------------------------------

enum P10_HCD_CORE_STOPGRID_CONSTANTS
{
    HCD_ECL2_CLK_SYNC_DROP_POLL_TIMEOUT_HW_NS                   = 10000,   // 10^4ns = 10us timeout
    HCD_ECL2_CLK_SYNC_DROP_POLL_DELAY_HW_NS                     = 100,     // 100ns poll loop delay
    HCD_ECL2_CLK_SYNC_DROP_POLL_DELAY_SIM_CYCLE                 = 3200,    // 3.2k sim cycle delay
    HCD_CORE_CHANGE_DONE_RESCLK_ENTRY_POLL_TIMEOUT_HW_NS        = 100000000, // 10^4ns = 10us timeout
    HCD_CORE_CHANGE_DONE_RESCLK_ENTRY_POLL_DELAY_HW_NS          = 100,     // 100ns poll loop delay
    HCD_CORE_CHANGE_DONE_RESCLK_ENTRY_POLL_DELAY_SIM_CYCLE      = 3200,    // 3.2k sim cycle delay
};

//------------------------------------------------------------------------------
// Procedure: p10_hcd_core_stopgrid
//------------------------------------------------------------------------------

fapi2::ReturnCode
p10_hcd_core_stopgrid(
    const fapi2::Target < fapi2::TARGET_TYPE_CORE | fapi2::TARGET_TYPE_MULTICAST, fapi2::MULTICAST_AND > & i_target)
{
    fapi2::Target < fapi2::TARGET_TYPE_EQ | fapi2::TARGET_TYPE_MULTICAST, fapi2::MULTICAST_AND > eq_target =
        i_target.getParent < fapi2::TARGET_TYPE_EQ | fapi2::TARGET_TYPE_MULTICAST > ();
    fapi2::buffer<buffer_t> l_mmioData = 0;
    fapi2::buffer<uint64_t> l_scomData = 0;
    uint32_t                l_timeout  = 0;
    uint32_t                l_core_change_done = 0;
    uint32_t                l_regions  = i_target.getCoreSelect();
    uint8_t                 l_attr_mma_poweroff_disable = 0;

#ifndef __PPE_QME
    auto l_chip_target = i_target.getParent<fapi2::TARGET_TYPE_PROC_CHIP>();
    fapi2::ATTR_ZERO_CORE_CHIP_Type l_zero_core_chip = 0;
#endif

    fapi2::Target < fapi2::TARGET_TYPE_SYSTEM > l_sys;
    FAPI_TRY( FAPI_ATTR_GET( fapi2::ATTR_SYSTEM_MMA_POWEROFF_DISABLE, l_sys, l_attr_mma_poweroff_disable ) );
#ifdef USE_RUNN
    fapi2::ATTR_RUNN_MODE_Type                  l_attr_runn_mode;
    FAPI_TRY( FAPI_ATTR_GET( fapi2::ATTR_RUNN_MODE, l_sys, l_attr_runn_mode ) );
#endif

    FAPI_INF(">>p10_hcd_core_stopgrid");

#ifndef __PPE_QME
    FAPI_TRY( FAPI_ATTR_GET( fapi2::ATTR_ZERO_CORE_CHIP, l_chip_target, l_zero_core_chip ) );

    if (l_zero_core_chip)
    {
        goto fapi_try_exit;
    }

#endif

    // Also stop mma clocks after/with core clocks
    // not part of core_stopclocks for its pure usage at p10_stopclocks
    // this hwp is shared stop2,3,11 path
    FAPI_TRY( p10_hcd_mma_stopclocks( i_target ) );

    // PowerON_Dis = 0 and PowerOFF_Dis = 0 do poweroff mma     as in dynamic
    // PowerON_Dis = 0 and PowerOFF_Dis = 1 do not poweroff mma as not in dynamic
    // PowerON_Dis = 1 and PowerOFF_Dis = 0 do poweroff mma     as in dynamic
    // PowerON_Dis = 1 and PowerOFF_Dis = 1 do not poweroff mma as not in dynamic
    if( !l_attr_mma_poweroff_disable )
    {
        //also shutdown mma power here as for WOF benefit
        //only do so when dynamic mode is enabled
        //
        //yes dynamic mode turn off mma power in stop2
        //no need to power off mma in either mma off mode(already off)
        //or static mma mode, as mma needs to remain alive
        //or in sync with stop in such case stop2 only stopclock mma above
        FAPI_TRY( p10_hcd_mma_poweroff( i_target ) );
    }

    FAPI_DBG("Disable ECL2 Skewadjust via CPMS_CGCSR_[1:CL2_CLK_SYNC_ENABLE]");
    FAPI_TRY( HCD_PUTMMIO_S( i_target, CPMS_CGCSR_WO_CLEAR, BIT64(1) ) );

    FAPI_DBG("Check ECL2 Skewadjust Removed via CPMS_CGCSR[33:CL2_CLK_SYNC_DONE]");
    l_timeout = HCD_ECL2_CLK_SYNC_DROP_POLL_TIMEOUT_HW_NS /
                HCD_ECL2_CLK_SYNC_DROP_POLL_DELAY_HW_NS;

    do
    {
        FAPI_TRY( HCD_GETMMIO_S( i_target, CPMS_CGCSR, l_scomData ) );

        // use multicastOR to check 0
        if(
#ifdef USE_RUNN
            ( !l_attr_runn_mode ) &&
#endif
            ( SCOM_GET(33) == 0 ) )
        {
            break;
        }

        fapi2::delay(HCD_ECL2_CLK_SYNC_DROP_POLL_DELAY_HW_NS,
                     HCD_ECL2_CLK_SYNC_DROP_POLL_DELAY_SIM_CYCLE);
    }
    while( (--l_timeout) != 0 );

    HCD_ASSERT4( (
#ifdef USE_RUNN
                     l_attr_runn_mode ? ( SCOM_GET(33) == 0 ) :
#endif
                     (l_timeout != 0) ),
                 ECL2_CLK_SYNC_DROP_TIMEOUT,
                 set_ECL2_CLK_SYNC_DROP_POLL_TIMEOUT_HW_NS, HCD_ECL2_CLK_SYNC_DROP_POLL_TIMEOUT_HW_NS,
                 set_CPMS_CGCSR, l_scomData,
                 set_MC_CORE_TARGET, i_target,
                 set_CORE_SELECT, i_target.getCoreSelect(),
                 "ERROR: ECL2 Clock Sync Drop Timeout");

    FAPI_DBG("Assert CORE_OFF_REQ[0:3] of Resonent Clocking via RCSCR[0:3]");
    FAPI_TRY( HCD_PUTMMIO_Q( eq_target, QME_RCSCR_WO_OR, MMIO_LOAD32H( ( l_regions << SHIFT32(3) ) ) ) );

    FAPI_DBG("Poll for CORE_CHANGE_DONE in RCSR[4:7]");
    l_timeout = HCD_CORE_CHANGE_DONE_RESCLK_ENTRY_POLL_TIMEOUT_HW_NS /
                HCD_CORE_CHANGE_DONE_RESCLK_ENTRY_POLL_DELAY_HW_NS;

    do
    {
        FAPI_TRY( HCD_GETMMIO_Q( eq_target, QME_RCSCR, l_mmioData ) );

        MMIO_EXTRACT(4, 4, l_core_change_done);

        if(
#ifdef USE_RUNN
            ( !l_attr_runn_mode ) &&
#endif
            ( (l_core_change_done & l_regions) == l_regions) )
        {
            break;
        }

        fapi2::delay(HCD_CORE_CHANGE_DONE_RESCLK_ENTRY_POLL_DELAY_HW_NS,
                     HCD_CORE_CHANGE_DONE_RESCLK_ENTRY_POLL_DELAY_SIM_CYCLE);
    }
    while( (--l_timeout) != 0 );

    HCD_ASSERT4( (
#ifdef USE_RUNN
                     l_attr_runn_mode ? ((l_core_change_done & l_regions) == l_regions) :
#endif
                     (l_timeout != 0) ),
                 CORE_CHANGE_DONE_RESCLK_ENTRY_TIMEOUT,
                 set_CORE_CHANGE_DONE_RESCLK_ENTRY_POLL_TIMEOUT_HW_NS, HCD_CORE_CHANGE_DONE_RESCLK_ENTRY_POLL_TIMEOUT_HW_NS,
                 set_CORE_CHANGE_DONE, l_core_change_done,
                 set_MC_CORE_TARGET, i_target,
                 set_CORE_SELECT, i_target.getCoreSelect(),
                 "ERROR: Core Resclk Change Done Entry Timeout");

    FAPI_DBG("Switch glsmux to refclk to save clock grid power via CPMS_CGCSR[11]");
    FAPI_TRY( HCD_PUTMMIO_S( i_target, CPMS_CGCSR_WO_CLEAR, BIT64(11) ) );

fapi_try_exit:

    FAPI_INF("<<p10_hcd_core_stopgrid");

    return fapi2::current_err;

}
<|endoftext|>


<commit_before>/*
 * (C) Copyright 2016 Mirantis Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Author:
 *     Radoslaw Zarzynski <rzarzynski@mirantis.com>
 */

#include <cstddef>
#include <type_traits>
#include <tuple>

template <class TypeT, size_t MaxSize>
class static_ptr {
  /* All variants of static_ptr are friends. */
  template <class Tf, size_t Sf> friend class static_ptr;
public:
  typedef TypeT* pointer;
  typedef TypeT element_type;

private:
  /* Virtual constructors for C++... */
  struct LifeCycleManager {
    virtual void clone_obj(void *, TypeT&&) const = 0;
    virtual void clone_lcm(void *) const = 0;

    virtual void delete_obj(TypeT&) const = 0;
  };

  typedef const LifeCycleManager* pointer_lcm;

  unsigned char storage[MaxSize];
  unsigned char storage_lcm[sizeof(LifeCycleManager)];
  bool is_empty = true;

  pointer_lcm get_lcm() noexcept {
    return reinterpret_cast<pointer_lcm>(storage_lcm);
  }

  template <
    class Te,
    class... Args,
    /* Dummy template parameter solely for SFINAE. */
    typename std::enable_if<
      std::is_base_of<TypeT, Te>::value>::type* = nullptr >
  void _emplace(Args&&... args) {
    /* Life cycle manager for the type Te. Due to nesting this class, each
     * instance of the emplace template will receive its own LCM with info
     * about the concrete Te deeply buried inside. That's the way how we
     * support "virtual constructors" and call a proper destructor even if
     * TypeT hasn't declared its dtor as virtual. */
    struct LCMe : public LifeCycleManager {
      virtual void clone_obj(void* p, TypeT&& u) const override {
        new (p) Te(static_cast<Te&&>(u));
      }

      virtual void clone_lcm(void* p) const override {
        new (p) LCMe;
      }

      virtual void delete_obj(TypeT& t) const override {
        static_cast<Te&>(t).~Te();
      }
    };

    /* The storage_lcm shouldn't store anything more than the VPTR. */
    new (storage_lcm) LCMe();
    new (storage) Te(std::forward<Args>(args)...);
    is_empty = false;
  }

  /* Helpers for make_obj. */
  template<int ...> struct seq { };

  template<int N, int ...S>
  struct gens : gens<N-1, N-1, S...> { };

  template<int ...S>
  struct gens<1, S...> {
    typedef seq<S...> type;
  };

  template<class Type, class Tuple, int ...S>
  void _make_obj(Tuple&& tup, seq<S...>) {
    _emplace<Type>(std::get<S>(tup) ...);
  }

  template <class Tf, size_t Sf>
  void _clone(static_ptr<Tf, Sf>&& rhs) {
    typename static_ptr<Tf, Sf>::pointer rhs_obj_ptr = rhs.get();

    if (rhs_obj_ptr) {
      rhs.get_lcm()->clone_obj(storage, std::move(*rhs_obj_ptr));
      rhs.get_lcm()->clone_lcm(storage_lcm);

      /* Using the already std::moved rhs_obj_ptr is fully intensional. */
      rhs.is_empty = true;
      rhs.get_lcm()->delete_obj(*rhs_obj_ptr);

      this->is_empty = false;
    }
  }

public:
  /* All necessary things are initialized in the definitions. NOTE: we won't
   * zeroize or touch the storage in any other way as the only thing it could
   * bring is an impact on performance. */
  static_ptr() noexcept = default;

  /* Constructor: the nullptr case. */
  static_ptr(nullptr_t) noexcept : static_ptr() {};

  /* Constructor: move from another instance of absolutely the same
   * variant of static_ptr. In other words, rhs must be an instance
   * of static<TypeT, MaxSize). The constructor is present only because
   * of the Return Value Optimization.  */
  static_ptr(static_ptr&& rhs) {
    _clone(std::move(rhs));
  }

  /* Constructor: move from a compatible variant of static_ptr. Variants
   * are compatible only if:
   *  1) a source one is smaller or equal in terms of available storage
   *     size than a destination one AND
   *  2) a destination one encapsulates a type that stays in is_base_of
   *     relationship with type stored by a source one. */
  template <class Tf, size_t Sf>
  static_ptr(static_ptr<Tf, Sf>&& rhs) {
    static_assert(MaxSize >= Sf,
                  "constructed from too big static_ptr instance");
    static_assert(std::is_base_of<TypeT, Tf>::value,
                  "constructed from non-related static_ptr instance");

    _clone(std::move(rhs));
  }

  /* Constructor: the from-make_static case. */
  template <class T>
  static_ptr(T&& tup) {
    using TypePtr = typename std::tuple_element<0, T>::type;
    using Type    = typename std::remove_pointer<TypePtr>::type;

    constexpr size_t tup_size = std::tuple_size<T>::value;

    _make_obj<Type>(std::move(tup), typename gens< tup_size >::type());
  }

  /* Assignment: move from a compatible variant of static_ptr. For details
   * please refer to the documentation of the corresponding constructor. */
  template <class Tf, size_t Sf>
  static_ptr& operator=(static_ptr<Tf, Sf>&& rhs) {
    static_assert(MaxSize >= Sf,
                  "assigned from too big static_ptr instance");
    static_assert(std::is_base_of<TypeT, Tf>::value,
                  "assigned from non-related static_ptr instance");

    /* First, release (destroy) the currently stored object if necessary. */
    pointer this_obj_ptr = this->get();
    if (this_obj_ptr) {
      this->get_lcm()->delete_obj(*this_obj_ptr);
      this->is_empty = true;
    }

    /* Second, MoveConstruct a new object using our own storage but basing
     * on the object hold by rhs. */
    _clone(std::move(rhs));

    return *this;
  }

  /* Let's mimic the std::unique_ptr's behaviour. It's very useful to say to
   * the world who controls the lifetime of the contained object. */
  static_ptr(const static_ptr&) = delete;
  static_ptr& operator=(const static_ptr&) = delete;

  ~static_ptr() {
    auto obj = get();
    if (obj) {
      get_lcm()->delete_obj(*obj);
    }
  }

  TypeT* operator->() {
    return get();
  }

  pointer get() noexcept {
    return is_empty ? nullptr : reinterpret_cast<pointer>(storage);
  }

  template <
    class Te,
    class... Args,
    /* Dummy template parameter solely for SFINAE. */
    typename std::enable_if<
      std::is_base_of<TypeT, Te>::value>::type* = nullptr >
  bool emplace(Args&&... args) {
    /* The public emplace method can be called on empty static_pointer only. */
    if (is_empty) {
      _emplace<Te>(std::forward<Args>(args)...);
    }
    return is_empty;
  }
};

template <class First>
constexpr size_t maxsizeof() {
  return sizeof(First);
}

template <class First, class Second, class... Args>
constexpr size_t maxsizeof() {
  return maxsizeof<First>() > maxsizeof<Second, Args...>()
                            ? maxsizeof<First>()
                            : maxsizeof<Second, Args...>();
}

/* C++ doesn't allow to explicitly specify parameters for template constructor
 * of a class template. They can be deduced only. Because of the restriction we
 * need a helper function to construct an instance of static_ptr::element_type
 * directly in the memory under static_ptr::storage_obj - without spawning any
 * temporary of static_ptr::element_type along the way.
 *
 * The idea is to prepare a std::tuple containing all information necessary to
 * create an object in its final destination and pass it to specific template
 * constructor of static_ptr that can live with the deduction-only limitation.
 * The std::tuple object should be optimized out thanks to the RVO.
 *
 * Another benefit is the similarity to std::make_shared and std::make_unique
 * functions. */
template <class T, class... Args>
std::tuple<T*, Args...> make_static(Args&&... args)
{
  /* As C++ doesn't offer a template constructor for a class template it's
   * impossible to construct the static_ptr::element_type inside  */
  return std::forward_as_tuple(static_cast<T*>(nullptr),
                               std::forward<Args>(args)...);
}
<commit_msg>Improve naming and const-correctness in static_ptr.hpp.<commit_after>/*
 * (C) Copyright 2016 Mirantis Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Author:
 *     Radoslaw Zarzynski <rzarzynski@mirantis.com>
 */

#include <cstddef>
#include <type_traits>
#include <tuple>

template <class TypeT, size_t MaxSize>
class static_ptr {
  /* All variants of static_ptr are friends. */
  template <class Tf, size_t Sf> friend class static_ptr;
public:
  typedef TypeT* pointer;
  typedef TypeT element_type;
  static constexpr size_t element_max_size = MaxSize;

private:
  /* Virtual constructors for C++... */
  struct LifeCycleManager {
    virtual void clone_obj(void *, element_type&&) const = 0;
    virtual void clone_lcm(void *) const = 0;

    virtual void delete_obj(element_type&) const = 0;
  };

  mutable unsigned char storage_obj[element_max_size];
  unsigned char storage_lcm[sizeof(LifeCycleManager)];
  bool is_empty = true;

  const LifeCycleManager& get_lcm() noexcept {
    return *reinterpret_cast<const LifeCycleManager*>(storage_lcm);
  }

  template <
    class Te,
    class... Args,
    /* Dummy template parameter solely for SFINAE. */
    typename std::enable_if<
      std::is_base_of<element_type, Te>::value>::type* = nullptr >
  void _emplace(Args&&... args) {
    /* Life cycle manager for the type Te. Due to nesting this class, each
     * instance of the emplace template will receive its own LCM with info
     * about the concrete Te deeply buried inside. That's the way how we
     * support "virtual constructors" and call a proper destructor even if
     * element_type hasn't declared its dtor as virtual. */
    struct LCMe : public LifeCycleManager {
      virtual void clone_obj(void* p, element_type&& u) const override {
        new (p) Te(static_cast<Te&&>(u));
      }

      virtual void clone_lcm(void* p) const override {
        new (p) LCMe;
      }

      virtual void delete_obj(element_type& t) const override {
        static_cast<Te&>(t).~Te();
      }
    };

    /* The storage_lcm shouldn't store anything more than the VPTR. */
    new (storage_lcm) LCMe();
    new (storage_obj) Te(std::forward<Args>(args)...);
    is_empty = false;
  }

  /* Helpers for make_obj. */
  template<int ...> struct seq { };

  template<int N, int ...S>
  struct gens : gens<N-1, N-1, S...> { };

  template<int ...S>
  struct gens<1, S...> {
    typedef seq<S...> type;
  };

  template<class Type, class Tuple, int ...S>
  void _make_obj(Tuple&& tup, seq<S...>) {
    _emplace<Type>(std::get<S>(tup) ...);
  }

  template <class Tf, size_t Sf>
  void _transfer_obj(static_ptr<Tf, Sf>&& rhs) {
    typename static_ptr<Tf, Sf>::pointer rhs_obj_ptr = rhs.get();

    if (rhs_obj_ptr) {
      rhs.get_lcm().clone_obj(storage_obj, std::move(*rhs_obj_ptr));
      rhs.get_lcm().clone_lcm(storage_lcm);

      /* Using the already std::moved rhs_obj_ptr is fully intensional. */
      rhs.is_empty = true;
      rhs.get_lcm().delete_obj(*rhs_obj_ptr);

      this->is_empty = false;
    }
  }

public:
  /* All necessary things are initialized in the definitions. NOTE: we won't
   * zeroize or touch the storage in any other way as the only thing it could
   * bring is an impact on performance. */
  static_ptr() noexcept = default;

  /* Constructor: the nullptr case. */
  static_ptr(nullptr_t) noexcept : static_ptr() {};

  /* Constructor: move from another instance of absolutely the same
   * variant of static_ptr. In other words, rhs must be an instance
   * of static<TypeT, MaxSize). The constructor is present only because
   * of the Return Value Optimization.  */
  static_ptr(static_ptr&& rhs) {
    _transfer_obj(std::move(rhs));
  }

  /* Constructor: move from a compatible variant of static_ptr. Variants
   * are compatible only if:
   *  1) a source one is smaller or equal in terms of available storage
   *     size than a destination one AND
   *  2) a destination one encapsulates a type that stays in is_base_of
   *     relationship with type stored by a source one. */
  template <class Tf, size_t Sf>
  static_ptr(static_ptr<Tf, Sf>&& rhs) {
    static_assert(element_max_size >= Sf,
                  "constructed from too big static_ptr instance");
    static_assert(std::is_base_of<element_type, Tf>::value,
                  "constructed from non-related static_ptr instance");

    _transfer_obj(std::move(rhs));
  }

  /* Constructor: the from-make_static case. */
  template <class T>
  static_ptr(T&& tup) {
    using TypePtr = typename std::tuple_element<0, T>::type;
    using Type    = typename std::remove_pointer<TypePtr>::type;

    constexpr size_t tup_size = std::tuple_size<T>::value;

    _make_obj<Type>(std::move(tup), typename gens<tup_size>::type());
  }

  /* Assignment: move from a compatible variant of static_ptr. For details
   * please refer to the documentation of the corresponding constructor. */
  template <class Tf, size_t Sf>
  static_ptr& operator=(static_ptr<Tf, Sf>&& rhs) {
    static_assert(element_max_size >= Sf,
                  "assigned from too big static_ptr instance");
    static_assert(std::is_base_of<element_type, Tf>::value,
                  "assigned from non-related static_ptr instance");

    /* First, release (destroy) the currently stored object if necessary. */
    pointer this_obj_ptr = this->get();
    if (this_obj_ptr) {
      this->get_lcm().delete_obj(*this_obj_ptr);
      this->is_empty = true;
    }

    /* Second, MoveConstruct a new object using our own storage but basing
     * on the object hold by rhs. */
    _transfer_obj(std::move(rhs));

    return *this;
  }

  /* Let's mimic the std::unique_ptr's behaviour. It's very useful to say to
   * the world who controls the lifetime of the contained object. */
  static_ptr(const static_ptr&) = delete;
  static_ptr& operator=(const static_ptr&) = delete;

  ~static_ptr() {
    auto obj = get();
    if (obj) {
      get_lcm().delete_obj(*obj);
    }
  }

  pointer operator->() const {
    return get();
  }

  pointer get() const noexcept {
    return is_empty ? nullptr : reinterpret_cast<pointer>(storage_obj);
  }

  template <
    class Te,
    class... Args,
    /* Dummy template parameter solely for SFINAE. */
    typename std::enable_if<
      std::is_base_of<element_type, Te>::value>::type* = nullptr >
  bool emplace(Args&&... args) {
    /* The public emplace method can be called on empty static_pointer only. */
    if (is_empty) {
      _emplace<Te>(std::forward<Args>(args)...);
    }
    return is_empty;
  }
};

template <class First>
constexpr size_t maxsizeof() {
  return sizeof(First);
}

template <class First, class Second, class... Args>
constexpr size_t maxsizeof() {
  return maxsizeof<First>() > maxsizeof<Second, Args...>()
                            ? maxsizeof<First>()
                            : maxsizeof<Second, Args...>();
}

/* C++ doesn't allow to explicitly specify parameters for template constructor
 * of a class template. They can be deduced only. Because of the restriction we
 * need a helper function to construct an instance of static_ptr::element_type
 * directly in the memory under static_ptr::storage_obj - without spawning any
 * temporary of static_ptr::element_type along the way.
 *
 * The idea is to prepare a std::tuple containing all information necessary to
 * create an object in its final destination and pass it to specific template
 * constructor of static_ptr that can live with the deduction-only limitation.
 * The std::tuple object should be optimized out thanks to the RVO.
 *
 * Another benefit is the similarity to std::make_shared and std::make_unique
 * functions. */
template <class T, class... Args>
std::tuple<T*, Args...> make_static(Args&&... args)
{
  /* As C++ doesn't offer a template constructor for a class template it's
   * impossible to construct the static_ptr::element_type inside  */
  return std::forward_as_tuple(static_cast<T*>(nullptr),
                               std::forward<Args>(args)...);
}
<|endoftext|>


<commit_before>/**
 * Zillians MMO
 * Copyright (C) 2007-2011 Zillians.com, Inc.
 * For more information see http://www.zillians.com
 *
 * Zillians MMO is the library and runtime for massive multiplayer online game
 * development in utility computing model, which runs as a service for every
 * developer to build their virtual world running on our GPU-assisted machines.
 *
 * This is a close source library intended to be used solely within Zillians.com
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include "language/tree/basic/Identifier.h"
#include "language/tree/basic/TypeSpecifier.h"
#include "language/tree/declaration/TypenameDecl.h"

namespace zillians { namespace language { namespace tree {

SimpleIdentifier::SimpleIdentifier()
{ }

SimpleIdentifier::SimpleIdentifier(const std::wstring& s) : name(s)
{ }

std::wstring SimpleIdentifier::toString() const
{
	return name;
}

bool SimpleIdentifier::isEmpty() const
{
	return (name.length() == 0);
}

bool SimpleIdentifier::isEqualImpl(const ASTNode& rhs, ASTNodeSet& visited) const
{
	BEGIN_COMPARE()
	COMPARE_MEMBER(name)
	END_COMPARE()
}

bool SimpleIdentifier::replaceUseWith(const ASTNode& from, const ASTNode& to, bool update_parent)
{
	BEGIN_REPLACE()
	REPLACE_USE_WITH(name)
	END_REPLACE()
}

ASTNode* SimpleIdentifier::clone() const
{
	return new SimpleIdentifier(name);
}

} } }

namespace zillians { namespace language { namespace tree {

NestedIdentifier::NestedIdentifier()
{ }

std::wstring NestedIdentifier::toString() const
{
	std::wstring t;

	foreach(i, identifier_list)
	{
		t += (*i)->toString();
		if(!is_end_of_foreach(i, identifier_list))
			t += L".";
	}

	return t;
}

bool NestedIdentifier::isEmpty() const
{
	foreach(i, identifier_list)
	{
		if(!(*i)->isEmpty())
			return false;
	}

	return true;
}

void NestedIdentifier::appendIdentifier(Identifier* id)
{
	id->parent = this;
	identifier_list.push_back(id);
}

bool NestedIdentifier::isEqualImpl(const ASTNode& rhs, ASTNodeSet& visited) const
{
	BEGIN_COMPARE()
	COMPARE_MEMBER(identifier_list)
	END_COMPARE()
}

bool NestedIdentifier::replaceUseWith(const ASTNode& from, const ASTNode& to, bool update_parent)
{
	BEGIN_REPLACE()
	REPLACE_USE_WITH(identifier_list)
	END_REPLACE()
}

ASTNode* NestedIdentifier::clone() const
{
	NestedIdentifier* cloned = new NestedIdentifier();
	foreach(i, identifier_list) cloned->appendIdentifier(cast<Identifier>((*i)->clone()));
	return cloned;
}

} } }

namespace zillians { namespace language { namespace tree {

TemplatedIdentifier::TemplatedIdentifier()
{ }

TemplatedIdentifier::TemplatedIdentifier(Usage::type type, Identifier* id) : type(type), id(id)
{
	id->parent = this;
}

std::wstring TemplatedIdentifier::toString() const
{
	std::wstring t;

	t += id->toString();
	t += L"<";
	foreach(i, templated_type_list)
	{
		t += (*i)->name->toString();
		if((*i)->specialized_type)
		{
			t += L":";
			t += (*i)->specialized_type->toString();
		}
		if(!is_end_of_foreach(i, templated_type_list))
			t += L",";
	}
	t += L">";

	return t;
}

bool TemplatedIdentifier::isVariadic() const
{
	auto last = *templated_type_list.rbegin();
	return last->name->toString() == L"...";
}

bool TemplatedIdentifier::isFullySpecialized() const
{
	foreach(i, templated_type_list)
	{
		if(!(*i)->specialized_type)
		{
			return false;
		}
		else
		{
			if((*i)->specialized_type->type == TypeSpecifier::ReferredType::UNSPECIFIED)
			{
				if(isa<TemplatedIdentifier>((*i)->specialized_type->referred.unspecified))
				{
					if(!cast<TemplatedIdentifier>((*i)->specialized_type->referred.unspecified)->isFullySpecialized())
					{
						return false;
					}
				}
			}
		}
	}
	return true;
}

void TemplatedIdentifier::specialize()
{
	if(type == Usage::FORMAL_PARAMETER)
	{
		foreach(i, templated_type_list)
		{
			if(!(*i)->specialized_type)
			{
				TypeSpecifier* specialized_type = NULL;
				if(isa<TemplatedIdentifier>((*i)->name))
				{
					TemplatedIdentifier* duplicated_id = cast<TemplatedIdentifier>((*i)->name->clone());
					duplicated_id->specialize();
					specialized_type = new TypeSpecifier(duplicated_id);
					specialized_type->parent = this;
				}
				else
				{
					specialized_type = new TypeSpecifier((*i)->name->clone());
					specialized_type->parent = this;
				}

				SimpleIdentifier* dummy_identifier = new SimpleIdentifier(L"_");
				(*i)->replaceUseWith(*((*i)->name), *dummy_identifier);
				(*i)->specialized_type = specialized_type;
			}
		}
	}
}

bool TemplatedIdentifier::isEmpty() const
{
	if(id->isEmpty() && templated_type_list.size() == 0)
		return true;
	else
		return false;
}

void TemplatedIdentifier::setIdentifier(Identifier* identifier)
{
	if(id) id->parent = NULL;
	id = identifier;
	id->parent = this;
}

void TemplatedIdentifier::append(TypenameDecl* type)
{
	type->parent = this;
	templated_type_list.push_back(type);
}

bool TemplatedIdentifier::isEqualImpl(const ASTNode& rhs, ASTNodeSet& visited) const
{
	BEGIN_COMPARE()
	COMPARE_MEMBER(type)
	COMPARE_MEMBER(id)
	COMPARE_MEMBER(templated_type_list)
	END_COMPARE()
}

bool TemplatedIdentifier::replaceUseWith(const ASTNode& from, const ASTNode& to, bool update_parent)
{
	BEGIN_REPLACE()
	REPLACE_USE_WITH(type)
	REPLACE_USE_WITH(id)
	REPLACE_USE_WITH(templated_type_list)
	END_REPLACE()
}

ASTNode* TemplatedIdentifier::clone() const
{
	TemplatedIdentifier* cloned = new TemplatedIdentifier(type, (id) ? cast<Identifier>(id->clone()) : NULL);

	foreach(i, templated_type_list)
		cloned->append(cast<TypenameDecl>((*i)->clone()));

	return cloned;
}

} } }
<commit_msg>Fix restructure specialize wrong parent bug<commit_after>/**
 * Zillians MMO
 * Copyright (C) 2007-2011 Zillians.com, Inc.
 * For more information see http://www.zillians.com
 *
 * Zillians MMO is the library and runtime for massive multiplayer online game
 * development in utility computing model, which runs as a service for every
 * developer to build their virtual world running on our GPU-assisted machines.
 *
 * This is a close source library intended to be used solely within Zillians.com
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include "language/tree/basic/Identifier.h"
#include "language/tree/basic/TypeSpecifier.h"
#include "language/tree/declaration/TypenameDecl.h"

namespace zillians { namespace language { namespace tree {

SimpleIdentifier::SimpleIdentifier()
{ }

SimpleIdentifier::SimpleIdentifier(const std::wstring& s) : name(s)
{ }

std::wstring SimpleIdentifier::toString() const
{
	return name;
}

bool SimpleIdentifier::isEmpty() const
{
	return (name.length() == 0);
}

bool SimpleIdentifier::isEqualImpl(const ASTNode& rhs, ASTNodeSet& visited) const
{
	BEGIN_COMPARE()
	COMPARE_MEMBER(name)
	END_COMPARE()
}

bool SimpleIdentifier::replaceUseWith(const ASTNode& from, const ASTNode& to, bool update_parent)
{
	BEGIN_REPLACE()
	REPLACE_USE_WITH(name)
	END_REPLACE()
}

ASTNode* SimpleIdentifier::clone() const
{
	return new SimpleIdentifier(name);
}

} } }

namespace zillians { namespace language { namespace tree {

NestedIdentifier::NestedIdentifier()
{ }

std::wstring NestedIdentifier::toString() const
{
	std::wstring t;

	foreach(i, identifier_list)
	{
		t += (*i)->toString();
		if(!is_end_of_foreach(i, identifier_list))
			t += L".";
	}

	return t;
}

bool NestedIdentifier::isEmpty() const
{
	foreach(i, identifier_list)
	{
		if(!(*i)->isEmpty())
			return false;
	}

	return true;
}

void NestedIdentifier::appendIdentifier(Identifier* id)
{
	id->parent = this;
	identifier_list.push_back(id);
}

bool NestedIdentifier::isEqualImpl(const ASTNode& rhs, ASTNodeSet& visited) const
{
	BEGIN_COMPARE()
	COMPARE_MEMBER(identifier_list)
	END_COMPARE()
}

bool NestedIdentifier::replaceUseWith(const ASTNode& from, const ASTNode& to, bool update_parent)
{
	BEGIN_REPLACE()
	REPLACE_USE_WITH(identifier_list)
	END_REPLACE()
}

ASTNode* NestedIdentifier::clone() const
{
	NestedIdentifier* cloned = new NestedIdentifier();
	foreach(i, identifier_list) cloned->appendIdentifier(cast<Identifier>((*i)->clone()));
	return cloned;
}

} } }

namespace zillians { namespace language { namespace tree {

TemplatedIdentifier::TemplatedIdentifier()
{ }

TemplatedIdentifier::TemplatedIdentifier(Usage::type type, Identifier* id) : type(type), id(id)
{
	id->parent = this;
}

std::wstring TemplatedIdentifier::toString() const
{
	std::wstring t;

	t += id->toString();
	t += L"<";
	foreach(i, templated_type_list)
	{
		t += (*i)->name->toString();
		if((*i)->specialized_type)
		{
			t += L":";
			t += (*i)->specialized_type->toString();
		}
		if(!is_end_of_foreach(i, templated_type_list))
			t += L",";
	}
	t += L">";

	return t;
}

bool TemplatedIdentifier::isVariadic() const
{
	auto last = *templated_type_list.rbegin();
	return last->name->toString() == L"...";
}

bool TemplatedIdentifier::isFullySpecialized() const
{
	foreach(i, templated_type_list)
	{
		if(!(*i)->specialized_type)
		{
			return false;
		}
		else
		{
			if((*i)->specialized_type->type == TypeSpecifier::ReferredType::UNSPECIFIED)
			{
				if(isa<TemplatedIdentifier>((*i)->specialized_type->referred.unspecified))
				{
					if(!cast<TemplatedIdentifier>((*i)->specialized_type->referred.unspecified)->isFullySpecialized())
					{
						return false;
					}
				}
			}
		}
	}
	return true;
}

void TemplatedIdentifier::specialize()
{
	if(type == Usage::FORMAL_PARAMETER)
	{
		foreach(i, templated_type_list)
		{
			if(!(*i)->specialized_type)
			{
				TypeSpecifier* specialized_type = NULL;
				if(isa<TemplatedIdentifier>((*i)->name))
				{
					TemplatedIdentifier* duplicated_id = cast<TemplatedIdentifier>((*i)->name->clone());
					duplicated_id->specialize();
					specialized_type = new TypeSpecifier(duplicated_id);
					specialized_type->parent = *i;
				}
				else
				{
					specialized_type = new TypeSpecifier((*i)->name->clone());
					specialized_type->parent = *i;
				}

				SimpleIdentifier* dummy_identifier = new SimpleIdentifier(L"_");
				(*i)->replaceUseWith(*((*i)->name), *dummy_identifier);
				(*i)->specialized_type = specialized_type;
			}
		}
	}
}

bool TemplatedIdentifier::isEmpty() const
{
	if(id->isEmpty() && templated_type_list.size() == 0)
		return true;
	else
		return false;
}

void TemplatedIdentifier::setIdentifier(Identifier* identifier)
{
	if(id) id->parent = NULL;
	id = identifier;
	id->parent = this;
}

void TemplatedIdentifier::append(TypenameDecl* type)
{
	type->parent = this;
	templated_type_list.push_back(type);
}

bool TemplatedIdentifier::isEqualImpl(const ASTNode& rhs, ASTNodeSet& visited) const
{
	BEGIN_COMPARE()
	COMPARE_MEMBER(type)
	COMPARE_MEMBER(id)
	COMPARE_MEMBER(templated_type_list)
	END_COMPARE()
}

bool TemplatedIdentifier::replaceUseWith(const ASTNode& from, const ASTNode& to, bool update_parent)
{
	BEGIN_REPLACE()
	REPLACE_USE_WITH(type)
	REPLACE_USE_WITH(id)
	REPLACE_USE_WITH(templated_type_list)
	END_REPLACE()
}

ASTNode* TemplatedIdentifier::clone() const
{
	TemplatedIdentifier* cloned = new TemplatedIdentifier(type, (id) ? cast<Identifier>(id->clone()) : NULL);

	foreach(i, templated_type_list)
		cloned->append(cast<TypenameDecl>((*i)->clone()));

	return cloned;
}

} } }
<|endoftext|>


<commit_before>// Copyright (c) 2019 by Robert Bosch GmbH. All rights reserved.
// Copyright (c) 2021 by Apex.AI Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0
#ifndef IOX_UTILS_CXX_VARIANT_INL
#define IOX_UTILS_CXX_VARIANT_INL

#include "iceoryx_utils/cxx/variant.hpp"

namespace iox
{
namespace cxx
{
template <typename... Types>
inline variant<Types...>::variant(const variant& f_rhs) noexcept
    : m_type_index(f_rhs.m_type_index)
{
    if (m_type_index != INVALID_VARIANT_INDEX)
    {
        internal::call_at_index<0, Types...>::copyConstructor(
            m_type_index, const_cast<internal::byte_t*>(f_rhs.m_storage), m_storage);
    }
}

template <typename... Types>
template <uint64_t N, typename... CTorArguments>
inline variant<Types...>::variant(const in_place_index<N>&, CTorArguments&&... f_args) noexcept
{
    emplace_at_index<N>(std::forward<CTorArguments>(f_args)...);
}

template <typename... Types>
template <typename T, typename... CTorArguments>
inline variant<Types...>::variant(const in_place_type<T>&, CTorArguments&&... f_args) noexcept
{
    emplace<T>(std::forward<CTorArguments>(f_args)...);
}

template <typename... Types>
variant<Types...>& variant<Types...>::operator=(const variant& f_rhs) noexcept
{
    if (this != &f_rhs)
    {
        if (m_type_index != f_rhs.m_type_index)
        {
            call_element_destructor();
            m_type_index = f_rhs.m_type_index;

            if (m_type_index != INVALID_VARIANT_INDEX)
            {
                internal::call_at_index<0, Types...>::copyConstructor(
                    m_type_index, const_cast<internal::byte_t*>(f_rhs.m_storage), m_storage);
            }
        }
        else
        {
            if (m_type_index != INVALID_VARIANT_INDEX)
            {
                internal::call_at_index<0, Types...>::copy(
                    m_type_index, const_cast<internal::byte_t*>(f_rhs.m_storage), m_storage);
            }
        }
    }
    return *this;
}

template <typename... Types>
variant<Types...>::variant(variant&& f_rhs) noexcept
    : m_type_index{std::move(f_rhs.m_type_index)}
{
    if (m_type_index != INVALID_VARIANT_INDEX)
    {
        internal::call_at_index<0, Types...>::moveConstructor(m_type_index, f_rhs.m_storage, m_storage);
    }
}

template <typename... Types>
variant<Types...>& variant<Types...>::operator=(variant&& f_rhs) noexcept
{
    if (this != &f_rhs)
    {
        if (m_type_index != f_rhs.m_type_index)
        {
            call_element_destructor();
            m_type_index = std::move(f_rhs.m_type_index);
            if (m_type_index != INVALID_VARIANT_INDEX)
            {
                internal::call_at_index<0, Types...>::moveConstructor(m_type_index, f_rhs.m_storage, m_storage);
            }
        }
        else
        {
            if (m_type_index != INVALID_VARIANT_INDEX)
            {
                internal::call_at_index<0, Types...>::move(m_type_index, f_rhs.m_storage, m_storage);
            }
        }
    }
    return *this;
}

template <typename... Types>
inline variant<Types...>::~variant() noexcept
{
    call_element_destructor();
}

template <typename... Types>
void variant<Types...>::call_element_destructor() noexcept
{
    if (m_type_index != INVALID_VARIANT_INDEX)
    {
        internal::call_at_index<0, Types...>::destructor(m_type_index, m_storage);
    }
}

template <typename... Types>
template <typename T>
inline typename std::enable_if<!std::is_same<T, variant<Types...>&>::value, variant<Types...>>::type&
variant<Types...>::operator=(T&& f_rhs) noexcept
{
    if (m_type_index == INVALID_VARIANT_INDEX)
    {
        m_type_index = internal::get_index_of_type<0, T, Types...>::index;
    }

    if (!has_bad_variant_element_access<T>())
    {
        auto storage = static_cast<T*>(static_cast<void*>(m_storage));
        *storage = (std::forward<T>(f_rhs));
    }
    else
    {
        error_message(__PRETTY_FUNCTION__,
                      "wrong variant type assignment, another type is already "
                      "set in variant");
    }

    return *this;
}

template <typename... Types>
template <uint64_t TypeIndex, typename... CTorArguments>
inline bool variant<Types...>::emplace_at_index(CTorArguments&&... f_args) noexcept
{
    static_assert(TypeIndex <= sizeof...(Types), "TypeIndex is out of bounds");

    using T = typename internal::get_type_at_index<0, TypeIndex, Types...>::type;

    call_element_destructor();
    new (m_storage) T(std::forward<CTorArguments>(f_args)...);
    m_type_index = TypeIndex;

    return true;
}

template <typename... Types>
template <typename T, typename... CTorArguments>
inline bool variant<Types...>::emplace(CTorArguments&&... f_args) noexcept
{
    if (m_type_index != INVALID_VARIANT_INDEX && has_bad_variant_element_access<T>())
    {
        error_message(__PRETTY_FUNCTION__,
                      "wrong variant type emplacement, another type is already "
                      "set in variant");
        return false;
    }

    if (m_type_index != INVALID_VARIANT_INDEX)
    {
        call_element_destructor();
    }

    new (m_storage) T(std::forward<CTorArguments>(f_args)...);
    m_type_index = internal::get_index_of_type<0, T, Types...>::index;

    return true;
}

template <typename... Types>
template <uint64_t TypeIndex>
inline typename internal::get_type_at_index<0, TypeIndex, Types...>::type* variant<Types...>::get_at_index() noexcept
{
    if (TypeIndex != m_type_index)
    {
        return nullptr;
    }

    using T = typename internal::get_type_at_index<0, TypeIndex, Types...>::type;

    return static_cast<T*>(static_cast<void*>(m_storage));
}

template <typename... Types>
template <uint64_t TypeIndex>
inline const typename internal::get_type_at_index<0, TypeIndex, Types...>::type*
variant<Types...>::get_at_index() const noexcept
{
    using T = typename internal::get_type_at_index<0, TypeIndex, Types...>::type;
    return const_cast<const T*>(const_cast<variant*>(this)->get_at_index<TypeIndex>());
}

template <typename... Types>
template <typename T>
inline const T* variant<Types...>::get() const noexcept
{
    if (has_bad_variant_element_access<T>())
    {
        return nullptr;
    }
    else
    {
        return static_cast<const T*>(static_cast<const void*>(m_storage));
    }
}

template <typename... Types>
template <typename T>
inline T* variant<Types...>::get() noexcept
{
    return const_cast<T*>(const_cast<const variant*>(this)->get<T>());
}

template <typename... Types>
template <typename T>
inline T* variant<Types...>::get_if(T* f_default_value) noexcept
{
    return const_cast<T*>(const_cast<const variant*>(this)->get_if<T>(const_cast<const T*>(f_default_value)));
}

template <typename... Types>
template <typename T>
inline const T* variant<Types...>::get_if(const T* f_default_value) const noexcept
{
    if (has_bad_variant_element_access<T>())
    {
        return f_default_value;
    }

    return this->get<T>();
}

template <typename... Types>
constexpr size_t variant<Types...>::index() const noexcept
{
    return m_type_index;
}

template <typename... Types>
template <typename T>
inline bool variant<Types...>::has_bad_variant_element_access() const noexcept
{
    static_assert(internal::does_contain_type<T, Types...>::value, "variant does not contain given type");
    return (m_type_index != internal::get_index_of_type<0, T, Types...>::index);
}

template <typename... Types>
inline void variant<Types...>::error_message(const char* f_source, const char* f_msg) noexcept
{
    std::cerr << f_source << " ::: " << f_msg << std::endl;
}

template <typename T, typename... Types>
inline constexpr bool holds_alternative(const variant<Types...>& f_variant) noexcept
{
    return f_variant.template get<T>() != nullptr;
}
} // namespace cxx
} // namespace iox

#endif // IOX_UTILS_CXX_VARIANT_INL
<commit_msg>Iox-#759 improve helix qac parsing coverage workaround to improve Helix QAC coverage by allowing it to parse this bit of code<commit_after>// Copyright (c) 2019 by Robert Bosch GmbH. All rights reserved.
// Copyright (c) 2021 by Apex.AI Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0
#ifndef IOX_UTILS_CXX_VARIANT_INL
#define IOX_UTILS_CXX_VARIANT_INL

#include "iceoryx_utils/cxx/variant.hpp"

namespace iox
{
namespace cxx
{
template <typename... Types>
inline variant<Types...>::variant(const variant& f_rhs) noexcept
    : m_type_index(f_rhs.m_type_index)
{
    if (m_type_index != INVALID_VARIANT_INDEX)
    {
        internal::call_at_index<0, Types...>::copyConstructor(
            m_type_index, const_cast<internal::byte_t*>(f_rhs.m_storage), m_storage);
    }
}

template <typename... Types>
template <uint64_t N, typename... CTorArguments>
inline variant<Types...>::variant(const in_place_index<N>&, CTorArguments&&... f_args) noexcept
{
    emplace_at_index<N>(std::forward<CTorArguments>(f_args)...);
}

template <typename... Types>
template <typename T, typename... CTorArguments>
inline variant<Types...>::variant(const in_place_type<T>&, CTorArguments&&... f_args) noexcept
{
    emplace<T>(std::forward<CTorArguments>(f_args)...);
}

template <typename... Types>
variant<Types...>& variant<Types...>::operator=(const variant& f_rhs) noexcept
{
    if (this != &f_rhs)
    {
        if (m_type_index != f_rhs.m_type_index)
        {
            call_element_destructor();
            m_type_index = f_rhs.m_type_index;

            if (m_type_index != INVALID_VARIANT_INDEX)
            {
                internal::call_at_index<0, Types...>::copyConstructor(
                    m_type_index, const_cast<internal::byte_t*>(f_rhs.m_storage), m_storage);
            }
        }
        else
        {
            if (m_type_index != INVALID_VARIANT_INDEX)
            {
                internal::call_at_index<0, Types...>::copy(
                    m_type_index, const_cast<internal::byte_t*>(f_rhs.m_storage), m_storage);
            }
        }
    }
    return *this;
}

template <typename... Types>
variant<Types...>::variant(variant&& f_rhs) noexcept
    : m_type_index{std::move(f_rhs.m_type_index)}
{
    if (m_type_index != INVALID_VARIANT_INDEX)
    {
        internal::call_at_index<0, Types...>::moveConstructor(m_type_index, f_rhs.m_storage, m_storage);
    }
}

template <typename... Types>
variant<Types...>& variant<Types...>::operator=(variant&& f_rhs) noexcept
{
    if (this != &f_rhs)
    {
        if (m_type_index != f_rhs.m_type_index)
        {
            call_element_destructor();
            m_type_index = std::move(f_rhs.m_type_index);
            if (m_type_index != INVALID_VARIANT_INDEX)
            {
                internal::call_at_index<0, Types...>::moveConstructor(m_type_index, f_rhs.m_storage, m_storage);
            }
        }
        else
        {
            if (m_type_index != INVALID_VARIANT_INDEX)
            {
                internal::call_at_index<0, Types...>::move(m_type_index, f_rhs.m_storage, m_storage);
            }
        }
    }
    return *this;
}

template <typename... Types>
inline variant<Types...>::~variant() noexcept
{
    call_element_destructor();
}

template <typename... Types>
void variant<Types...>::call_element_destructor() noexcept
{
    if (m_type_index != INVALID_VARIANT_INDEX)
    {
        internal::call_at_index<0, Types...>::destructor(m_type_index, m_storage);
    }
}

template <typename... Types>
template <typename T>
inline typename std::enable_if<!std::is_same<T, variant<Types...>&>::value, variant<Types...>>::type&
variant<Types...>::operator=(T&& f_rhs) noexcept
{
    if (m_type_index == INVALID_VARIANT_INDEX)
    {
        m_type_index = internal::get_index_of_type<0, T, Types...>::index;
    }

    if (!has_bad_variant_element_access<T>())
    {
        auto storage = static_cast<T*>(static_cast<void*>(m_storage));
        *storage = (std::forward<T>(f_rhs));
    }
    else
    {
        error_message(__PRETTY_FUNCTION__,
                      "wrong variant type assignment, another type is already "
                      "set in variant");
    }

    return *this;
}

template <typename... Types>
template <uint64_t TypeIndex, typename... CTorArguments>
inline bool variant<Types...>::emplace_at_index(CTorArguments&&... f_args) noexcept
{
    static_assert(TypeIndex <= sizeof...(Types), "TypeIndex is out of bounds");

    using T = typename internal::get_type_at_index<0, TypeIndex, Types...>::type;

    call_element_destructor();
    new (m_storage) T(std::forward<CTorArguments>(f_args)...);
    m_type_index = TypeIndex;

    return true;
}

template <typename... Types>
template <typename T, typename... CTorArguments>
inline bool variant<Types...>::emplace(CTorArguments&&... f_args) noexcept
{
    if (m_type_index != INVALID_VARIANT_INDEX && has_bad_variant_element_access<T>())
    {
        error_message(__PRETTY_FUNCTION__,
                      "wrong variant type emplacement, another type is already "
                      "set in variant");
        return false;
    }

    if (m_type_index != INVALID_VARIANT_INDEX)
    {
        call_element_destructor();
    }

    new (m_storage) T(std::forward<CTorArguments>(f_args)...);
    m_type_index = internal::get_index_of_type<0, T, Types...>::index;

    return true;
}

template <typename... Types>
template <uint64_t TypeIndex>
inline typename internal::get_type_at_index<0, TypeIndex, Types...>::type* variant<Types...>::get_at_index() noexcept
{
    if (TypeIndex != m_type_index)
    {
        return nullptr;
    }

    using T = typename internal::get_type_at_index<0, TypeIndex, Types...>::type;

    return static_cast<T*>(static_cast<void*>(m_storage));
}

template <typename... Types>
template <uint64_t TypeIndex>
inline const typename internal::get_type_at_index<0, TypeIndex, Types...>::type*
variant<Types...>::get_at_index() const noexcept
{
    using T = typename internal::get_type_at_index<0, TypeIndex, Types...>::type;
    return const_cast<const T*>(const_cast<variant*>(this)->template get_at_index<TypeIndex>());
}

template <typename... Types>
template <typename T>
inline const T* variant<Types...>::get() const noexcept
{
    if (has_bad_variant_element_access<T>())
    {
        return nullptr;
    }
    else
    {
        return static_cast<const T*>(static_cast<const void*>(m_storage));
    }
}

template <typename... Types>
template <typename T>
inline T* variant<Types...>::get() noexcept
{
    return const_cast<T*>(const_cast<const variant*>(this)->get<T>());
}

template <typename... Types>
template <typename T>
inline T* variant<Types...>::get_if(T* f_default_value) noexcept
{
    return const_cast<T*>(const_cast<const variant*>(this)->get_if<T>(const_cast<const T*>(f_default_value)));
}

template <typename... Types>
template <typename T>
inline const T* variant<Types...>::get_if(const T* f_default_value) const noexcept
{
    if (has_bad_variant_element_access<T>())
    {
        return f_default_value;
    }

    return this->get<T>();
}

template <typename... Types>
constexpr size_t variant<Types...>::index() const noexcept
{
    return m_type_index;
}

template <typename... Types>
template <typename T>
inline bool variant<Types...>::has_bad_variant_element_access() const noexcept
{
    static_assert(internal::does_contain_type<T, Types...>::value, "variant does not contain given type");
    return (m_type_index != internal::get_index_of_type<0, T, Types...>::index);
}

template <typename... Types>
inline void variant<Types...>::error_message(const char* f_source, const char* f_msg) noexcept
{
    std::cerr << f_source << " ::: " << f_msg << std::endl;
}

template <typename T, typename... Types>
inline constexpr bool holds_alternative(const variant<Types...>& f_variant) noexcept
{
    return f_variant.template get<T>() != nullptr;
}
} // namespace cxx
} // namespace iox

#endif // IOX_UTILS_CXX_VARIANT_INL
<|endoftext|>