<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/lib/dimm/rcd_load.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2019                        */
/* [+] 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 rcd_load.C
/// @brief Run and manage the RCD_LOAD engine
///
// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
// *HWP HWP Backup: Andre Marin <aamarin@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 2
// *HWP Consumed by: FSP:HB

#include <fapi2.H>

#include <mss.H>
#include <lib/dimm/rcd_load.H>
#include <lib/dimm/rcd_load_ddr4.H>

using fapi2::TARGET_TYPE_MCBIST;
using fapi2::TARGET_TYPE_MCA;
using fapi2::TARGET_TYPE_MCS;
using fapi2::TARGET_TYPE_DIMM;

using fapi2::FAPI2_RC_SUCCESS;

namespace mss
{
///
/// @brief Perform the rcd_load operations - TARGET_TYPE_MCBIST specialization
/// @param[in] i_target, a fapi2::Target<TARGET_TYPE_MCBIST>
/// @return FAPI2_RC_SUCCESS if and only if ok
///
template<>
fapi2::ReturnCode rcd_load<TARGET_TYPE_MCBIST>( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target )
{
    // A vector of CCS instructions. We'll ask the targets to fill it, and then we'll execute it
    ccs::program<TARGET_TYPE_MCBIST> l_program;

    // Clear the initial delays. This will force the CCS engine to recompute the delay based on the
    // instructions in the CCS instruction vector
    l_program.iv_poll.iv_initial_delay = 0;
    l_program.iv_poll.iv_initial_sim_delay = 0;

    for (auto c : i_target.getChildren<TARGET_TYPE_MCS>())
    {
        for (auto p : c.getChildren<TARGET_TYPE_MCA>())
        {
            for (auto d : p.getChildren<TARGET_TYPE_DIMM>())
            {
                FAPI_DBG("rcd load for %s", mss::c_str(d));
                FAPI_TRY( perform_rcd_load(d, l_program.iv_instructions) );
            }

            // We have to configure the CCS engine to let it know which port these instructions are
            // going out (or whether it's broadcast ...) so lets execute the instructions we presently
            // have so that we kind of do this by port
            FAPI_TRY( ccs::execute(i_target, l_program, p) );
        }
    }

fapi_try_exit:
    return fapi2::current_err;
}

///
/// @brief Perform the rcd_load operations - unknown DIMM case
/// @param[in] i_target, a fapi2::Target<TARGET_TYPE_DIMM>
/// @param[in] a vector of CCS instructions we should add to (unused)
/// @return FAPI2_RC_SUCCESS if and only if ok
///
template<>
fapi2::ReturnCode perform_rcd_load<DEFAULT_KIND>( const fapi2::Target<TARGET_TYPE_DIMM>& i_target,
        std::vector< ccs::instruction_t<TARGET_TYPE_MCBIST> >& i_inst)
{
    uint8_t l_type = 0;
    uint8_t l_gen = 0;

    FAPI_TRY( mss::eff_dimm_type(i_target, l_type) );
    FAPI_TRY( mss::eff_dram_gen(i_target, l_gen) );

    // If we're here, we have a problem. The DIMM kind (type and/or generation) wasn't know
    // to our dispatcher. We have a DIMM plugged in we don't know how to deal with.
    FAPI_ASSERT(false,
                fapi2::MSS_UNKNOWN_DIMM()
                .set_DIMM_TYPE(l_type)
                .set_DRAM_GEN(l_gen)
                .set_DIMM_IN_ERROR(i_target),
                "Unable to perform rcd load on %s: unknown type (%d) or generation (%d)",
                mss::c_str(i_target), l_type, l_gen);

fapi_try_exit:
    return fapi2::current_err;
}

///
/// @brief Perform the rcd_load operations - RDIMM DDR4
/// @param[in] i_target, a fapi2::Target<TARGET_TYPE_DIMM>
/// @param[in] a vector of CCS instructions we should add to
/// @return FAPI2_RC_SUCCESS if and only if ok
///
template<>
fapi2::ReturnCode perform_rcd_load<KIND_RDIMM_DDR4>( const fapi2::Target<TARGET_TYPE_DIMM>& i_target,
        std::vector< ccs::instruction_t<TARGET_TYPE_MCBIST> >& i_inst)
{
    FAPI_DBG("perform rcd_load for %s [expecting rdimm (ddr4)]", mss::c_str(i_target));
    FAPI_TRY( rcd_load_ddr4(i_target, i_inst) );

fapi_try_exit:
    return fapi2::current_err;
}

///
/// @brief Perform the rcd_load operations - LRDIMM DDR4
/// @param[in] i_target, a fapi2::Target<TARGET_TYPE_DIMM>
/// @param[in] a vector of CCS instructions we should add to
/// @return FAPI2_RC_SUCCESS if and only if ok
///
template<>
fapi2::ReturnCode perform_rcd_load<KIND_LRDIMM_DDR4>( const fapi2::Target<TARGET_TYPE_DIMM>& i_target,
        std::vector< ccs::instruction_t<TARGET_TYPE_MCBIST> >& i_inst)
{
    FAPI_DBG("perform rcd_load for %s [expecting lrdimm (ddr4)]", mss::c_str(i_target));
    FAPI_TRY( rcd_load_ddr4(i_target, i_inst) );

fapi_try_exit:
    return fapi2::current_err;
}

///
/// @brief Perform the rcd_load operations - start the dispatcher
/// @param[in] i_target, a fapi2::Target<TARGET_TYPE_DIMM>
/// @param[in] a vector of CCS instructions we should add to
/// @return FAPI2_RC_SUCCESS if and only if ok
///
template<>
fapi2::ReturnCode perform_rcd_load<FORCE_DISPATCH>( const fapi2::Target<TARGET_TYPE_DIMM>& i_target,
        std::vector< ccs::instruction_t<TARGET_TYPE_MCBIST> >& i_inst)
{
    uint8_t l_type = 0;
    uint8_t l_gen = 0;

    FAPI_TRY( mss::eff_dimm_type(i_target, l_type) );
    FAPI_TRY( mss::eff_dram_gen(i_target, l_gen) );

    return perform_rcd_load_dispatch<FORCE_DISPATCH>(dimm_kind( l_type, l_gen ), i_target, i_inst);

fapi_try_exit:
    FAPI_ERR("couldn't get dimm type, dram gen: %s", mss::c_str(i_target));
    return fapi2::current_err;
}

} // namespace
<commit_msg>L3 draminit and mss_lib<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/lib/dimm/rcd_load.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2019                        */
/* [+] 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 rcd_load.C
/// @brief Run and manage the RCD_LOAD engine
///
// *HWP HWP Owner: Jacob Harvey <jlharvey@us.ibm.com>
// *HWP HWP Backup: Andre Marin <aamarin@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 3
// *HWP Consumed by: FSP:HB

#include <fapi2.H>

#include <mss.H>
#include <lib/dimm/rcd_load.H>
#include <lib/dimm/rcd_load_ddr4.H>
#include <generic/memory/lib/utils/find.H>

using fapi2::TARGET_TYPE_MCBIST;
using fapi2::TARGET_TYPE_MCA;
using fapi2::TARGET_TYPE_MCS;
using fapi2::TARGET_TYPE_DIMM;

using fapi2::FAPI2_RC_SUCCESS;

namespace mss
{
///
/// @brief Perform the rcd_load operations - TARGET_TYPE_MCBIST specialization
/// @param[in] i_target, a fapi2::Target<TARGET_TYPE_MCBIST>
/// @return FAPI2_RC_SUCCESS if and only if ok
///
template<>
fapi2::ReturnCode rcd_load<TARGET_TYPE_MCBIST>( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target )
{
    // A vector of CCS instructions. We'll ask the targets to fill it, and then we'll execute it
    ccs::program<TARGET_TYPE_MCBIST> l_program;

    // Clear the initial delays. This will force the CCS engine to recompute the delay based on the
    // instructions in the CCS instruction vector
    l_program.iv_poll.iv_initial_delay = 0;
    l_program.iv_poll.iv_initial_sim_delay = 0;

    for (const auto& p : find_targets<TARGET_TYPE_MCA>(i_target))
    {
        for (const auto& d : find_targets<TARGET_TYPE_DIMM>(p))
        {
            FAPI_DBG("rcd load for %s", mss::c_str(d));
            FAPI_TRY( perform_rcd_load(d, l_program.iv_instructions) );
        }

        // We have to configure the CCS engine to let it know which port these instructions are
        // going out (or whether it's broadcast ...) so lets execute the instructions we presently
        // have so that we kind of do this by port
        FAPI_TRY( ccs::execute(i_target, l_program, p) );
    }

fapi_try_exit:
    return fapi2::current_err;
}

///
/// @brief Perform the rcd_load operations - unknown DIMM case
/// @param[in] i_target, a fapi2::Target<TARGET_TYPE_DIMM>
/// @param[in] a vector of CCS instructions we should add to (unused)
/// @return FAPI2_RC_SUCCESS if and only if ok
///
template<>
fapi2::ReturnCode perform_rcd_load<DEFAULT_KIND>( const fapi2::Target<TARGET_TYPE_DIMM>& i_target,
        std::vector< ccs::instruction_t<TARGET_TYPE_MCBIST> >& i_inst)
{
    uint8_t l_type = 0;
    uint8_t l_gen = 0;

    FAPI_TRY( mss::eff_dimm_type(i_target, l_type) );
    FAPI_TRY( mss::eff_dram_gen(i_target, l_gen) );

    // If we're here, we have a problem. The DIMM kind (type and/or generation) wasn't known
    // to our dispatcher. We have a DIMM plugged in we don't know how to deal with.
    FAPI_ASSERT(false,
                fapi2::MSS_UNKNOWN_DIMM()
                .set_DIMM_TYPE(l_type)
                .set_DRAM_GEN(l_gen)
                .set_DIMM_IN_ERROR(i_target),
                "Unable to perform rcd load on %s: unknown type (%d) or generation (%d)",
                mss::c_str(i_target), l_type, l_gen);

fapi_try_exit:
    return fapi2::current_err;
}

///
/// @brief Perform the rcd_load operations - RDIMM DDR4
/// @param[in] i_target, a fapi2::Target<TARGET_TYPE_DIMM>
/// @param[in] a vector of CCS instructions we should add to
/// @return FAPI2_RC_SUCCESS if and only if ok
///
template<>
fapi2::ReturnCode perform_rcd_load<KIND_RDIMM_DDR4>( const fapi2::Target<TARGET_TYPE_DIMM>& i_target,
        std::vector< ccs::instruction_t<TARGET_TYPE_MCBIST> >& i_inst)
{
    FAPI_DBG("perform rcd_load for %s [expecting rdimm (ddr4)]", mss::c_str(i_target));
    FAPI_TRY( rcd_load_ddr4(i_target, i_inst) );

fapi_try_exit:
    return fapi2::current_err;
}

///
/// @brief Perform the rcd_load operations - LRDIMM DDR4
/// @param[in] i_target, a fapi2::Target<TARGET_TYPE_DIMM>
/// @param[in] a vector of CCS instructions we should add to
/// @return FAPI2_RC_SUCCESS if and only if ok
///
template<>
fapi2::ReturnCode perform_rcd_load<KIND_LRDIMM_DDR4>( const fapi2::Target<TARGET_TYPE_DIMM>& i_target,
        std::vector< ccs::instruction_t<TARGET_TYPE_MCBIST> >& i_inst)
{
    FAPI_DBG("perform rcd_load for %s [expecting lrdimm (ddr4)]", mss::c_str(i_target));
    FAPI_TRY( rcd_load_ddr4(i_target, i_inst) );

fapi_try_exit:
    return fapi2::current_err;
}

///
/// @brief Perform the rcd_load operations - start the dispatcher
/// @param[in] i_target, a fapi2::Target<TARGET_TYPE_DIMM>
/// @param[in] a vector of CCS instructions we should add to
/// @return FAPI2_RC_SUCCESS if and only if ok
///
template<>
fapi2::ReturnCode perform_rcd_load<FORCE_DISPATCH>( const fapi2::Target<TARGET_TYPE_DIMM>& i_target,
        std::vector< ccs::instruction_t<TARGET_TYPE_MCBIST> >& i_inst)
{
    uint8_t l_type = 0;
    uint8_t l_gen = 0;

    FAPI_TRY( mss::eff_dimm_type(i_target, l_type) );
    FAPI_TRY( mss::eff_dram_gen(i_target, l_gen) );

    return perform_rcd_load_dispatch<FORCE_DISPATCH>(dimm_kind( l_type, l_gen ), i_target, i_inst);

fapi_try_exit:
    FAPI_ERR("couldn't get dimm type, dram gen: %s", mss::c_str(i_target));
    return fapi2::current_err;
}

} // namespace
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/nest/p9_mss_eff_grouping.H $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2019                        */
/* [+] 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  p9_mss_eff_grouping.H
///
/// @brief Perform Memory Controller grouping on each processor chip
///
/// The purpose of this procedure is to effectively group the memory on each
/// processor chip based on available memory behind its memory grouping ports.
/// Some placement policy/scheme and other info that are stored in the
/// attributes are used as part of the grouping process.
///
/// ----------------------------------------------------------------------------
/// *HWP HWP Owner   : Joe McGill <jmcgill@us.ibm.com>
/// *HWP FW Owner    : Thi Tran <thi@us.ibm.com>
/// *HWP Team        : Nest
/// *HWP Level       : 1
/// *HWP Consumed by : HB
/// ----------------------------------------------------------------------------

#ifndef _P9_MSS_EFF_GROUPING_H_
#define _P9_MSS_EFF_GROUPING_H_

//------------------------------------------------------------------------------
// Includes
//------------------------------------------------------------------------------
#include <fapi2.H>

///----------------------------------------------------------------------------
/// Constant definitions
///----------------------------------------------------------------------------

// Constants used for EffGroupingData struct
const uint8_t DATA_GROUPS   = 16;   // 8 regular groups, 8 mirrored groups
const uint8_t MIRR_OFFSET   = 8;    // Start of mirrored offset in DATA_GROUPS
const uint8_t DATA_ELEMENTS = 18;   // 18 items of data for each group

// Indexes used for EffGroupingData::iv_data DATA ELEMENTS
const uint8_t PORT_SIZE = 0;         // Memory size of each port in group (GB)
const uint8_t PORTS_IN_GROUP = 1;    // Number of ports in group
const uint8_t GROUP_SIZE = 2;        // Memory size of entire group (GB)
const uint8_t BASE_ADDR = 3;         // Base Address
#define MEMBER_IDX(X) ((X) + 4)      // List of MC ports in group
#define ALT_VALID(X) ((X) + 12)      // Alt Memory valid (2 alt memory regions)
#define ALT_SIZE(X) ((X) + 14)       // Alt Memory Size
#define ALT_BASE_ADDR(X) ((X) + 16)  // Alt Base Address

// Number of memory regions
const uint8_t NUM_NON_MIRROR_REGIONS = 8;
const uint8_t NUM_MIRROR_REGIONS = 4;
const uint8_t NUM_OF_HTM_REGIONS = 2; // 2 HTM memory regions
const uint8_t NUM_OF_ALT_MEM_REGIONS = 2; // 2 memory holes

// ------------------------------------------------------
// MC ports
// Define the MC ports to be grouped.
// For Nimbus, MC port is an MCA (8 MCAs)
// For Cumulus, MC port is a DMI (8 DMIs)
// -------------------------------------------------------
const uint8_t NUM_MC_PORTS_PER_PROC = 8;
const uint8_t NUM_DIMMS_PER_DRAM_PORT = 2; // 2 DIMMs per DRAM port

/// Function pointer typedef definition for HWP call support
typedef fapi2::ReturnCode (*p9_mss_eff_grouping_FP_t)(
    const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>&);

//------------------------------------------------------------------------------
// Function prototypes
//------------------------------------------------------------------------------
///
/// @brief p9_mss_eff_grouping procedure
///
/// This HWP is to group the MCs of the input target processor chip based
/// on the amount of memory behind its ports and some policy attribute settings.
///
/// @param[in]    i_target   Reference to TARGET_TYPE_PROC_CHIP target
///
/// @return FAPI2_RC_SUCCESS if success, else error code.
///
extern "C"
{

    fapi2::ReturnCode p9_mss_eff_grouping(
        const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target);

} // extern "C"

#endif  // _P9_MSS_EFF_GROUPING_H_
<commit_msg>Fix HB build failure and incorrect HWP level lable<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/nest/p9_mss_eff_grouping.H $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2019                        */
/* [+] 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  p9_mss_eff_grouping.H
///
/// @brief Perform Memory Controller grouping on each processor chip
///
/// The purpose of this procedure is to effectively group the memory on each
/// processor chip based on available memory behind its memory grouping ports.
/// Some placement policy/scheme and other info that are stored in the
/// attributes are used as part of the grouping process.
///
/// ----------------------------------------------------------------------------
/// *HWP HWP Owner   : Joe McGill <jmcgill@us.ibm.com>
/// *HWP FW Owner    : Thi Tran <thi@us.ibm.com>
/// *HWP Team        : Nest
/// *HWP Level       : 2
/// *HWP Consumed by : HB
/// ----------------------------------------------------------------------------

#ifndef _P9_MSS_EFF_GROUPING_H_
#define _P9_MSS_EFF_GROUPING_H_

//------------------------------------------------------------------------------
// Includes
//------------------------------------------------------------------------------
#include <fapi2.H>

///----------------------------------------------------------------------------
/// Constant definitions
///----------------------------------------------------------------------------

// Constants used for EffGroupingData struct
const uint8_t DATA_GROUPS   = 16;   // 8 regular groups, 8 mirrored groups
const uint8_t MIRR_OFFSET   = 8;    // Start of mirrored offset in DATA_GROUPS
const uint8_t DATA_ELEMENTS = 18;   // 18 items of data for each group

// Indexes used for EffGroupingData::iv_data DATA ELEMENTS
const uint8_t PORT_SIZE = 0;         // Memory size of each port in group (GB)
const uint8_t PORTS_IN_GROUP = 1;    // Number of ports in group
const uint8_t GROUP_SIZE = 2;        // Memory size of entire group (GB)
const uint8_t BASE_ADDR = 3;         // Base Address
#define MEMBER_IDX(X) ((X) + 4)      // List of MC ports in group
#define ALT_VALID(X) ((X) + 12)      // Alt Memory valid (2 alt memory regions)
#define ALT_SIZE(X) ((X) + 14)       // Alt Memory Size
#define ALT_BASE_ADDR(X) ((X) + 16)  // Alt Base Address

// Number of memory regions
const uint8_t NUM_NON_MIRROR_REGIONS = 8;
const uint8_t NUM_MIRROR_REGIONS = 4;
const uint8_t NUM_OF_HTM_REGIONS = 2; // 2 HTM memory regions
const uint8_t NUM_OF_ALT_MEM_REGIONS = 2; // 2 memory holes

// ------------------------------------------------------
// MC ports
// Define the MC ports to be grouped.
// For Nimbus, MC port is an MCA (8 MCAs)
// For Cumulus, MC port is a DMI (8 DMIs)
// -------------------------------------------------------
const uint8_t NUM_MC_PORTS_PER_PROC = 8;
const uint8_t NUM_DIMMS_PER_DRAM_PORT = 2; // 2 DIMMs per DRAM port

/// Function pointer typedef definition for HWP call support
typedef fapi2::ReturnCode (*p9_mss_eff_grouping_FP_t)(
    const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>&);

//------------------------------------------------------------------------------
// Function prototypes
//------------------------------------------------------------------------------
///
/// @brief p9_mss_eff_grouping procedure
///
/// This HWP is to group the MCs of the input target processor chip based
/// on the amount of memory behind its ports and some policy attribute settings.
///
/// @param[in]    i_target   Reference to TARGET_TYPE_PROC_CHIP target
///
/// @return FAPI2_RC_SUCCESS if success, else error code.
///
extern "C"
{

    fapi2::ReturnCode p9_mss_eff_grouping(
        const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target);

} // extern "C"

#endif  // _P9_MSS_EFF_GROUPING_H_
<|endoftext|>


<commit_before>#include "MifareClassic.h"
#include "Ndef.h"
#include <Adafruit_NFCShield_I2C.h>

#define ULTRALIGHT_PAGE_SIZE 4
#define ULTRALIGHT_READ_SIZE 4

// MIFARE ULTRALIGHT C - NFC FORUM TYPE 2

// TODO verify these assumptions!
int getUltralightBufferSize(int messageLength)
{

  // TLV header is 3 bytes. TLV terminator is 1 byte.
  int bufferSize = messageLength + 4;

  // TODO ULTRALIGHT_PAGE_SIZE or ULTRALIGHT_READ_SIZE
  // bufferSize needs to be a multiple of ULTRALIGHT_PAGE_SIZE
  if (bufferSize % ULTRALIGHT_READ_SIZE != 0)
  {
      bufferSize = ((messageLength / ULTRALIGHT_READ_SIZE) + 1) * ULTRALIGHT_READ_SIZE;
  }

  return bufferSize;
}

NdefMessage readMifareUltralight(Adafruit_NFCShield_I2C& nfc)
{
    int currentPage = 5; // data starts on page 5
    int messageLength = 0;
    byte pageData[ULTRALIGHT_READ_SIZE]; // TODO RTFM, I think we get many pages, can I read less often?

    int success = nfc.mifareultralight_ReadPage (currentPage, pageData);
    if (success)
    {
      messageLength = pageData[2];
    }
    else
    {
      Serial.print("Error. Failed read page ");Serial.println(currentPage);
    }

    // this should be nested in the message length loop
    int index = 0;
    int bufferSize = getUltralightBufferSize(messageLength);
    uint8_t buffer[bufferSize];

    Serial.print("Message Length ");Serial.println(messageLength);
    Serial.print("Buffer Size ");Serial.println(bufferSize);

    // TODO special case
    // Message Length == 0 should return an TNF_EMPTY data is 0x44 0x03 0x00 0xFE

    // for (page = 6; page < 63; page++) {
    while (index < messageLength)
    {

      // read the data
      success = nfc.mifareultralight_ReadPage(currentPage, &buffer[index]);
      if (success)
      {
        Serial.print("Read page ");Serial.println(currentPage);
      }
      else
      {
        Serial.print("Read failed");Serial.println(currentPage);
        // TODO error handling
      }

      index += ULTRALIGHT_PAGE_SIZE; // TODO ULTRALIGHT_READ_SIZE
      currentPage++;  // TODO jump multiple pages!!!

      // TODO don't read past block 63

    }

    nfc.PrintHex(&buffer[3], messageLength); // TODO MIFARE_DATA_START_INDEX 3

    NdefMessage ndefMessage = NdefMessage(&buffer[3], messageLength);
    return ndefMessage;
}

<commit_msg>print page contents<commit_after>#include "MifareClassic.h"
#include "Ndef.h"
#include <Adafruit_NFCShield_I2C.h>

#define ULTRALIGHT_PAGE_SIZE 4
#define ULTRALIGHT_READ_SIZE 4

// MIFARE ULTRALIGHT C - NFC FORUM TYPE 2

// TODO verify these assumptions!
int getUltralightBufferSize(int messageLength)
{

  // TLV header is 3 bytes. TLV terminator is 1 byte.
  int bufferSize = messageLength + 4;

  // TODO ULTRALIGHT_PAGE_SIZE or ULTRALIGHT_READ_SIZE
  // bufferSize needs to be a multiple of ULTRALIGHT_PAGE_SIZE
  if (bufferSize % ULTRALIGHT_READ_SIZE != 0)
  {
      bufferSize = ((messageLength / ULTRALIGHT_READ_SIZE) + 1) * ULTRALIGHT_READ_SIZE;
  }

  return bufferSize;
}

NdefMessage readMifareUltralight(Adafruit_NFCShield_I2C& nfc)
{
    int currentPage = 5; // data starts on page 5
    int messageLength = 0;
    byte pageData[ULTRALIGHT_READ_SIZE]; // TODO RTFM, I think we get many pages, can I read less often?

    int success = nfc.mifareultralight_ReadPage (currentPage, pageData);
    if (success)
    {
      messageLength = pageData[2];
    }
    else
    {
      Serial.print("Error. Failed read page ");Serial.println(currentPage);
    }

    // this should be nested in the message length loop
    int index = 0;
    int bufferSize = getUltralightBufferSize(messageLength);
    uint8_t buffer[bufferSize];

    Serial.print("Message Length ");Serial.println(messageLength);
    Serial.print("Buffer Size ");Serial.println(bufferSize);

    // TODO special case
    // Message Length == 0 should return an TNF_EMPTY data is 0x44 0x03 0x00 0xFE

    // for (page = 6; page < 63; page++) {
    while (index < messageLength)
    {

      // read the data
      success = nfc.mifareultralight_ReadPage(currentPage, &buffer[index]);
      if (success)
      {
        Serial.print("Page ");Serial.print(currentPage);Serial.print(" ");
        nfc.PrintHexChar(&buffer[index], ULTRALIGHT_PAGE_SIZE);
      }
      else
      {
        Serial.print("Read failed");Serial.println(currentPage);
        // TODO error handling
      }

      index += ULTRALIGHT_PAGE_SIZE; // TODO ULTRALIGHT_READ_SIZE
      currentPage++;  // TODO jump multiple pages!!!

      // TODO don't read past block 63

    }

    nfc.PrintHex(&buffer[3], messageLength); // TODO MIFARE_DATA_START_INDEX 3

    NdefMessage ndefMessage = NdefMessage(&buffer[3], messageLength);
    return ndefMessage;
}

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2017 Google 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.
 */

#include "log.h"

#include "core/cc/target.h"

#if TARGET_OS != GAPID_OS_ANDROID

#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <chrono>
#include <ctime> // Required for MSVC.

namespace core {

Logger Logger::mInstance = Logger();

void Logger::init(unsigned level, const char* system, const char* path) {
    mInstance.mLevel = level;
    mInstance.mSystem = system;
    if (path != nullptr) {
        if (FILE* f = fopen(path, "w")) {
            GAPID_INFO("Logging to %s", path);
            mInstance.mFiles.push_back(f);
        } else {
            GAPID_WARNING("Can't open file for logging (%s): %s", path, strerror(errno));
        }
    }
}

Logger::Logger() : mLevel(LOG_LEVEL_INFO), mSystem("") {
    mFiles.push_back(stdout);
}

Logger::~Logger() {
    for (FILE* file : mFiles) {
        fclose(file);
    }
}

void Logger::logf(unsigned level, const char* file, unsigned line, const char* format, ...) const {
    va_list args;
    va_start(args, format);
    vlogf(level, file, line, format, args);
    va_end(args);
}

void Logger::vlogf(unsigned level, const char* src_file, unsigned src_line, const char* format, va_list args) const {
    // Get the current time with milliseconds precision
    auto t = std::chrono::system_clock::now();
    std::time_t now = std::chrono::system_clock::to_time_t(t);
    std::tm* loc = std::localtime(&now);
    auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(t.time_since_epoch());

    for (FILE* file : mFiles) {
        // Print out the common part of the log messages
        fprintf(file, "%02d:%02d:%02d.%03d %c %s: [%s:%u] ", loc->tm_hour, loc->tm_min, loc->tm_sec,
                static_cast<int>(ms.count() % 1000), "FEWIDV"[level], mSystem, src_file, src_line);

        // Print out the actual log message
        vfprintf(file, format, args);

        // Always finish with a newline
        fprintf(file, "\n");

        // Flush the log to ensure that every message is written out even if the application crashes
        fflush(file);
    }

    if (level == LOG_LEVEL_FATAL) {
        exit(EXIT_FAILURE);
    }
}

}  // namespace core

#endif  // TARGET_OS != GAPID_OS_ANDROID
<commit_msg>core/cc/log: Fix crash due to repeated use of va_list.<commit_after>/*
 * Copyright (C) 2017 Google 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.
 */

#include "log.h"

#include "core/cc/target.h"

#if TARGET_OS != GAPID_OS_ANDROID

#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <chrono>
#include <ctime> // Required for MSVC.

namespace core {

Logger Logger::mInstance = Logger();

void Logger::init(unsigned level, const char* system, const char* path) {
    mInstance.mLevel = level;
    mInstance.mSystem = system;
    if (path != nullptr) {
        if (FILE* f = fopen(path, "w")) {
            GAPID_INFO("Logging to %s", path);
            mInstance.mFiles.push_back(f);
        } else {
            GAPID_WARNING("Can't open file for logging (%s): %s", path, strerror(errno));
        }
    }
}

Logger::Logger() : mLevel(LOG_LEVEL_INFO), mSystem("") {
    mFiles.push_back(stdout);
}

Logger::~Logger() {
    for (FILE* file : mFiles) {
        fclose(file);
    }
}

void Logger::logf(unsigned level, const char* file, unsigned line, const char* format, ...) const {
    va_list args;
    va_start(args, format);
    vlogf(level, file, line, format, args);
    va_end(args);
}

void Logger::vlogf(unsigned level, const char* src_file, unsigned src_line, const char* format, va_list args) const {
    // Get the current time with milliseconds precision
    auto t = std::chrono::system_clock::now();
    std::time_t now = std::chrono::system_clock::to_time_t(t);
    std::tm* loc = std::localtime(&now);
    auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(t.time_since_epoch());

    for (FILE* file : mFiles) {
        va_list args_copy;
        va_copy(args_copy, args);

        // Print out the common part of the log messages
        fprintf(file, "%02d:%02d:%02d.%03d %c %s: [%s:%u] ", loc->tm_hour, loc->tm_min, loc->tm_sec,
                static_cast<int>(ms.count() % 1000), "FEWIDV"[level], mSystem, src_file, src_line);

        // Print out the actual log message
        vfprintf(file, format, args_copy);

        // Always finish with a newline
        fprintf(file, "\n");

        // Flush the log to ensure that every message is written out even if the application crashes
        fflush(file);
    }

    if (level == LOG_LEVEL_FATAL) {
        exit(EXIT_FAILURE);
    }
}

}  // namespace core

#endif  // TARGET_OS != GAPID_OS_ANDROID
<|endoftext|>


<commit_before>/**
 * Clever programming language
 * Copyright (c) Clever Team
 *
 * This file is distributed under the MIT license. See LICENSE for details.
 */

#include <iostream>
#include "core/ast.h"
#include "core/codegen.h"
#include "core/scope.h"
#include "core/compiler.h"

namespace clever { namespace ast {

void Codegen::init()
{
	m_scope = new Scope;
	m_scope_pool[m_scope_id++] = m_scope;
}

void Codegen::visit(IntLit* node)
{
	node->setConstId(m_compiler->addConstant(new Value(node->getValue())));
}

void Codegen::visit(DoubleLit* node)
{
	node->setConstId(m_compiler->addConstant(new Value(node->getValue())));
}

void Codegen::visit(StringLit* node)
{
	node->setConstId(m_compiler->addConstant(new Value(node->getValue())));
}

void Codegen::visit(Ident* node)
{
	Symbol* sym = m_scope->getAny(node->getName());

	if (!sym) {
		m_compiler->errorf(node->getLocation(),
			"Variable `%S' not found!", node->getName());
	}
	std::cout << "id: " << sym->value_id << std::endl;

	node->setValueId(sym->value_id);
	node->setScopeId(sym->scope->getId());
}

void Codegen::visit(Import* node)
{
	if (node->getModule()) {
		m_compiler->getPkgManager().importModule(m_scope,
			node->getPackage()->getName(), node->getModule()->getName());
	} else {
		m_compiler->getPkgManager().importPackage(m_scope,
			node->getPackage()->getName());
	}
}

void Codegen::visit(Block* node)
{
	m_scope = m_scope->newLexicalScope();
	m_scope->setId(m_scope_id);
	m_scope_pool[m_scope_id++] = m_scope;

	std::vector<Node*> nodes = node->getNodes();
	std::vector<Node*>::const_iterator it = nodes.begin(), end = nodes.end();
	while (it != end) {
		(*it)->accept(*this);
		++it;
	}

	m_scope = m_scope->getParent();
}

void Codegen::visit(VariableDecl* node)
{
	if (node->hasAssignment()) {
		m_scope->pushValue(node->getIdent()->getName(), new Value());
		node->getAssignment()->accept(*this);
	} else {
		size_t var_id = m_scope->pushValue(node->getIdent()->getName(), new Value());

		m_ir.push_back(
			IR(OP_ASSIGN,
				Operand(FETCH_VAL, var_id, m_scope->getId()),
				Operand(FETCH_VAL, m_scope->pushConst(new Value()), m_scope->getId())));
	}
}

void Codegen::visit(Assignment* node)
{
	// TODO: allow assignment of any possible left hand side.

	Ident* ident = static_cast<Ident*>(node->getLhs());
	Symbol* sym = m_scope->getLocal(ident->getName());
	Node* rhs = node->getRhs();

	if (!sym) {
		m_compiler->errorf(node->getLocation(),
			"Variable `%S' not found!", ident->getName());
	}

	rhs->accept(*this);

	if (rhs->isLiteral()) {
		m_ir.push_back(IR(OP_ASSIGN,
			Operand(FETCH_VAL, sym->value_id, sym->scope->getId()),
			Operand(FETCH_CONST, static_cast<Literal*>(rhs)->getConstId())));
	}

	// TODO: if node->isConditional() is true, emit branching code to avoid assignment when ident has been initialized.
}

void Codegen::visit(FunctionCall* node)
{
	Ident* ident = static_cast<Ident*>(node->getCallee());
	Symbol* sym = m_scope->getAny(ident->getName());

	if (!sym) {
		m_compiler->errorf(node->getLocation(),
			"Function `%S' not found!", ident->getName());
	}

	if (node->hasArgs()) {
		NodeList& args = node->getArgs()->getNodes();
		NodeList::const_iterator it = args.begin(), end = args.end();

		while (it != end) {
			Operand operand;

			(*it)->accept(*this);

			if ((*it)->isLiteral()) {
				operand.op_type = FETCH_CONST;
				operand.value_id = static_cast<Literal*>(*it)->getConstId();
			} else {
				std::cout << "foo" << std::endl;

				operand.op_type = FETCH_VAL;
				operand.value_id = (*it)->getValueId();
				operand.scope_id = (*it)->getScopeId();
			}
			m_ir.push_back(IR(OP_SEND_VAL, operand));
			++it;
		}
	}

	m_ir.push_back(IR(OP_FCALL,
		Operand(FETCH_VAL, sym->value_id, sym->scope->getId())));
}

void Codegen::visit(FunctionDecl* node)
{
	const CString* name = node->getIdent()->getName();
	Symbol* sym = m_scope->getLocal(name);
	size_t start_func;

	if (sym) {
		m_compiler->errorf(node->getLocation(),
			"Function `%S' already defined in the scope!", name);
	}

	Function* func = static_cast<Function*>(CLEVER_FUNC_TYPE->allocData());

	func->setName(*name);
	func->setUserDefined();
	func->setAddr(m_ir.size());

	Value* fval = new Value();
	fval->setType(CLEVER_FUNC_TYPE);
	fval->setObj(func);

	m_scope->pushValue(name, fval);

	start_func = m_ir.size();

	// XXX: what's the point of a jump here?
	m_ir.push_back(IR(OP_JMP, Operand(JMP_ADDR, 0)));

	// TODO: find a cleaner way to enter and leave scopes
	m_scope = m_scope->newLexicalScope();
	m_scope->setId(m_scope_id);
	m_scope_pool[m_scope_id++] = m_scope;

	if (node->hasArgs()) {
		for (size_t i = 0; i < node->numArgs(); ++i) {
			VariableDecl* decl = static_cast<VariableDecl*>(node->getArg(i));

			if (decl->hasAssignment()) {
				decl->getAssignment()->setConditional(true);
			}
		}

		node->getArgs()->accept(*this);
	}

	node->getBlock()->accept(*this);

	m_scope = m_scope->getParent();

	m_ir.push_back(IR(OP_LEAVE));

	m_ir[start_func].op1.value_id = m_ir.size();
}

void Codegen::visit(Return* node)
{
	// TODO: return value
	m_ir.push_back(IR(OP_RET));
}

void Codegen::visit(While* node)
{
	size_t start_while = m_ir.size();

	node->getCondition()->accept(*this);

	m_ir.push_back(IR(OP_JMPZ));

	node->getBlock()->accept(*this);

	m_ir.push_back(IR(OP_JMP, Operand(JMP_ADDR, start_while)));

	m_ir[start_while].op2.value_id = m_ir.size();
}

}} // clever::ast
<commit_msg>- Removed debug prints<commit_after>/**
 * Clever programming language
 * Copyright (c) Clever Team
 *
 * This file is distributed under the MIT license. See LICENSE for details.
 */

#include <iostream>
#include "core/ast.h"
#include "core/codegen.h"
#include "core/scope.h"
#include "core/compiler.h"

namespace clever { namespace ast {

void Codegen::init()
{
	m_scope = new Scope;
	m_scope_pool[m_scope_id++] = m_scope;
}

void Codegen::visit(IntLit* node)
{
	node->setConstId(m_compiler->addConstant(new Value(node->getValue())));
}

void Codegen::visit(DoubleLit* node)
{
	node->setConstId(m_compiler->addConstant(new Value(node->getValue())));
}

void Codegen::visit(StringLit* node)
{
	node->setConstId(m_compiler->addConstant(new Value(node->getValue())));
}

void Codegen::visit(Ident* node)
{
	Symbol* sym = m_scope->getAny(node->getName());

	if (!sym) {
		m_compiler->errorf(node->getLocation(),
			"Variable `%S' not found!", node->getName());
	}

	node->setValueId(sym->value_id);
	node->setScopeId(sym->scope->getId());
}

void Codegen::visit(Import* node)
{
	if (node->getModule()) {
		m_compiler->getPkgManager().importModule(m_scope,
			node->getPackage()->getName(), node->getModule()->getName());
	} else {
		m_compiler->getPkgManager().importPackage(m_scope,
			node->getPackage()->getName());
	}
}

void Codegen::visit(Block* node)
{
	m_scope = m_scope->newLexicalScope();
	m_scope->setId(m_scope_id);
	m_scope_pool[m_scope_id++] = m_scope;

	std::vector<Node*> nodes = node->getNodes();
	std::vector<Node*>::const_iterator it = nodes.begin(), end = nodes.end();
	while (it != end) {
		(*it)->accept(*this);
		++it;
	}

	m_scope = m_scope->getParent();
}

void Codegen::visit(VariableDecl* node)
{
	if (node->hasAssignment()) {
		m_scope->pushValue(node->getIdent()->getName(), new Value());
		node->getAssignment()->accept(*this);
	} else {
		size_t var_id = m_scope->pushValue(node->getIdent()->getName(), new Value());

		m_ir.push_back(
			IR(OP_ASSIGN,
				Operand(FETCH_VAL, var_id, m_scope->getId()),
				Operand(FETCH_VAL, m_scope->pushConst(new Value()), m_scope->getId())));
	}
}

void Codegen::visit(Assignment* node)
{
	// TODO: allow assignment of any possible left hand side.

	Ident* ident = static_cast<Ident*>(node->getLhs());
	Symbol* sym = m_scope->getLocal(ident->getName());
	Node* rhs = node->getRhs();

	if (!sym) {
		m_compiler->errorf(node->getLocation(),
			"Variable `%S' not found!", ident->getName());
	}

	rhs->accept(*this);

	if (rhs->isLiteral()) {
		m_ir.push_back(IR(OP_ASSIGN,
			Operand(FETCH_VAL, sym->value_id, sym->scope->getId()),
			Operand(FETCH_CONST, static_cast<Literal*>(rhs)->getConstId())));
	}

	// TODO: if node->isConditional() is true, emit branching code to avoid assignment when ident has been initialized.
}

void Codegen::visit(FunctionCall* node)
{
	Ident* ident = static_cast<Ident*>(node->getCallee());
	Symbol* sym = m_scope->getAny(ident->getName());

	if (!sym) {
		m_compiler->errorf(node->getLocation(),
			"Function `%S' not found!", ident->getName());
	}

	if (node->hasArgs()) {
		NodeList& args = node->getArgs()->getNodes();
		NodeList::const_iterator it = args.begin(), end = args.end();

		while (it != end) {
			Operand operand;

			(*it)->accept(*this);

			if ((*it)->isLiteral()) {
				operand.op_type = FETCH_CONST;
				operand.value_id = static_cast<Literal*>(*it)->getConstId();
			} else {
				operand.op_type = FETCH_VAL;
				operand.value_id = (*it)->getValueId();
				operand.scope_id = (*it)->getScopeId();
			}
			m_ir.push_back(IR(OP_SEND_VAL, operand));
			++it;
		}
	}

	m_ir.push_back(IR(OP_FCALL,
		Operand(FETCH_VAL, sym->value_id, sym->scope->getId())));
}

void Codegen::visit(FunctionDecl* node)
{
	const CString* name = node->getIdent()->getName();
	Symbol* sym = m_scope->getLocal(name);
	size_t start_func;

	if (sym) {
		m_compiler->errorf(node->getLocation(),
			"Function `%S' already defined in the scope!", name);
	}

	Function* func = static_cast<Function*>(CLEVER_FUNC_TYPE->allocData());

	func->setName(*name);
	func->setUserDefined();
	func->setAddr(m_ir.size());

	Value* fval = new Value();
	fval->setType(CLEVER_FUNC_TYPE);
	fval->setObj(func);

	m_scope->pushValue(name, fval);

	start_func = m_ir.size();

	// XXX: what's the point of a jump here?
	m_ir.push_back(IR(OP_JMP, Operand(JMP_ADDR, 0)));

	// TODO: find a cleaner way to enter and leave scopes
	m_scope = m_scope->newLexicalScope();
	m_scope->setId(m_scope_id);
	m_scope_pool[m_scope_id++] = m_scope;

	if (node->hasArgs()) {
		for (size_t i = 0; i < node->numArgs(); ++i) {
			VariableDecl* decl = static_cast<VariableDecl*>(node->getArg(i));

			if (decl->hasAssignment()) {
				decl->getAssignment()->setConditional(true);
			}
		}

		node->getArgs()->accept(*this);
	}

	node->getBlock()->accept(*this);

	m_scope = m_scope->getParent();

	m_ir.push_back(IR(OP_LEAVE));

	m_ir[start_func].op1.value_id = m_ir.size();
}

void Codegen::visit(Return* node)
{
	// TODO: return value
	m_ir.push_back(IR(OP_RET));
}

void Codegen::visit(While* node)
{
	size_t start_while = m_ir.size();

	node->getCondition()->accept(*this);

	m_ir.push_back(IR(OP_JMPZ));

	node->getBlock()->accept(*this);

	m_ir.push_back(IR(OP_JMP, Operand(JMP_ADDR, start_while)));

	m_ir[start_while].op2.value_id = m_ir.size();
}

}} // clever::ast
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2016 Shanghai Jiao Tong University.
 *     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.
 *
 * For more about this software visit:
 *
 *      http://ipads.se.sjtu.edu.cn/projects/wukong
 *
 */

#pragma once

#include <map>
#include <string>
#include <fstream>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <sstream>
#include <boost/algorithm/string/predicate.hpp>

#include "rdma.hpp"
#include "assertion.hpp"

using namespace std;

int global_num_servers = 1;    // the number of servers
int global_num_threads = 2;    // the number of threads per server (incl. proxy and engine)

int global_num_proxies = 1;    // the number of proxies
int global_num_engines = 1;    // the number of engines

string global_input_folder;

int global_data_port_base = 5500;
int global_ctrl_port_base = 9576;

int global_memstore_size_gb = 20;
int global_rdma_buf_size_mb = 64;
int global_rdma_rbf_size_mb = 16;

bool global_use_rdma = true;
bool global_generate_statistics = true;
bool global_enable_caching = true;
bool global_enable_workstealing = false;

int global_mt_threshold = 16;
int global_rdma_threshold = 300;

bool global_silent = true;  // don't take back results by default

bool global_enable_planner = true;  // for planner

bool global_enable_vattr = false;  // for attr

// GPU related
int global_gpu_num_agents = 1;
int global_gpu_rdma_buf_size_mb = 64;

static bool set_immutable_config(string cfg_name, string value)
{
    if (cfg_name == "global_num_proxies") {
        global_num_proxies = atoi(value.c_str());
        ASSERT(global_num_proxies > 0);
    } else if (cfg_name == "global_num_engines") {
        global_num_engines = atoi(value.c_str());
        ASSERT(global_num_engines > 0);
    } else if (cfg_name == "global_input_folder") {
        global_input_folder = value;

        // make sure to check that the global_input_folder is non-empty.
        if (global_input_folder.length() == 0) {
            logstream(LOG_ERROR) << "the directory path of RDF data can not be empty!"
                                 << "You should set \"global_input_folder\" in config file." << LOG_endl;
            exit(-1);
        }

        // force a "/" at the end of global_input_folder.
        if (global_input_folder[global_input_folder.length() - 1] != '/')
            global_input_folder = global_input_folder + "/";
    } else if (cfg_name == "global_data_port_base") {
        global_data_port_base = atoi(value.c_str());
        ASSERT(global_data_port_base > 0);
    } else if (cfg_name == "global_ctrl_port_base") {
        global_ctrl_port_base = atoi(value.c_str());
        ASSERT(global_ctrl_port_base > 0);
    } else if (cfg_name == "global_memstore_size_gb") {
        global_memstore_size_gb = atoi(value.c_str());
        ASSERT(global_memstore_size_gb > 0);
    } else if (cfg_name == "global_rdma_buf_size_mb") {
        global_rdma_buf_size_mb = atoi(value.c_str());
        ASSERT(global_rdma_buf_size_mb > 0);
    } else if (cfg_name == "global_rdma_rbf_size_mb") {
        global_rdma_rbf_size_mb = atoi(value.c_str());
        ASSERT(global_rdma_rbf_size_mb > 0);
    } else if (cfg_name == "global_generate_statistics") {
        global_generate_statistics = atoi(value.c_str());
    } else if (cfg_name == "global_gpu_num_agents") {
		global_gpu_num_agents = atoi(value.c_str());
	} else if (cfg_name == "global_gpu_rdma_buf_size_mb") {
		global_gpu_rdma_buf_size_mb = atoi(value.c_str());
	}
    else {
        return false;
    }

    return true;
}

static bool set_mutable_config(string cfg_name, string value)
{
    if (cfg_name == "global_use_rdma") {
        if (atoi(value.c_str())) {
            if (!RDMA::get_rdma().has_rdma()) {
                logstream(LOG_ERROR) << "can't enable RDMA due to building Wukong w/o RDMA support!\n"
                                     << "HINT: please disable global_use_rdma in config file." << LOG_endl;
                global_use_rdma = false; // disable RDMA if no RDMA device
                return true;
            }

            global_use_rdma = true;
        } else {
            global_use_rdma = false;
        }
    } else if (cfg_name == "global_rdma_threshold") {
        global_rdma_threshold = atoi(value.c_str());
    } else if (cfg_name == "global_mt_threshold") {
        global_mt_threshold = atoi(value.c_str());
        ASSERT(global_mt_threshold > 0);
    } else if (cfg_name == "global_enable_caching") {
        global_enable_caching = atoi(value.c_str());
    } else if (cfg_name == "global_enable_workstealing") {
        global_enable_workstealing = atoi(value.c_str());
    } else if (cfg_name == "global_silent") {
        global_silent = atoi(value.c_str());
    } else if (cfg_name == "global_enable_planner") {
        global_enable_planner = atoi(value.c_str());
    } else if (cfg_name == "global_enable_vattr") {
        global_enable_vattr = atoi(value.c_str());
    } else {
        return false;
    }

    return true;
}

static void str2items(string str, map<string, string> &items)
{
    istringstream iss(str);
    string row, val;
    while (iss >> row >> val)
        items[row] = val;
}

static void file2items(string fname, map<string, string> &items)
{
    ifstream file(fname.c_str());
    if (!file) {
        logstream(LOG_ERROR) << fname << " does not exist." << LOG_endl;
        exit(0);
    }

    string line, row, val;
    while (std::getline(file, line)) {
        if (boost::starts_with(line, "#") || line.empty())
            continue; // skip comments and blank lines

        istringstream iss(line);
        iss >> row >> val;
        items[row] = val;
    }
}

/**
 * reload config
 */
void reload_config(string str)
{
    // TODO: it should ensure that there is no outstanding queries.

    // load config file
    map<string, string> items;
    str2items(str, items);

    for (auto const &entry : items)
        set_mutable_config(entry.first, entry.second);

    // limited the number of engines
    global_mt_threshold = max(1, min(global_mt_threshold, global_num_engines));

    return;
}

/**
 * load config
 */
void load_config(string fname, int num_servers)
{
    global_num_servers = num_servers;
    ASSERT(num_servers > 0);

    // load config file
    map<string, string> items;
    file2items(fname, items);

    for (auto const &entry : items) {
        if (!(set_immutable_config(entry.first, entry.second)
                || set_mutable_config(entry.first, entry.second))) {
            logstream(LOG_WARNING) << "unsupported configuration item! ("
                                   << entry.first << ")" << LOG_endl;
        }
    }

    // set the total number of threads
    global_num_threads = global_num_engines + global_num_proxies;

    // limited the number of engines
    global_mt_threshold = max(1, min(global_mt_threshold, global_num_engines));

    return;
}

/**
 * print current config
 */
void print_config(void)
{
    logstream(LOG_INFO) << "------ global configurations ------" << LOG_endl;

    // setting by config file
    logstream(LOG_INFO) << "the number of proxies: "        << global_num_proxies           << LOG_endl;
    logstream(LOG_INFO) << "the number of engines: "        << global_num_engines           << LOG_endl;
    logstream(LOG_INFO) << "global_input_folder: "      << global_input_folder          << LOG_endl;
    logstream(LOG_INFO) << "global_data_port_base: "        << global_data_port_base        << LOG_endl;
    logstream(LOG_INFO) << "global_ctrl_port_base: "        << global_ctrl_port_base        << LOG_endl;
    logstream(LOG_INFO) << "global_memstore_size_gb: "  << global_memstore_size_gb      << LOG_endl;
    logstream(LOG_INFO) << "global_rdma_buf_size_mb: "  << global_rdma_buf_size_mb      << LOG_endl;
    logstream(LOG_INFO) << "global_rdma_rbf_size_mb: "  << global_rdma_rbf_size_mb      << LOG_endl;
    logstream(LOG_INFO) << "global_use_rdma: "          << global_use_rdma              << LOG_endl;
    logstream(LOG_INFO) << "global_enable_caching: "        << global_enable_caching        << LOG_endl;
    logstream(LOG_INFO) << "global_enable_workstealing: "   << global_enable_workstealing   << LOG_endl;
    logstream(LOG_INFO) << "global_rdma_threshold: "        << global_rdma_threshold        << LOG_endl;
    logstream(LOG_INFO) << "global_mt_threshold: "      << global_mt_threshold          << LOG_endl;
    logstream(LOG_INFO) << "global_silent: "                << global_silent                << LOG_endl;
    logstream(LOG_INFO) << "global_enable_planner: "        << global_enable_planner        << LOG_endl;
    logstream(LOG_INFO) << "global_generate_statistics: "   << global_generate_statistics   << LOG_endl;
    logstream(LOG_INFO) << "global_enable_vattr: "      << global_enable_vattr          << LOG_endl;
#ifdef USE_GPU
    logstream(LOG_INFO) << "GPU related configurations:" << LOG_endl;
    logstream(LOG_INFO) << "global_gpu_num_agents: "        << global_gpu_num_agents        << LOG_endl;
    logstream(LOG_INFO) << "global_gpu_rdma_buf_size_mb: "  << global_gpu_rdma_buf_size_mb  << LOG_endl;
#endif

    logstream(LOG_INFO) << "--" << LOG_endl;

    // compute from other settings
    logstream(LOG_INFO) << "the number of servers: "        << global_num_servers           << LOG_endl;
    logstream(LOG_INFO) << "the number of threads: "        << global_num_threads           << LOG_endl;

}
<commit_msg>surround gpu-related configurations with macro<commit_after>/*
 * Copyright (c) 2016 Shanghai Jiao Tong University.
 *     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.
 *
 * For more about this software visit:
 *
 *      http://ipads.se.sjtu.edu.cn/projects/wukong
 *
 */

#pragma once

#include <map>
#include <string>
#include <fstream>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <sstream>
#include <boost/algorithm/string/predicate.hpp>

#include "rdma.hpp"
#include "assertion.hpp"

using namespace std;

int global_num_servers = 1;    // the number of servers
int global_num_threads = 2;    // the number of threads per server (incl. proxy and engine)

int global_num_proxies = 1;    // the number of proxies
int global_num_engines = 1;    // the number of engines

string global_input_folder;

int global_data_port_base = 5500;
int global_ctrl_port_base = 9576;

int global_memstore_size_gb = 20;
int global_rdma_buf_size_mb = 64;
int global_rdma_rbf_size_mb = 16;

bool global_use_rdma = true;
bool global_generate_statistics = true;
bool global_enable_caching = true;
bool global_enable_workstealing = false;

int global_mt_threshold = 16;
int global_rdma_threshold = 300;

bool global_silent = true;  // don't take back results by default

bool global_enable_planner = true;  // for planner

bool global_enable_vattr = false;  // for attr

#ifdef USE_GPU
// GPU-related configurations
int global_gpu_num_agents = 1;
int global_gpu_rdma_buf_size_mb = 64;
#endif

static bool set_immutable_config(string cfg_name, string value)
{
    if (cfg_name == "global_num_proxies") {
        global_num_proxies = atoi(value.c_str());
        ASSERT(global_num_proxies > 0);
    } else if (cfg_name == "global_num_engines") {
        global_num_engines = atoi(value.c_str());
        ASSERT(global_num_engines > 0);
    } else if (cfg_name == "global_input_folder") {
        global_input_folder = value;

        // make sure to check that the global_input_folder is non-empty.
        if (global_input_folder.length() == 0) {
            logstream(LOG_ERROR) << "the directory path of RDF data can not be empty!"
                                 << "You should set \"global_input_folder\" in config file." << LOG_endl;
            exit(-1);
        }

        // force a "/" at the end of global_input_folder.
        if (global_input_folder[global_input_folder.length() - 1] != '/')
            global_input_folder = global_input_folder + "/";
    } else if (cfg_name == "global_data_port_base") {
        global_data_port_base = atoi(value.c_str());
        ASSERT(global_data_port_base > 0);
    } else if (cfg_name == "global_ctrl_port_base") {
        global_ctrl_port_base = atoi(value.c_str());
        ASSERT(global_ctrl_port_base > 0);
    } else if (cfg_name == "global_memstore_size_gb") {
        global_memstore_size_gb = atoi(value.c_str());
        ASSERT(global_memstore_size_gb > 0);
    } else if (cfg_name == "global_rdma_buf_size_mb") {
        global_rdma_buf_size_mb = atoi(value.c_str());
        ASSERT(global_rdma_buf_size_mb > 0);
    } else if (cfg_name == "global_rdma_rbf_size_mb") {
        global_rdma_rbf_size_mb = atoi(value.c_str());
        ASSERT(global_rdma_rbf_size_mb > 0);
    } else if (cfg_name == "global_generate_statistics") {
        global_generate_statistics = atoi(value.c_str());
    }
#ifdef USE_GPU
    else if (cfg_name == "global_gpu_num_agents") {
		global_gpu_num_agents = atoi(value.c_str());
	} else if (cfg_name == "global_gpu_rdma_buf_size_mb") {
		global_gpu_rdma_buf_size_mb = atoi(value.c_str());
	}
#endif
    else {
        return false;
    }

    return true;
}

static bool set_mutable_config(string cfg_name, string value)
{
    if (cfg_name == "global_use_rdma") {
        if (atoi(value.c_str())) {
            if (!RDMA::get_rdma().has_rdma()) {
                logstream(LOG_ERROR) << "can't enable RDMA due to building Wukong w/o RDMA support!\n"
                                     << "HINT: please disable global_use_rdma in config file." << LOG_endl;
                global_use_rdma = false; // disable RDMA if no RDMA device
                return true;
            }

            global_use_rdma = true;
        } else {
            global_use_rdma = false;
        }
    } else if (cfg_name == "global_rdma_threshold") {
        global_rdma_threshold = atoi(value.c_str());
    } else if (cfg_name == "global_mt_threshold") {
        global_mt_threshold = atoi(value.c_str());
        ASSERT(global_mt_threshold > 0);
    } else if (cfg_name == "global_enable_caching") {
        global_enable_caching = atoi(value.c_str());
    } else if (cfg_name == "global_enable_workstealing") {
        global_enable_workstealing = atoi(value.c_str());
    } else if (cfg_name == "global_silent") {
        global_silent = atoi(value.c_str());
    } else if (cfg_name == "global_enable_planner") {
        global_enable_planner = atoi(value.c_str());
    } else if (cfg_name == "global_enable_vattr") {
        global_enable_vattr = atoi(value.c_str());
    } else {
        return false;
    }

    return true;
}

static void str2items(string str, map<string, string> &items)
{
    istringstream iss(str);
    string row, val;
    while (iss >> row >> val)
        items[row] = val;
}

static void file2items(string fname, map<string, string> &items)
{
    ifstream file(fname.c_str());
    if (!file) {
        logstream(LOG_ERROR) << fname << " does not exist." << LOG_endl;
        exit(0);
    }

    string line, row, val;
    while (std::getline(file, line)) {
        if (boost::starts_with(line, "#") || line.empty())
            continue; // skip comments and blank lines

        istringstream iss(line);
        iss >> row >> val;
        items[row] = val;
    }
}

/**
 * reload config
 */
void reload_config(string str)
{
    // TODO: it should ensure that there is no outstanding queries.

    // load config file
    map<string, string> items;
    str2items(str, items);

    for (auto const &entry : items)
        set_mutable_config(entry.first, entry.second);

    // limited the number of engines
    global_mt_threshold = max(1, min(global_mt_threshold, global_num_engines));

    return;
}

/**
 * load config
 */
void load_config(string fname, int num_servers)
{
    global_num_servers = num_servers;
    ASSERT(num_servers > 0);

    // load config file
    map<string, string> items;
    file2items(fname, items);

    for (auto const &entry : items) {
        if (!(set_immutable_config(entry.first, entry.second)
                || set_mutable_config(entry.first, entry.second))) {
            logstream(LOG_WARNING) << "unsupported configuration item! ("
                                   << entry.first << ")" << LOG_endl;
        }
    }

    // set the total number of threads
    global_num_threads = global_num_engines + global_num_proxies;

    // limited the number of engines
    global_mt_threshold = max(1, min(global_mt_threshold, global_num_engines));

    return;
}

/**
 * print current config
 */
void print_config(void)
{
    logstream(LOG_INFO) << "------ global configurations ------" << LOG_endl;

    // setting by config file
    logstream(LOG_INFO) << "the number of proxies: "        << global_num_proxies           << LOG_endl;
    logstream(LOG_INFO) << "the number of engines: "        << global_num_engines           << LOG_endl;
    logstream(LOG_INFO) << "global_input_folder: "      << global_input_folder          << LOG_endl;
    logstream(LOG_INFO) << "global_data_port_base: "        << global_data_port_base        << LOG_endl;
    logstream(LOG_INFO) << "global_ctrl_port_base: "        << global_ctrl_port_base        << LOG_endl;
    logstream(LOG_INFO) << "global_memstore_size_gb: "  << global_memstore_size_gb      << LOG_endl;
    logstream(LOG_INFO) << "global_rdma_buf_size_mb: "  << global_rdma_buf_size_mb      << LOG_endl;
    logstream(LOG_INFO) << "global_rdma_rbf_size_mb: "  << global_rdma_rbf_size_mb      << LOG_endl;
    logstream(LOG_INFO) << "global_use_rdma: "          << global_use_rdma              << LOG_endl;
    logstream(LOG_INFO) << "global_enable_caching: "        << global_enable_caching        << LOG_endl;
    logstream(LOG_INFO) << "global_enable_workstealing: "   << global_enable_workstealing   << LOG_endl;
    logstream(LOG_INFO) << "global_rdma_threshold: "        << global_rdma_threshold        << LOG_endl;
    logstream(LOG_INFO) << "global_mt_threshold: "      << global_mt_threshold          << LOG_endl;
    logstream(LOG_INFO) << "global_silent: "                << global_silent                << LOG_endl;
    logstream(LOG_INFO) << "global_enable_planner: "        << global_enable_planner        << LOG_endl;
    logstream(LOG_INFO) << "global_generate_statistics: "   << global_generate_statistics   << LOG_endl;
    logstream(LOG_INFO) << "global_enable_vattr: "      << global_enable_vattr          << LOG_endl;

#ifdef USE_GPU
    logstream(LOG_INFO) << "GPU related configurations:" << LOG_endl;
    logstream(LOG_INFO) << "global_gpu_num_agents: "        << global_gpu_num_agents        << LOG_endl;
    logstream(LOG_INFO) << "global_gpu_rdma_buf_size_mb: "  << global_gpu_rdma_buf_size_mb  << LOG_endl;
#endif

    logstream(LOG_INFO) << "--" << LOG_endl;

    // compute from other settings
    logstream(LOG_INFO) << "the number of servers: "        << global_num_servers           << LOG_endl;
    logstream(LOG_INFO) << "the number of threads: "        << global_num_threads           << LOG_endl;

}
<|endoftext|>


<commit_before>#ifndef ENTT_SIGNAL_DELEGATE_HPP
#define ENTT_SIGNAL_DELEGATE_HPP

#include <tuple>
#include <cstddef>
#include <utility>
#include <functional>
#include <type_traits>
#include "../config/config.h"

namespace entt {

/**
 * @cond TURN_OFF_DOXYGEN
 * Internal details not to be documented.
 */

namespace internal {

template<typename Ret, typename... Args>
auto function_pointer(Ret(*)(Args...)) -> Ret(*)(Args...);

template<typename Ret, typename Type, typename... Args, typename Other>
auto function_pointer(Ret(*)(Type, Args...), Other &&) -> Ret(*)(Args...);

template<typename Class, typename Ret, typename... Args, typename... Other>
auto function_pointer(Ret(Class:: *)(Args...), Other &&...) -> Ret(*)(Args...);

template<typename Class, typename Ret, typename... Args, typename... Other>
auto function_pointer(Ret(Class:: *)(Args...) const, Other &&...) -> Ret(*)(Args...);

template<typename Class, typename Type, typename... Other>
auto function_pointer(Type Class:: *, Other &&...) -> Type(*)();

template<typename... Type>
using function_pointer_t = decltype(internal::function_pointer(std::declval<Type>()...));

template<typename... Class, typename Ret, typename... Args>
[[nodiscard]] constexpr auto index_sequence_for(Ret(*)(Args...)) {
    return std::index_sequence_for<Class..., Args...>{};
}

}

/**
 * Internal details not to be documented.
 * @endcond
 */

/*! @brief Used to wrap a function or a member of a specified type. */
template<auto>
struct connect_arg_t {};

/*! @brief Constant of type connect_arg_t used to disambiguate calls. */
template<auto Func>
inline constexpr connect_arg_t<Func> connect_arg{};

/**
 * @brief Basic delegate implementation.
 *
 * Primary template isn't defined on purpose. All the specializations give a
 * compile-time error unless the template parameter is a function type.
 */
template<typename>
class delegate;

/**
 * @brief Utility class to use to send around functions and members.
 *
 * Unmanaged delegate for function pointers and members. Users of this class are
 * in charge of disconnecting instances before deleting them.
 *
 * A delegate can be used as a general purpose invoker without memory overhead
 * for free functions possibly with payloads and bound or unbound members.
 *
 * @tparam Ret Return type of a function type.
 * @tparam Args Types of arguments of a function type.
 */
template<typename Ret, typename... Args>
class delegate<Ret(Args...)> {
    template<auto Candidate, std::size_t... Index>
    [[nodiscard]] auto wrap(std::index_sequence<Index...>) ENTT_NOEXCEPT {
        return [](const void *, Args... args) -> Ret {
            [[maybe_unused]] const auto arguments = std::forward_as_tuple(std::forward<Args>(args)...);
            return Ret(std::invoke(Candidate, std::forward<std::tuple_element_t<Index, std::tuple<Args...>>>(std::get<Index>(arguments))...));
        };
    }

    template<auto Candidate, typename Type, std::size_t... Index>
    [[nodiscard]] auto wrap(Type &, std::index_sequence<Index...>) ENTT_NOEXCEPT {
        return [](const void *payload, Args... args) -> Ret {
            [[maybe_unused]] const auto arguments = std::forward_as_tuple(std::forward<Args>(args)...);
            Type *curr = static_cast<Type *>(const_cast<std::conditional_t<std::is_const_v<Type>, const void *, void *>>(payload));
            return Ret(std::invoke(Candidate, *curr, std::forward<std::tuple_element_t<Index, std::tuple<Args...>>>(std::get<Index>(arguments))...));
        };
    }

    template<auto Candidate, typename Type, std::size_t... Index>
    [[nodiscard]] auto wrap(Type *, std::index_sequence<Index...>) ENTT_NOEXCEPT {
        return [](const void *payload, Args... args) -> Ret {
            [[maybe_unused]] const auto arguments = std::forward_as_tuple(std::forward<Args>(args)...);
            Type *curr = static_cast<Type *>(const_cast<std::conditional_t<std::is_const_v<Type>, const void *, void *>>(payload));
            return Ret(std::invoke(Candidate, curr, std::forward<std::tuple_element_t<Index, std::tuple<Args...>>>(std::get<Index>(arguments))...));
        };
    }

public:
    /*! @brief Function type of the contained target. */
    using function_type = Ret(const void *, Args...);
    /*! @brief Function type of the delegate. */
    using type = Ret(Args...);
    /*! @brief Return type of the delegate. */
    using result_type = Ret;

    /*! @brief Default constructor. */
    delegate() ENTT_NOEXCEPT
        : fn{nullptr}, data{nullptr}
    {}

    /**
     * @brief Constructs a delegate and connects a free function or an unbound
     * member.
     * @tparam Candidate Function or member to connect to the delegate.
     */
    template<auto Candidate>
    delegate(connect_arg_t<Candidate>) ENTT_NOEXCEPT {
        connect<Candidate>();
    }

    /**
     * @brief Constructs a delegate and connects a free function with payload or
     * a bound member.
     * @tparam Candidate Function or member to connect to the delegate.
     * @tparam Type Type of class or type of payload.
     * @param value_or_instance A valid object that fits the purpose.
     */
    template<auto Candidate, typename Type>
    delegate(connect_arg_t<Candidate>, Type &&value_or_instance) ENTT_NOEXCEPT {
        connect<Candidate>(std::forward<Type>(value_or_instance));
    }

    /**
     * @brief Constructs a delegate and connects an user defined function with
     * optional payload.
     * @param function Function to connect to the delegate.
     * @param payload User defined arbitrary data.
     */
    delegate(function_type *function, const void *payload = nullptr) ENTT_NOEXCEPT {
        connect(function, payload);
    }

    /**
     * @brief Connects a free function or an unbound member to a delegate.
     * @tparam Candidate Function or member to connect to the delegate.
     */
    template<auto Candidate>
    void connect() ENTT_NOEXCEPT {
        data = nullptr;

        if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), Args...>) {
            fn = [](const void *, Args... args) -> Ret {
                return Ret(std::invoke(Candidate, std::forward<Args>(args)...));
            };
        } else if constexpr(std::is_member_pointer_v<decltype(Candidate)>) {
            fn = wrap<Candidate>(internal::index_sequence_for<std::tuple_element_t<0, std::tuple<Args...>>>(internal::function_pointer_t<decltype(Candidate)>{}));
        } else {
            fn = wrap<Candidate>(internal::index_sequence_for(internal::function_pointer_t<decltype(Candidate)>{}));
        }
    }

    /**
     * @brief Connects a free function with payload or a bound member to a
     * delegate.
     *
     * The delegate isn't responsible for the connected object or the payload.
     * Users must always guarantee that the lifetime of the instance overcomes
     * the one of the delegate.

     * When used to connect a free function with payload, its signature must be
     * such that the instance is the first argument before the ones used to
     * define the delegate itself.
     *
     * @tparam Candidate Function or member to connect to the delegate.
     * @tparam Type Type of class or type of payload.
     * @param value_or_instance A valid reference that fits the purpose.
     */
    template<auto Candidate, typename Type>
    void connect(Type &value_or_instance) ENTT_NOEXCEPT {
        data = &value_or_instance;

        if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), Type &, Args...>) {
            fn = [](const void *payload, Args... args) -> Ret {
                Type *curr = static_cast<Type *>(const_cast<std::conditional_t<std::is_const_v<Type>, const void *, void *>>(payload));
                return Ret(std::invoke(Candidate, *curr, std::forward<Args>(args)...));
            };
        } else {
            fn = wrap<Candidate>(value_or_instance, internal::index_sequence_for(internal::function_pointer_t<decltype(Candidate), Type>{}));
        }
    }

    /**
     * @brief Connects a free function with payload or a bound member to a
     * delegate.
     *
     * @sa connect(Type &)
     *
     * @tparam Candidate Function or member to connect to the delegate.
     * @tparam Type Type of class or type of payload.
     * @param value_or_instance A valid pointer that fits the purpose.
     */
    template<auto Candidate, typename Type>
    void connect(Type *value_or_instance) ENTT_NOEXCEPT {
        data = value_or_instance;

        if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), Type *, Args...>) {
            fn = [](const void *payload, Args... args) -> Ret {
                Type *curr = static_cast<Type *>(const_cast<std::conditional_t<std::is_const_v<Type>, const void *, void *>>(payload));
                return Ret(std::invoke(Candidate, curr, std::forward<Args>(args)...));
            };
        } else {
            fn = wrap<Candidate>(value_or_instance, internal::index_sequence_for(internal::function_pointer_t<decltype(Candidate), Type>{}));
        }
    }

    /**
     * @brief Connects an user defined function with optional payload to a
     * delegate.
     *
     * The delegate isn't responsible for the connected object or the payload.
     * Users must always guarantee that the lifetime of an instance overcomes
     * the one of the delegate.

     * The payload is returned as the first argument to the target function in
     * all cases.
     *
     * @param function Function to connect to the delegate.
     * @param payload User defined arbitrary data.
     */
    void connect(function_type *function, const void *payload = nullptr) ENTT_NOEXCEPT {
        fn = function;
        data = payload;
    }

    /**
     * @brief Resets a delegate.
     *
     * After a reset, a delegate cannot be invoked anymore.
     */
    void reset() ENTT_NOEXCEPT {
        fn = nullptr;
        data = nullptr;
    }

    /**
     * @brief Returns the instance or the payload linked to a delegate, if any.
     * @return An opaque pointer to the underlying data.
     */
    [[nodiscard]] const void * instance() const ENTT_NOEXCEPT {
        return data;
    }

    /**
     * @brief Triggers a delegate.
     *
     * The delegate invokes the underlying function and returns the result.
     *
     * @warning
     * Attempting to trigger an invalid delegate results in undefined
     * behavior.
     *
     * @param args Arguments to use to invoke the underlying function.
     * @return The value returned by the underlying function.
     */
    Ret operator()(Args... args) const {
        ENTT_ASSERT(fn);
        return fn(data, std::forward<Args>(args)...);
    }

    /**
     * @brief Checks whether a delegate actually stores a listener.
     * @return False if the delegate is empty, true otherwise.
     */
    [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT {
        // no need to test also data
        return !(fn == nullptr);
    }

    /**
     * @brief Compares the contents of two delegates.
     * @param other Delegate with which to compare.
     * @return False if the two contents differ, true otherwise.
     */
    [[nodiscard]] bool operator==(const delegate<Ret(Args...)> &other) const ENTT_NOEXCEPT {
        return fn == other.fn && data == other.data;
    }

private:
    function_type *fn;
    const void *data;
};

/**
 * @brief Compares the contents of two delegates.
 * @tparam Ret Return type of a function type.
 * @tparam Args Types of arguments of a function type.
 * @param lhs A valid delegate object.
 * @param rhs A valid delegate object.
 * @return True if the two contents differ, false otherwise.
 */
template<typename Ret, typename... Args>
[[nodiscard]] bool operator!=(const delegate<Ret(Args...)> &lhs, const delegate<Ret(Args...)> &rhs) ENTT_NOEXCEPT {
    return !(lhs == rhs);
}

/**
 * @brief Deduction guide.
 * @tparam Candidate Function or member to connect to the delegate.
 */
template<auto Candidate>
delegate(connect_arg_t<Candidate>) ENTT_NOEXCEPT
-> delegate<std::remove_pointer_t<internal::function_pointer_t<decltype(Candidate)>>>;

/**
 * @brief Deduction guide.
 * @tparam Candidate Function or member to connect to the delegate.
 * @tparam Type Type of class or type of payload.
 */
template<auto Candidate, typename Type>
delegate(connect_arg_t<Candidate>, Type &&) ENTT_NOEXCEPT
-> delegate<std::remove_pointer_t<internal::function_pointer_t<decltype(Candidate), Type>>>;

/**
 * @brief Deduction guide.
 * @tparam Ret Return type of a function type.
 * @tparam Args Types of arguments of a function type.
 */
template<typename Ret, typename... Args>
delegate(Ret(*)(const void *, Args...), const void * = nullptr) ENTT_NOEXCEPT
-> delegate<Ret(Args...)>;

}

#endif
<commit_msg>delegate: use constness_as_t internally<commit_after>#ifndef ENTT_SIGNAL_DELEGATE_HPP
#define ENTT_SIGNAL_DELEGATE_HPP

#include <tuple>
#include <cstddef>
#include <utility>
#include <functional>
#include <type_traits>
#include "../core/type_traits.hpp"
#include "../config/config.h"

namespace entt {

/**
 * @cond TURN_OFF_DOXYGEN
 * Internal details not to be documented.
 */

namespace internal {

template<typename Ret, typename... Args>
auto function_pointer(Ret(*)(Args...)) -> Ret(*)(Args...);

template<typename Ret, typename Type, typename... Args, typename Other>
auto function_pointer(Ret(*)(Type, Args...), Other &&) -> Ret(*)(Args...);

template<typename Class, typename Ret, typename... Args, typename... Other>
auto function_pointer(Ret(Class:: *)(Args...), Other &&...) -> Ret(*)(Args...);

template<typename Class, typename Ret, typename... Args, typename... Other>
auto function_pointer(Ret(Class:: *)(Args...) const, Other &&...) -> Ret(*)(Args...);

template<typename Class, typename Type, typename... Other>
auto function_pointer(Type Class:: *, Other &&...) -> Type(*)();

template<typename... Type>
using function_pointer_t = decltype(internal::function_pointer(std::declval<Type>()...));

template<typename... Class, typename Ret, typename... Args>
[[nodiscard]] constexpr auto index_sequence_for(Ret(*)(Args...)) {
    return std::index_sequence_for<Class..., Args...>{};
}

}

/**
 * Internal details not to be documented.
 * @endcond
 */

/*! @brief Used to wrap a function or a member of a specified type. */
template<auto>
struct connect_arg_t {};

/*! @brief Constant of type connect_arg_t used to disambiguate calls. */
template<auto Func>
inline constexpr connect_arg_t<Func> connect_arg{};

/**
 * @brief Basic delegate implementation.
 *
 * Primary template isn't defined on purpose. All the specializations give a
 * compile-time error unless the template parameter is a function type.
 */
template<typename>
class delegate;

/**
 * @brief Utility class to use to send around functions and members.
 *
 * Unmanaged delegate for function pointers and members. Users of this class are
 * in charge of disconnecting instances before deleting them.
 *
 * A delegate can be used as a general purpose invoker without memory overhead
 * for free functions possibly with payloads and bound or unbound members.
 *
 * @tparam Ret Return type of a function type.
 * @tparam Args Types of arguments of a function type.
 */
template<typename Ret, typename... Args>
class delegate<Ret(Args...)> {
    template<auto Candidate, std::size_t... Index>
    [[nodiscard]] auto wrap(std::index_sequence<Index...>) ENTT_NOEXCEPT {
        return [](const void *, Args... args) -> Ret {
            [[maybe_unused]] const auto arguments = std::forward_as_tuple(std::forward<Args>(args)...);
            return Ret(std::invoke(Candidate, std::forward<std::tuple_element_t<Index, std::tuple<Args...>>>(std::get<Index>(arguments))...));
        };
    }

    template<auto Candidate, typename Type, std::size_t... Index>
    [[nodiscard]] auto wrap(Type &, std::index_sequence<Index...>) ENTT_NOEXCEPT {
        return [](const void *payload, Args... args) -> Ret {
            [[maybe_unused]] const auto arguments = std::forward_as_tuple(std::forward<Args>(args)...);
            Type *curr = static_cast<Type *>(const_cast<constness_as_t<void, Type> *>(payload));
            return Ret(std::invoke(Candidate, *curr, std::forward<std::tuple_element_t<Index, std::tuple<Args...>>>(std::get<Index>(arguments))...));
        };
    }

    template<auto Candidate, typename Type, std::size_t... Index>
    [[nodiscard]] auto wrap(Type *, std::index_sequence<Index...>) ENTT_NOEXCEPT {
        return [](const void *payload, Args... args) -> Ret {
            [[maybe_unused]] const auto arguments = std::forward_as_tuple(std::forward<Args>(args)...);
            Type *curr = static_cast<Type *>(const_cast<constness_as_t<void, Type> *>(payload));
            return Ret(std::invoke(Candidate, curr, std::forward<std::tuple_element_t<Index, std::tuple<Args...>>>(std::get<Index>(arguments))...));
        };
    }

public:
    /*! @brief Function type of the contained target. */
    using function_type = Ret(const void *, Args...);
    /*! @brief Function type of the delegate. */
    using type = Ret(Args...);
    /*! @brief Return type of the delegate. */
    using result_type = Ret;

    /*! @brief Default constructor. */
    delegate() ENTT_NOEXCEPT
        : fn{nullptr}, data{nullptr}
    {}

    /**
     * @brief Constructs a delegate and connects a free function or an unbound
     * member.
     * @tparam Candidate Function or member to connect to the delegate.
     */
    template<auto Candidate>
    delegate(connect_arg_t<Candidate>) ENTT_NOEXCEPT {
        connect<Candidate>();
    }

    /**
     * @brief Constructs a delegate and connects a free function with payload or
     * a bound member.
     * @tparam Candidate Function or member to connect to the delegate.
     * @tparam Type Type of class or type of payload.
     * @param value_or_instance A valid object that fits the purpose.
     */
    template<auto Candidate, typename Type>
    delegate(connect_arg_t<Candidate>, Type &&value_or_instance) ENTT_NOEXCEPT {
        connect<Candidate>(std::forward<Type>(value_or_instance));
    }

    /**
     * @brief Constructs a delegate and connects an user defined function with
     * optional payload.
     * @param function Function to connect to the delegate.
     * @param payload User defined arbitrary data.
     */
    delegate(function_type *function, const void *payload = nullptr) ENTT_NOEXCEPT {
        connect(function, payload);
    }

    /**
     * @brief Connects a free function or an unbound member to a delegate.
     * @tparam Candidate Function or member to connect to the delegate.
     */
    template<auto Candidate>
    void connect() ENTT_NOEXCEPT {
        data = nullptr;

        if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), Args...>) {
            fn = [](const void *, Args... args) -> Ret {
                return Ret(std::invoke(Candidate, std::forward<Args>(args)...));
            };
        } else if constexpr(std::is_member_pointer_v<decltype(Candidate)>) {
            fn = wrap<Candidate>(internal::index_sequence_for<std::tuple_element_t<0, std::tuple<Args...>>>(internal::function_pointer_t<decltype(Candidate)>{}));
        } else {
            fn = wrap<Candidate>(internal::index_sequence_for(internal::function_pointer_t<decltype(Candidate)>{}));
        }
    }

    /**
     * @brief Connects a free function with payload or a bound member to a
     * delegate.
     *
     * The delegate isn't responsible for the connected object or the payload.
     * Users must always guarantee that the lifetime of the instance overcomes
     * the one of the delegate.

     * When used to connect a free function with payload, its signature must be
     * such that the instance is the first argument before the ones used to
     * define the delegate itself.
     *
     * @tparam Candidate Function or member to connect to the delegate.
     * @tparam Type Type of class or type of payload.
     * @param value_or_instance A valid reference that fits the purpose.
     */
    template<auto Candidate, typename Type>
    void connect(Type &value_or_instance) ENTT_NOEXCEPT {
        data = &value_or_instance;

        if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), Type &, Args...>) {
            fn = [](const void *payload, Args... args) -> Ret {
                Type *curr = static_cast<Type *>(const_cast<constness_as_t<void, Type> *>(payload));
                return Ret(std::invoke(Candidate, *curr, std::forward<Args>(args)...));
            };
        } else {
            fn = wrap<Candidate>(value_or_instance, internal::index_sequence_for(internal::function_pointer_t<decltype(Candidate), Type>{}));
        }
    }

    /**
     * @brief Connects a free function with payload or a bound member to a
     * delegate.
     *
     * @sa connect(Type &)
     *
     * @tparam Candidate Function or member to connect to the delegate.
     * @tparam Type Type of class or type of payload.
     * @param value_or_instance A valid pointer that fits the purpose.
     */
    template<auto Candidate, typename Type>
    void connect(Type *value_or_instance) ENTT_NOEXCEPT {
        data = value_or_instance;

        if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), Type *, Args...>) {
            fn = [](const void *payload, Args... args) -> Ret {
                Type *curr = static_cast<Type *>(const_cast<constness_as_t<void, Type> *>(payload));
                return Ret(std::invoke(Candidate, curr, std::forward<Args>(args)...));
            };
        } else {
            fn = wrap<Candidate>(value_or_instance, internal::index_sequence_for(internal::function_pointer_t<decltype(Candidate), Type>{}));
        }
    }

    /**
     * @brief Connects an user defined function with optional payload to a
     * delegate.
     *
     * The delegate isn't responsible for the connected object or the payload.
     * Users must always guarantee that the lifetime of an instance overcomes
     * the one of the delegate.

     * The payload is returned as the first argument to the target function in
     * all cases.
     *
     * @param function Function to connect to the delegate.
     * @param payload User defined arbitrary data.
     */
    void connect(function_type *function, const void *payload = nullptr) ENTT_NOEXCEPT {
        fn = function;
        data = payload;
    }

    /**
     * @brief Resets a delegate.
     *
     * After a reset, a delegate cannot be invoked anymore.
     */
    void reset() ENTT_NOEXCEPT {
        fn = nullptr;
        data = nullptr;
    }

    /**
     * @brief Returns the instance or the payload linked to a delegate, if any.
     * @return An opaque pointer to the underlying data.
     */
    [[nodiscard]] const void * instance() const ENTT_NOEXCEPT {
        return data;
    }

    /**
     * @brief Triggers a delegate.
     *
     * The delegate invokes the underlying function and returns the result.
     *
     * @warning
     * Attempting to trigger an invalid delegate results in undefined
     * behavior.
     *
     * @param args Arguments to use to invoke the underlying function.
     * @return The value returned by the underlying function.
     */
    Ret operator()(Args... args) const {
        ENTT_ASSERT(fn);
        return fn(data, std::forward<Args>(args)...);
    }

    /**
     * @brief Checks whether a delegate actually stores a listener.
     * @return False if the delegate is empty, true otherwise.
     */
    [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT {
        // no need to test also data
        return !(fn == nullptr);
    }

    /**
     * @brief Compares the contents of two delegates.
     * @param other Delegate with which to compare.
     * @return False if the two contents differ, true otherwise.
     */
    [[nodiscard]] bool operator==(const delegate<Ret(Args...)> &other) const ENTT_NOEXCEPT {
        return fn == other.fn && data == other.data;
    }

private:
    function_type *fn;
    const void *data;
};

/**
 * @brief Compares the contents of two delegates.
 * @tparam Ret Return type of a function type.
 * @tparam Args Types of arguments of a function type.
 * @param lhs A valid delegate object.
 * @param rhs A valid delegate object.
 * @return True if the two contents differ, false otherwise.
 */
template<typename Ret, typename... Args>
[[nodiscard]] bool operator!=(const delegate<Ret(Args...)> &lhs, const delegate<Ret(Args...)> &rhs) ENTT_NOEXCEPT {
    return !(lhs == rhs);
}

/**
 * @brief Deduction guide.
 * @tparam Candidate Function or member to connect to the delegate.
 */
template<auto Candidate>
delegate(connect_arg_t<Candidate>) ENTT_NOEXCEPT
-> delegate<std::remove_pointer_t<internal::function_pointer_t<decltype(Candidate)>>>;

/**
 * @brief Deduction guide.
 * @tparam Candidate Function or member to connect to the delegate.
 * @tparam Type Type of class or type of payload.
 */
template<auto Candidate, typename Type>
delegate(connect_arg_t<Candidate>, Type &&) ENTT_NOEXCEPT
-> delegate<std::remove_pointer_t<internal::function_pointer_t<decltype(Candidate), Type>>>;

/**
 * @brief Deduction guide.
 * @tparam Ret Return type of a function type.
 * @tparam Args Types of arguments of a function type.
 */
template<typename Ret, typename... Args>
delegate(Ret(*)(const void *, Args...), const void * = nullptr) ENTT_NOEXCEPT
-> delegate<Ret(Args...)>;

}

#endif
<|endoftext|>


<commit_before><commit_msg>Deleting the item from a form autofill popup with just one item would leave an empty autofill popup (not very visible but capturing focus).<commit_after><|endoftext|>