<commit_before>/*
 * Distributed under the OSI-approved Apache License, Version 2.0.  See
 * accompanying file Copyright.txt for details.
 *
 * InSituMPIWriter.cpp
 * Class to exchange data using MPI between Writer and Reader
 *  partition of an application
 * It requires MPI
 *
 *  Created on: Dec 18, 2017
 *      Author: Norbert Podhorszki pnorbert@ornl.gov
 */

#include "adios2/helper/adiosMath.h"

#include "InSituMPIFunctions.h"
#include "InSituMPISchedules.h"
#include "InSituMPIWriter.h"
#include "InSituMPIWriter.tcc"

#include <iostream>

namespace adios2
{
namespace core
{
namespace engine
{

InSituMPIWriter::InSituMPIWriter(IO &io, const std::string &name,
                                 const Mode mode, MPI_Comm mpiComm)
: Engine("InSituMPIWriter", io, name, mode, mpiComm),
  m_BP3Serializer(mpiComm, m_DebugMode)
{
    m_EndMessage = " in call to InSituMPIWriter " + m_Name + " Open\n";
    Init();
    m_BP3Serializer.InitParameters(m_IO.m_Parameters);

    m_RankAllPeers = insitumpi::FindPeers(mpiComm, m_Name, true, m_CommWorld);
    MPI_Comm_rank(m_CommWorld, &m_GlobalRank);
    MPI_Comm_size(m_CommWorld, &m_GlobalNproc);
    MPI_Comm_rank(mpiComm, &m_WriterRank);
    MPI_Comm_size(mpiComm, &m_WriterNproc);
    m_RankDirectPeers =
        insitumpi::AssignPeers(m_WriterRank, m_WriterNproc, m_RankAllPeers);
    if (m_Verbosity == 5)
    {
        std::cout << "InSituMPI Writer " << m_WriterRank << " Open(" << m_Name
                  << "). #readers=" << m_RankAllPeers.size()
                  << " #writers=" << m_WriterNproc
                  << " #appsize=" << m_GlobalNproc
                  << " #direct peers=" << m_RankDirectPeers.size() << std::endl;
    }
    insitumpi::ConnectDirectPeers(m_CommWorld, true,
                                  (m_BP3Serializer.m_RankMPI == 0),
                                  m_GlobalRank, m_RankDirectPeers);
}

InSituMPIWriter::~InSituMPIWriter() {}

StepStatus InSituMPIWriter::BeginStep(StepMode mode, const float timeoutSeconds)
{
    if (m_Verbosity == 5)
    {
        std::cout << "InSituMPI Writer " << m_WriterRank << " BeginStep()\n";
    }
    if (mode != StepMode::Append)
    {
        throw std::invalid_argument(
            "ERROR: InSituMPI engine only supports appending steps "
            "(BeginStep(adios2::StepMode::Append)");
    }

    m_CurrentStep++; // 0 is the first step
    if (m_Verbosity == 5)
    {
        std::cout << "InSituMPI Writer " << m_WriterRank << " new step "
                  << m_CurrentStep << " for " << m_Name << ". Notify peers..."
                  << std::endl;
    }
    // Send the step to all reader peers, asynchronously
    // We need to do some time a Wait on any Isend/Irecv otherwise
    // MPI_Comm_free() will never release the communicator
    m_MPIRequests.emplace_back();
    const int index = m_MPIRequests.size() - 1;
    for (auto peerRank : m_RankDirectPeers)
    {
        MPI_Isend(&m_CurrentStep, 1, MPI_INT, peerRank,
                  insitumpi::MpiTags::Step, m_CommWorld,
                  m_MPIRequests.data() + index);
    }

    m_NCallsPerformPuts = 0;
    m_BP3Serializer.m_DeferredVariables.clear();
    m_BP3Serializer.m_DeferredVariablesDataSize = 0;

    // start a fresh buffer with a new Process Group
    m_BP3Serializer.ResetBuffer(m_BP3Serializer.m_Data);
    if (!m_BP3Serializer.m_MetadataSet.DataPGIsOpen)
    {
        std::vector<std::string> empty;
        m_BP3Serializer.PutProcessGroupIndex(m_IO.m_Name, m_IO.m_HostLanguage,
                                             empty);
    }

    return StepStatus::OK;
}

void InSituMPIWriter::PerformPuts()
{
    if (m_Verbosity == 5)
    {
        std::cout << "InSituMPI Writer " << m_WriterRank << " PerformPuts()\n";
    }
    if (m_NCallsPerformPuts > 0)
    {
        throw std::runtime_error("ERROR: InSituMPI engine only allows for 1 "
                                 "PerformPuts() per step.");
    }
    m_NCallsPerformPuts++;

    if (m_CurrentStep == 0 || !m_FixedLocalSchedule)
    {
        // Create local metadata and send to reader peers
        // std::vector<char> mdVar = m_BP3Serializer.SerializeIndices(
        //    m_BP3Serializer.m_MetadataSet.VarsIndices);
        // Create Global metadata and send to readers
        m_BP3Serializer.SerializeData(m_IO, true); // advance timestep
        m_BP3Serializer.SerializeMetadataInData();
        m_BP3Serializer.AggregateCollectiveMetadata(
            m_MPIComm, m_BP3Serializer.m_Metadata, true);

        // store length long enough to survive Isend() completion
        // so don't move this into the next if branch
        unsigned long mdLen = m_BP3Serializer.m_Metadata.m_Position;

        // Send the metadata to all reader peers, asynchronously
        // we don't care about keeping these requests because
        // we will wait next for response from all readers
        if (m_BP3Serializer.m_RankMPI == 0)
        {
            if (m_Verbosity == 5)
            {
                std::cout << "InSituMPI Writer " << m_WriterRank
                          << " Metadata has = "
                          << m_BP3Serializer.m_MetadataSet.DataPGVarsCount
                          << " variables. size = "
                          << m_BP3Serializer.m_Metadata.m_Position << std::endl;
            }

            // FIXME: Which reader is actually listening for this request?
            if (m_Verbosity == 5)
            {
                std::cout << "InSituMPI Writer " << m_WriterRank
                          << " World rank = " << m_GlobalRank
                          << " sends metadata to Reader World rank = "
                          << m_RankDirectPeers[0] << std::endl;
            }
            MPI_Request request;
            // for (auto peerRank : m_RankDirectPeers)
            int peerRank = m_RankDirectPeers[0];
            // send fix schedule info, then length of metadata array,
            // then metadata array

            MPI_Isend(&mdLen, 1, MPI_UNSIGNED_LONG, peerRank,
                      insitumpi::MpiTags::MetadataLength, m_CommWorld,
                      &request);
            MPI_Isend(m_BP3Serializer.m_Metadata.m_Buffer.data(), mdLen,
                      MPI_CHAR, peerRank, insitumpi::MpiTags::Metadata,
                      m_CommWorld, &request);
        }
    }

    // exchange flags about fixed schedule
    if (m_CurrentStep == 0)
    {
        MPI_Request request;
        int peerRank = m_RankDirectPeers[0];
        int fixed;

        if (m_BP3Serializer.m_RankMPI == 0)
        {
            // send flag about this sender's fixed schedule
            fixed = (int)m_FixedLocalSchedule;
            MPI_Send(&fixed, 1, MPI_INT, peerRank,
                     insitumpi::MpiTags::FixedRemoteSchedule, m_CommWorld);

            // recv flag about the receiver's fixed schedule
            MPI_Status status;
            MPI_Recv(&fixed, 1, MPI_INT, peerRank,
                     insitumpi::MpiTags::FixedRemoteSchedule, m_CommWorld,
                     &status);
        }
        // broadcast fixed schedule flag to every reader
        MPI_Bcast(&fixed, 1, MPI_INT, 0, m_MPIComm);
        m_FixedRemoteSchedule = (fixed ? true : false);
        if (m_BP3Serializer.m_RankMPI == 0)
        {
            if (m_Verbosity == 5)
            {
                std::cout << "InSituMPI Writer " << m_WriterRank
                          << " fixed Writer schedule = " << m_FixedLocalSchedule
                          << " fixed Reader schedule = "
                          << m_FixedRemoteSchedule << std::endl;
            }
        }
    }

    if (m_CurrentStep == 0 || !m_FixedRemoteSchedule)
    {
        // Collect the read requests from ALL readers
        // FIXME: How do we make this Irecv from all readers
        // std::vector<MPI_Request> requests(m_RankAllPeers.size());
        std::vector<MPI_Status> statuses(m_RankAllPeers.size());
        std::vector<std::vector<char>> serializedSchedules(
            m_RankAllPeers.size());
        for (int peerID = 0; peerID < m_RankAllPeers.size(); peerID++)
        {
            int rsLen;
            MPI_Recv(&rsLen, 1, MPI_INT, m_RankAllPeers[peerID],
                     insitumpi::MpiTags::ReadScheduleLength, m_CommWorld,
                     &statuses[peerID]);
            serializedSchedules[peerID].resize(rsLen);
            MPI_Recv(serializedSchedules[peerID].data(), rsLen, MPI_CHAR,
                     m_RankAllPeers[peerID], insitumpi::MpiTags::ReadSchedule,
                     m_CommWorld, &statuses[peerID]);
            if (m_Verbosity == 5)
            {
                std::cout << "InSituMPI Writer " << m_WriterRank
                          << " received read schedule from Reader  " << peerID
                          << " global rank " << m_RankAllPeers[peerID]
                          << " length = " << rsLen << std::endl;
            }
        }

        // build (and remember for fixed schedule) the read request table
        // std::map<std::string, std::map<size_t, std::vector<SubFileInfo>>>
        // map
        m_WriteScheduleMap.clear();
        m_WriteScheduleMap =
            insitumpi::DeserializeReadSchedule(serializedSchedules);
        if (m_Verbosity == 5)
        {
            std::cout << "InSituMPI Writer " << m_WriterRank << " schedule:  ";
            insitumpi::PrintReadScheduleMap(m_WriteScheduleMap);
            std::cout << std::endl;
        }

        const int nRequests = insitumpi::GetNumberOfRequestsInWriteScheduleMap(
            m_WriteScheduleMap);
        m_MPIRequests.reserve(nRequests + 1); // +1 is a request from BeginStep
    }

    // Make the send requests for each variable for each matching peer
    // request
    for (const auto &variableName : m_BP3Serializer.m_DeferredVariables)
    {
        // Create the async send for the variable
        AsyncSendVariable(variableName);
    }

    m_BP3Serializer.m_DeferredVariables.clear();
    if (!m_FixedRemoteSchedule)
    {
        m_BP3Serializer.ResetBuffer(m_BP3Serializer.m_Data, true);
        m_BP3Serializer.ResetBuffer(m_BP3Serializer.m_Metadata, true);
        // FIXME: Somehow m_MetadataSet should be clean up too
    }
}

void InSituMPIWriter::AsyncSendVariable(std::string variableName)
{
    const std::string type(m_IO.InquireVariableType(variableName));

    if (type == "compound")
    {
        // not supported
    }
#define declare_template_instantiation(T)                                      \
    else if (type == helper::GetType<T>())                                     \
    {                                                                          \
        Variable<T> *variable = m_IO.InquireVariable<T>(variableName);         \
        if (m_DebugMode && variable == nullptr)                                \
        {                                                                      \
            throw std::invalid_argument(                                       \
                "ERROR: variable " + variableName +                            \
                " not found, in call to AsyncSendVariable\n");                 \
        }                                                                      \
                                                                               \
        for (const auto &blockInfo : variable->m_BlocksInfo)                   \
        {                                                                      \
            AsyncSendVariable<T>(*variable, blockInfo);                        \
        }                                                                      \
        variable->m_BlocksInfo.clear();                                        \
    }

    ADIOS2_FOREACH_TYPE_1ARG(declare_template_instantiation)
#undef declare_template_instantiation
}

void InSituMPIWriter::EndStep()
{
    if (m_Verbosity == 5)
    {
        std::cout << "InSituMPI Writer " << m_WriterRank << " EndStep()\n";
    }
    if (m_BP3Serializer.m_DeferredVariables.size() > 0)
    {
        PerformPuts();
    }

    // TODO: Blocking wait for all data transfers to finish
    const int nRequests = m_MPIRequests.size();
    std::vector<MPI_Status> statuses(nRequests);
    int ierr;

    ierr = MPI_Waitall(nRequests, m_MPIRequests.data(), statuses.data());

    if (ierr == MPI_ERR_IN_STATUS)
    {
        for (int i = 0; i < nRequests; i++)
        {
            if (statuses[i].MPI_ERROR == MPI_ERR_PENDING)
            {
                std::cerr << "InSituMPI Writer " << m_WriterRank
                          << " Pending transfer error when waiting for all "
                             "data transfers to complete. request id = "
                          << i << std::endl;
            }
            else if (statuses[i].MPI_ERROR != MPI_SUCCESS)
            {
                std::cerr << "InSituMPI Writer " << m_WriterRank
                          << " MPI Error when waiting for all data transfers "
                             "to complete. Error code = "
                          << ierr << std::endl;
            }
        }
    }

    m_MPIRequests.clear();

    // Wait for final acknowledgment from the readers
    int dummy;
    if (m_BP3Serializer.m_RankMPI == 0)
    {
        MPI_Status status;
        MPI_Recv(&dummy, 1, MPI_INT, m_RankDirectPeers[0],
                 insitumpi::MpiTags::ReadCompleted, m_CommWorld, &status);
    }
    MPI_Bcast(&dummy, 1, MPI_INT, 0, m_MPIComm);

    if (m_Verbosity == 5)
    {
        std::cout << "InSituMPI Writer " << m_WriterRank
                  << " completed EndStep()\n";
    }
}

// PRIVATE

#define declare_type(T)                                                        \
    void InSituMPIWriter::DoPutSync(Variable<T> &variable, const T *values)    \
    {                                                                          \
        PutSyncCommon(variable, variable.SetBlockInfo(values, m_CurrentStep)); \
        variable.m_BlocksInfo.clear();                                         \
    }                                                                          \
    void InSituMPIWriter::DoPutDeferred(Variable<T> &variable,                 \
                                        const T *values)                       \
    {                                                                          \
        PutDeferredCommon(variable, values);                                   \
    }
ADIOS2_FOREACH_TYPE_1ARG(declare_type)
#undef declare_type

void InSituMPIWriter::Init()
{
    InitParameters();
    InitTransports();
}

void InSituMPIWriter::InitParameters()
{
    auto itVerbosity = m_IO.m_Parameters.find("verbose");
    if (itVerbosity != m_IO.m_Parameters.end())
    {
        m_Verbosity = std::stoi(itVerbosity->second);
        if (m_DebugMode)
        {
            if (m_Verbosity < 0 || m_Verbosity > 5)
                throw std::invalid_argument(
                    "ERROR: Method verbose argument must be an "
                    "integer in the range [0,5], in call to "
                    "Open or Engine constructor\n");
        }
    }
}

void InSituMPIWriter::InitTransports()
{
    // Nothing to process from m_IO.m_TransportsParameters
}

void InSituMPIWriter::DoClose(const int transportIndex)
{
    if (m_Verbosity == 5)
    {
        std::cout << "InSituMPI Writer " << m_WriterRank << " Close(" << m_Name
                  << ")\n";
    }
    m_CurrentStep = -1; // -1 will indicate end of stream
    // Send -1 to all reader peers, asynchronously
    MPI_Request request;
    for (auto peerRank : m_RankDirectPeers)
    {
        MPI_Isend(&m_CurrentStep, 1, MPI_INT, peerRank,
                  insitumpi::MpiTags::Step, m_CommWorld, &request);
    }
}

} // end namespace engine
} // end namespace core
} // end namespace adios2
<commit_msg>Clean and reset BP3Deserialized at each step to not accumulate the metadata in memory over time<commit_after>/*
 * Distributed under the OSI-approved Apache License, Version 2.0.  See
 * accompanying file Copyright.txt for details.
 *
 * InSituMPIWriter.cpp
 * Class to exchange data using MPI between Writer and Reader
 *  partition of an application
 * It requires MPI
 *
 *  Created on: Dec 18, 2017
 *      Author: Norbert Podhorszki pnorbert@ornl.gov
 */

#include "adios2/helper/adiosMath.h"

#include "InSituMPIFunctions.h"
#include "InSituMPISchedules.h"
#include "InSituMPIWriter.h"
#include "InSituMPIWriter.tcc"

#include <iostream>

namespace adios2
{
namespace core
{
namespace engine
{

InSituMPIWriter::InSituMPIWriter(IO &io, const std::string &name,
                                 const Mode mode, MPI_Comm mpiComm)
: Engine("InSituMPIWriter", io, name, mode, mpiComm),
  m_BP3Serializer(mpiComm, m_DebugMode)
{
    m_EndMessage = " in call to InSituMPIWriter " + m_Name + " Open\n";
    Init();
    m_BP3Serializer.InitParameters(m_IO.m_Parameters);

    m_RankAllPeers = insitumpi::FindPeers(mpiComm, m_Name, true, m_CommWorld);
    MPI_Comm_rank(m_CommWorld, &m_GlobalRank);
    MPI_Comm_size(m_CommWorld, &m_GlobalNproc);
    MPI_Comm_rank(mpiComm, &m_WriterRank);
    MPI_Comm_size(mpiComm, &m_WriterNproc);
    m_RankDirectPeers =
        insitumpi::AssignPeers(m_WriterRank, m_WriterNproc, m_RankAllPeers);
    if (m_Verbosity == 5)
    {
        std::cout << "InSituMPI Writer " << m_WriterRank << " Open(" << m_Name
                  << "). #readers=" << m_RankAllPeers.size()
                  << " #writers=" << m_WriterNproc
                  << " #appsize=" << m_GlobalNproc
                  << " #direct peers=" << m_RankDirectPeers.size() << std::endl;
    }
    insitumpi::ConnectDirectPeers(m_CommWorld, true,
                                  (m_BP3Serializer.m_RankMPI == 0),
                                  m_GlobalRank, m_RankDirectPeers);
}

InSituMPIWriter::~InSituMPIWriter() {}

StepStatus InSituMPIWriter::BeginStep(StepMode mode, const float timeoutSeconds)
{
    if (m_Verbosity == 5)
    {
        std::cout << "InSituMPI Writer " << m_WriterRank << " BeginStep()\n";
    }
    if (mode != StepMode::Append)
    {
        throw std::invalid_argument(
            "ERROR: InSituMPI engine only supports appending steps "
            "(BeginStep(adios2::StepMode::Append)");
    }

    m_CurrentStep++; // 0 is the first step
    if (m_Verbosity == 5)
    {
        std::cout << "InSituMPI Writer " << m_WriterRank << " new step "
                  << m_CurrentStep << " for " << m_Name << ". Notify peers..."
                  << std::endl;
    }
    // Send the step to all reader peers, asynchronously
    // We need to do some time a Wait on any Isend/Irecv otherwise
    // MPI_Comm_free() will never release the communicator
    m_MPIRequests.emplace_back();
    const int index = m_MPIRequests.size() - 1;
    for (auto peerRank : m_RankDirectPeers)
    {
        MPI_Isend(&m_CurrentStep, 1, MPI_INT, peerRank,
                  insitumpi::MpiTags::Step, m_CommWorld,
                  m_MPIRequests.data() + index);
    }

    m_NCallsPerformPuts = 0;
    m_BP3Serializer.m_DeferredVariables.clear();
    m_BP3Serializer.m_DeferredVariablesDataSize = 0;

    // start a fresh buffer with a new Process Group
    m_BP3Serializer.ResetBuffer(m_BP3Serializer.m_Data, true);
    m_BP3Serializer.ResetBuffer(m_BP3Serializer.m_Metadata, true);
    m_BP3Serializer.ResetIndices();
    /*if (!m_BP3Serializer.m_MetadataSet.DataPGIsOpen)
    {
        std::vector<std::string> empty;
        m_BP3Serializer.PutProcessGroupIndex(m_IO.m_Name, m_IO.m_HostLanguage,
                                             empty);
    }*/

    return StepStatus::OK;
}

void InSituMPIWriter::PerformPuts()
{
    if (m_Verbosity == 5)
    {
        std::cout << "InSituMPI Writer " << m_WriterRank << " PerformPuts()\n";
    }
    if (m_NCallsPerformPuts > 0)
    {
        throw std::runtime_error("ERROR: InSituMPI engine only allows for 1 "
                                 "PerformPuts() per step.");
    }
    m_NCallsPerformPuts++;

    if (m_CurrentStep == 0 || !m_FixedLocalSchedule)
    {
        // Create local metadata and send to reader peers
        // std::vector<char> mdVar = m_BP3Serializer.SerializeIndices(
        //    m_BP3Serializer.m_MetadataSet.VarsIndices);
        // Create Global metadata and send to readers
        m_BP3Serializer.SerializeData(m_IO, true); // advance timestep
        m_BP3Serializer.SerializeMetadataInData();
        m_BP3Serializer.AggregateCollectiveMetadata(
            m_MPIComm, m_BP3Serializer.m_Metadata, true);

        // store length long enough to survive Isend() completion
        // so don't move this into the next if branch
        unsigned long mdLen = m_BP3Serializer.m_Metadata.m_Position;

        // Send the metadata to all reader peers, asynchronously
        // we don't care about keeping these requests because
        // we will wait next for response from all readers
        if (m_BP3Serializer.m_RankMPI == 0)
        {
            if (m_Verbosity == 5)
            {
                std::cout << "InSituMPI Writer " << m_WriterRank
                          << " Metadata has = "
                          << m_BP3Serializer.m_MetadataSet.DataPGVarsCount
                          << " variables. size = "
                          << m_BP3Serializer.m_Metadata.m_Position << std::endl;
            }

            // FIXME: Which reader is actually listening for this request?
            if (m_Verbosity == 5)
            {
                std::cout << "InSituMPI Writer " << m_WriterRank
                          << " World rank = " << m_GlobalRank
                          << " sends metadata to Reader World rank = "
                          << m_RankDirectPeers[0] << std::endl;
            }
            MPI_Request request;
            // for (auto peerRank : m_RankDirectPeers)
            int peerRank = m_RankDirectPeers[0];
            // send fix schedule info, then length of metadata array,
            // then metadata array

            MPI_Isend(&mdLen, 1, MPI_UNSIGNED_LONG, peerRank,
                      insitumpi::MpiTags::MetadataLength, m_CommWorld,
                      &request);
            MPI_Isend(m_BP3Serializer.m_Metadata.m_Buffer.data(), mdLen,
                      MPI_CHAR, peerRank, insitumpi::MpiTags::Metadata,
                      m_CommWorld, &request);
        }
    }

    // exchange flags about fixed schedule
    if (m_CurrentStep == 0)
    {
        MPI_Request request;
        int peerRank = m_RankDirectPeers[0];
        int fixed;

        if (m_BP3Serializer.m_RankMPI == 0)
        {
            // send flag about this sender's fixed schedule
            fixed = (int)m_FixedLocalSchedule;
            MPI_Send(&fixed, 1, MPI_INT, peerRank,
                     insitumpi::MpiTags::FixedRemoteSchedule, m_CommWorld);

            // recv flag about the receiver's fixed schedule
            MPI_Status status;
            MPI_Recv(&fixed, 1, MPI_INT, peerRank,
                     insitumpi::MpiTags::FixedRemoteSchedule, m_CommWorld,
                     &status);
        }
        // broadcast fixed schedule flag to every reader
        MPI_Bcast(&fixed, 1, MPI_INT, 0, m_MPIComm);
        m_FixedRemoteSchedule = (fixed ? true : false);
        if (m_BP3Serializer.m_RankMPI == 0)
        {
            if (m_Verbosity == 5)
            {
                std::cout << "InSituMPI Writer " << m_WriterRank
                          << " fixed Writer schedule = " << m_FixedLocalSchedule
                          << " fixed Reader schedule = "
                          << m_FixedRemoteSchedule << std::endl;
            }
        }
    }

    if (m_CurrentStep == 0 || !m_FixedRemoteSchedule)
    {
        // Collect the read requests from ALL readers
        // FIXME: How do we make this Irecv from all readers
        // std::vector<MPI_Request> requests(m_RankAllPeers.size());
        std::vector<MPI_Status> statuses(m_RankAllPeers.size());
        std::vector<std::vector<char>> serializedSchedules(
            m_RankAllPeers.size());
        for (int peerID = 0; peerID < m_RankAllPeers.size(); peerID++)
        {
            int rsLen;
            MPI_Recv(&rsLen, 1, MPI_INT, m_RankAllPeers[peerID],
                     insitumpi::MpiTags::ReadScheduleLength, m_CommWorld,
                     &statuses[peerID]);
            serializedSchedules[peerID].resize(rsLen);
            MPI_Recv(serializedSchedules[peerID].data(), rsLen, MPI_CHAR,
                     m_RankAllPeers[peerID], insitumpi::MpiTags::ReadSchedule,
                     m_CommWorld, &statuses[peerID]);
            if (m_Verbosity == 5)
            {
                std::cout << "InSituMPI Writer " << m_WriterRank
                          << " received read schedule from Reader  " << peerID
                          << " global rank " << m_RankAllPeers[peerID]
                          << " length = " << rsLen << std::endl;
            }
        }

        // build (and remember for fixed schedule) the read request table
        // std::map<std::string, std::map<size_t, std::vector<SubFileInfo>>>
        // map
        m_WriteScheduleMap.clear();
        m_WriteScheduleMap =
            insitumpi::DeserializeReadSchedule(serializedSchedules);
        if (m_Verbosity == 5)
        {
            std::cout << "InSituMPI Writer " << m_WriterRank << " schedule:  ";
            insitumpi::PrintReadScheduleMap(m_WriteScheduleMap);
            std::cout << std::endl;
        }

        const int nRequests = insitumpi::GetNumberOfRequestsInWriteScheduleMap(
            m_WriteScheduleMap);
        m_MPIRequests.reserve(nRequests + 1); // +1 is a request from BeginStep
    }

    // Make the send requests for each variable for each matching peer
    // request
    for (const auto &variableName : m_BP3Serializer.m_DeferredVariables)
    {
        // Create the async send for the variable
        AsyncSendVariable(variableName);
    }

    m_BP3Serializer.m_DeferredVariables.clear();
    if (!m_FixedRemoteSchedule)
    {
        m_BP3Serializer.ResetBuffer(m_BP3Serializer.m_Data, true);
        m_BP3Serializer.ResetBuffer(m_BP3Serializer.m_Metadata, true);
        // FIXME: Somehow m_MetadataSet should be clean up too
    }
}

void InSituMPIWriter::AsyncSendVariable(std::string variableName)
{
    const std::string type(m_IO.InquireVariableType(variableName));

    if (type == "compound")
    {
        // not supported
    }
#define declare_template_instantiation(T)                                      \
    else if (type == helper::GetType<T>())                                     \
    {                                                                          \
        Variable<T> *variable = m_IO.InquireVariable<T>(variableName);         \
        if (m_DebugMode && variable == nullptr)                                \
        {                                                                      \
            throw std::invalid_argument(                                       \
                "ERROR: variable " + variableName +                            \
                " not found, in call to AsyncSendVariable\n");                 \
        }                                                                      \
                                                                               \
        for (const auto &blockInfo : variable->m_BlocksInfo)                   \
        {                                                                      \
            AsyncSendVariable<T>(*variable, blockInfo);                        \
        }                                                                      \
        variable->m_BlocksInfo.clear();                                        \
    }

    ADIOS2_FOREACH_TYPE_1ARG(declare_template_instantiation)
#undef declare_template_instantiation
}

void InSituMPIWriter::EndStep()
{
    if (m_Verbosity == 5)
    {
        std::cout << "InSituMPI Writer " << m_WriterRank << " EndStep()\n";
    }
    if (m_BP3Serializer.m_DeferredVariables.size() > 0)
    {
        PerformPuts();
    }

    // TODO: Blocking wait for all data transfers to finish
    const int nRequests = m_MPIRequests.size();
    std::vector<MPI_Status> statuses(nRequests);
    int ierr;

    ierr = MPI_Waitall(nRequests, m_MPIRequests.data(), statuses.data());

    if (ierr == MPI_ERR_IN_STATUS)
    {
        for (int i = 0; i < nRequests; i++)
        {
            if (statuses[i].MPI_ERROR == MPI_ERR_PENDING)
            {
                std::cerr << "InSituMPI Writer " << m_WriterRank
                          << " Pending transfer error when waiting for all "
                             "data transfers to complete. request id = "
                          << i << std::endl;
            }
            else if (statuses[i].MPI_ERROR != MPI_SUCCESS)
            {
                std::cerr << "InSituMPI Writer " << m_WriterRank
                          << " MPI Error when waiting for all data transfers "
                             "to complete. Error code = "
                          << ierr << std::endl;
            }
        }
    }

    m_MPIRequests.clear();

    // Wait for final acknowledgment from the readers
    int dummy;
    if (m_BP3Serializer.m_RankMPI == 0)
    {
        MPI_Status status;
        MPI_Recv(&dummy, 1, MPI_INT, m_RankDirectPeers[0],
                 insitumpi::MpiTags::ReadCompleted, m_CommWorld, &status);
    }
    MPI_Bcast(&dummy, 1, MPI_INT, 0, m_MPIComm);

    if (m_Verbosity == 5)
    {
        std::cout << "InSituMPI Writer " << m_WriterRank
                  << " completed EndStep()\n";
    }
}

// PRIVATE

#define declare_type(T)                                                        \
    void InSituMPIWriter::DoPutSync(Variable<T> &variable, const T *values)    \
    {                                                                          \
        PutSyncCommon(variable, variable.SetBlockInfo(values, m_CurrentStep)); \
        variable.m_BlocksInfo.clear();                                         \
    }                                                                          \
    void InSituMPIWriter::DoPutDeferred(Variable<T> &variable,                 \
                                        const T *values)                       \
    {                                                                          \
        PutDeferredCommon(variable, values);                                   \
    }
ADIOS2_FOREACH_TYPE_1ARG(declare_type)
#undef declare_type

void InSituMPIWriter::Init()
{
    InitParameters();
    InitTransports();
}

void InSituMPIWriter::InitParameters()
{
    auto itVerbosity = m_IO.m_Parameters.find("verbose");
    if (itVerbosity != m_IO.m_Parameters.end())
    {
        m_Verbosity = std::stoi(itVerbosity->second);
        if (m_DebugMode)
        {
            if (m_Verbosity < 0 || m_Verbosity > 5)
                throw std::invalid_argument(
                    "ERROR: Method verbose argument must be an "
                    "integer in the range [0,5], in call to "
                    "Open or Engine constructor\n");
        }
    }
}

void InSituMPIWriter::InitTransports()
{
    // Nothing to process from m_IO.m_TransportsParameters
}

void InSituMPIWriter::DoClose(const int transportIndex)
{
    if (m_Verbosity == 5)
    {
        std::cout << "InSituMPI Writer " << m_WriterRank << " Close(" << m_Name
                  << ")\n";
    }
    m_CurrentStep = -1; // -1 will indicate end of stream
    // Send -1 to all reader peers, asynchronously
    MPI_Request request;
    for (auto peerRank : m_RankDirectPeers)
    {
        MPI_Isend(&m_CurrentStep, 1, MPI_INT, peerRank,
                  insitumpi::MpiTags::Step, m_CommWorld, &request);
    }
}

} // end namespace engine
} // end namespace core
} // end namespace adios2
<|endoftext|>


<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/base/l10n/l10n_util_win.h"

#include <windowsx.h>
#include <algorithm>
#include <iterator>

#include "base/i18n/rtl.h"
#include "base/lazy_instance.h"
#include "base/string_number_conversions.h"
#include "base/win/i18n.h"
#include "base/win/windows_version.h"
#include "grit/app_locale_settings.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/win/dpi.h"

namespace {

void AdjustLogFont(const string16& font_family,
                   double font_size_scaler,
                   double dpi_scale,
                   LOGFONT* logfont) {
  DCHECK(font_size_scaler > 0);
  font_size_scaler = std::max(std::min(font_size_scaler, 2.0), 0.7);
  // Font metrics are computed in pixels and scale in high-DPI mode.
  // Normalized by the DPI scale factor in order to work in DIP with
  // Views/Aura. Call with dpi_scale=1 to keep the size in pixels.
  font_size_scaler /= dpi_scale;
  logfont->lfHeight = static_cast<long>(font_size_scaler *
      static_cast<double>(abs(logfont->lfHeight)) + 0.5) *
      (logfont->lfHeight > 0 ? 1 : -1);

  // TODO(jungshik): We may want to check the existence of the font.
  // If it's not installed, we shouldn't adjust the font.
  if (font_family != L"default") {
    int name_len = std::min(static_cast<int>(font_family.size()),
                            LF_FACESIZE -1);
    memcpy(logfont->lfFaceName, font_family.data(), name_len * sizeof(WORD));
    logfont->lfFaceName[name_len] = 0;
  }
}

bool IsFontPresent(const wchar_t* font_name) {
  HFONT hfont = CreateFont(12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                           font_name);
  if (hfont == NULL)
    return false;
  HDC dc = GetDC(0);
  HGDIOBJ oldFont = static_cast<HFONT>(SelectObject(dc, hfont));
  WCHAR actual_font_name[LF_FACESIZE];
  DWORD size_ret = GetTextFace(dc, LF_FACESIZE, actual_font_name);
  actual_font_name[LF_FACESIZE - 1] = 0;
  SelectObject(dc, oldFont);
  DeleteObject(hfont);
  ReleaseDC(0, dc);
  // We don't have to worry about East Asian fonts with locale-dependent
  // names here.
  return wcscmp(font_name, actual_font_name) == 0;
}

class OverrideLocaleHolder {
 public:
  OverrideLocaleHolder() {}
  const std::vector<std::string>& value() const { return value_; }
  void swap_value(std::vector<std::string>* override_value) {
    value_.swap(*override_value);
  }
 private:
  std::vector<std::string> value_;
  DISALLOW_COPY_AND_ASSIGN(OverrideLocaleHolder);
};

base::LazyInstance<OverrideLocaleHolder> override_locale_holder =
    LAZY_INSTANCE_INITIALIZER;

}  // namespace

namespace l10n_util {

int GetExtendedStyles() {
  return !base::i18n::IsRTL() ? 0 : WS_EX_LAYOUTRTL | WS_EX_RTLREADING;
}

int GetExtendedTooltipStyles() {
  return !base::i18n::IsRTL() ? 0 : WS_EX_LAYOUTRTL;
}

void HWNDSetRTLLayout(HWND hwnd) {
  DWORD ex_style = ::GetWindowLong(hwnd, GWL_EXSTYLE);

  // We don't have to do anything if the style is already set for the HWND.
  if (!(ex_style & WS_EX_LAYOUTRTL)) {
    ex_style |= WS_EX_LAYOUTRTL;
    ::SetWindowLong(hwnd, GWL_EXSTYLE, ex_style);

    // Right-to-left layout changes are not applied to the window immediately
    // so we should make sure a WM_PAINT is sent to the window by invalidating
    // the entire window rect.
    ::InvalidateRect(hwnd, NULL, true);
  }
}

bool IsLocaleSupportedByOS(const std::string& locale) {
  // Block Amharic on Windows XP unless 'Abyssinica SIL' font is present.
  // On Win XP, no Ethiopic/Amahric font is availabel out of box. We hard-coded
  // 'Abyssinica SIL' in the resource bundle to use in the UI. Check
  // for its presence to determine whether or not to support Amharic UI on XP.
  return (base::win::GetVersion() >= base::win::VERSION_VISTA ||
      !LowerCaseEqualsASCII(locale, "am") || IsFontPresent(L"Abyssinica SIL"));
}

bool NeedOverrideDefaultUIFont(string16* override_font_family,
                               double* font_size_scaler) {
  // This is rather simple-minded to deal with the UI font size
  // issue for some Indian locales (ml, bn, hi) for which
  // the default Windows fonts are too small to be legible.  For those
  // locales, IDS_UI_FONT_FAMILY is set to an actual font family to
  // use while for other locales, it's set to 'default'.

  // XP and Vista or later have different font size issues and
  // we need separate ui font specifications.
  int ui_font_family_id = IDS_UI_FONT_FAMILY;
  int ui_font_size_scaler_id = IDS_UI_FONT_SIZE_SCALER;
  if (base::win::GetVersion() < base::win::VERSION_VISTA) {
    ui_font_family_id = IDS_UI_FONT_FAMILY_XP;
    ui_font_size_scaler_id = IDS_UI_FONT_SIZE_SCALER_XP;
  }

  string16 ui_font_family = GetStringUTF16(ui_font_family_id);
  int scaler100;
  if (!base::StringToInt(l10n_util::GetStringUTF16(ui_font_size_scaler_id),
                         &scaler100))
    return false;

  // We use the OS default in two cases:
  // 1) The resource bundle has 'default' and '100' for font family and
  //    font scaler.
  // 2) The resource bundle is not available for some reason and
  //    ui_font_family is empty.
  if (ui_font_family == L"default" && scaler100 == 100 ||
      ui_font_family.empty())
    return false;
  if (override_font_family && font_size_scaler) {
    override_font_family->swap(ui_font_family);
    *font_size_scaler = scaler100 / 100.0;
  }
  return true;
}

void AdjustUIFont(LOGFONT* logfont) {
  AdjustUIFontForDIP(ui::GetDPIScale(), logfont);
}

void AdjustUIFontForDIP(float dpi_scale, LOGFONT* logfont) {
  string16 ui_font_family = L"default";
  double ui_font_size_scaler = 1;
  if (NeedOverrideDefaultUIFont(&ui_font_family, &ui_font_size_scaler) ||
      dpi_scale != 1) {
    AdjustLogFont(ui_font_family, ui_font_size_scaler, dpi_scale, logfont);
  }
}

void AdjustUIFontForWindow(HWND hwnd) {
  string16 ui_font_family;
  double ui_font_size_scaler;
  if (NeedOverrideDefaultUIFont(&ui_font_family, &ui_font_size_scaler)) {
    LOGFONT logfont;
    if (GetObject(GetWindowFont(hwnd), sizeof(logfont), &logfont)) {
      double dpi_scale = 1;
      AdjustLogFont(ui_font_family, ui_font_size_scaler, dpi_scale, &logfont);
      HFONT hfont = CreateFontIndirect(&logfont);
      if (hfont)
        SetWindowFont(hwnd, hfont, FALSE);
    }
  }
}

void OverrideLocaleWithUILanguageList() {
  std::vector<std::wstring> ui_languages;
  if (base::win::i18n::GetThreadPreferredUILanguageList(&ui_languages)) {
    std::vector<std::string> ascii_languages;
    ascii_languages.reserve(ui_languages.size());
    std::transform(ui_languages.begin(), ui_languages.end(),
                   std::back_inserter(ascii_languages), &WideToASCII);
    override_locale_holder.Get().swap_value(&ascii_languages);
  } else {
    NOTREACHED() << "Failed to determine the UI language for locale override.";
  }
}

const std::vector<std::string>& GetLocaleOverrides() {
  return override_locale_holder.Get().value();
}

}  // namespace l10n_util
<commit_msg>Add safeguard against scaling for DPI setting if not in high-DPI mode.<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/base/l10n/l10n_util_win.h"

#include <windowsx.h>
#include <algorithm>
#include <iterator>

#include "base/i18n/rtl.h"
#include "base/lazy_instance.h"
#include "base/string_number_conversions.h"
#include "base/win/i18n.h"
#include "base/win/windows_version.h"
#include "grit/app_locale_settings.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/win/dpi.h"

namespace {

void AdjustLogFont(const string16& font_family,
                   double font_size_scaler,
                   double dpi_scale,
                   LOGFONT* logfont) {
  DCHECK(font_size_scaler > 0);
  font_size_scaler = std::max(std::min(font_size_scaler, 2.0), 0.7);
  // Font metrics are computed in pixels and scale in high-DPI mode.
  // Normalized by the DPI scale factor in order to work in DIP with
  // Views/Aura. Call with dpi_scale=1 to keep the size in pixels.
  font_size_scaler /= dpi_scale;
  logfont->lfHeight = static_cast<long>(font_size_scaler *
      static_cast<double>(abs(logfont->lfHeight)) + 0.5) *
      (logfont->lfHeight > 0 ? 1 : -1);

  // TODO(jungshik): We may want to check the existence of the font.
  // If it's not installed, we shouldn't adjust the font.
  if (font_family != L"default") {
    int name_len = std::min(static_cast<int>(font_family.size()),
                            LF_FACESIZE -1);
    memcpy(logfont->lfFaceName, font_family.data(), name_len * sizeof(WORD));
    logfont->lfFaceName[name_len] = 0;
  }
}

bool IsFontPresent(const wchar_t* font_name) {
  HFONT hfont = CreateFont(12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                           font_name);
  if (hfont == NULL)
    return false;
  HDC dc = GetDC(0);
  HGDIOBJ oldFont = static_cast<HFONT>(SelectObject(dc, hfont));
  WCHAR actual_font_name[LF_FACESIZE];
  DWORD size_ret = GetTextFace(dc, LF_FACESIZE, actual_font_name);
  actual_font_name[LF_FACESIZE - 1] = 0;
  SelectObject(dc, oldFont);
  DeleteObject(hfont);
  ReleaseDC(0, dc);
  // We don't have to worry about East Asian fonts with locale-dependent
  // names here.
  return wcscmp(font_name, actual_font_name) == 0;
}

class OverrideLocaleHolder {
 public:
  OverrideLocaleHolder() {}
  const std::vector<std::string>& value() const { return value_; }
  void swap_value(std::vector<std::string>* override_value) {
    value_.swap(*override_value);
  }
 private:
  std::vector<std::string> value_;
  DISALLOW_COPY_AND_ASSIGN(OverrideLocaleHolder);
};

base::LazyInstance<OverrideLocaleHolder> override_locale_holder =
    LAZY_INSTANCE_INITIALIZER;

}  // namespace

namespace l10n_util {

int GetExtendedStyles() {
  return !base::i18n::IsRTL() ? 0 : WS_EX_LAYOUTRTL | WS_EX_RTLREADING;
}

int GetExtendedTooltipStyles() {
  return !base::i18n::IsRTL() ? 0 : WS_EX_LAYOUTRTL;
}

void HWNDSetRTLLayout(HWND hwnd) {
  DWORD ex_style = ::GetWindowLong(hwnd, GWL_EXSTYLE);

  // We don't have to do anything if the style is already set for the HWND.
  if (!(ex_style & WS_EX_LAYOUTRTL)) {
    ex_style |= WS_EX_LAYOUTRTL;
    ::SetWindowLong(hwnd, GWL_EXSTYLE, ex_style);

    // Right-to-left layout changes are not applied to the window immediately
    // so we should make sure a WM_PAINT is sent to the window by invalidating
    // the entire window rect.
    ::InvalidateRect(hwnd, NULL, true);
  }
}

bool IsLocaleSupportedByOS(const std::string& locale) {
  // Block Amharic on Windows XP unless 'Abyssinica SIL' font is present.
  // On Win XP, no Ethiopic/Amahric font is availabel out of box. We hard-coded
  // 'Abyssinica SIL' in the resource bundle to use in the UI. Check
  // for its presence to determine whether or not to support Amharic UI on XP.
  return (base::win::GetVersion() >= base::win::VERSION_VISTA ||
      !LowerCaseEqualsASCII(locale, "am") || IsFontPresent(L"Abyssinica SIL"));
}

bool NeedOverrideDefaultUIFont(string16* override_font_family,
                               double* font_size_scaler) {
  // This is rather simple-minded to deal with the UI font size
  // issue for some Indian locales (ml, bn, hi) for which
  // the default Windows fonts are too small to be legible.  For those
  // locales, IDS_UI_FONT_FAMILY is set to an actual font family to
  // use while for other locales, it's set to 'default'.

  // XP and Vista or later have different font size issues and
  // we need separate ui font specifications.
  int ui_font_family_id = IDS_UI_FONT_FAMILY;
  int ui_font_size_scaler_id = IDS_UI_FONT_SIZE_SCALER;
  if (base::win::GetVersion() < base::win::VERSION_VISTA) {
    ui_font_family_id = IDS_UI_FONT_FAMILY_XP;
    ui_font_size_scaler_id = IDS_UI_FONT_SIZE_SCALER_XP;
  }

  string16 ui_font_family = GetStringUTF16(ui_font_family_id);
  int scaler100;
  if (!base::StringToInt(l10n_util::GetStringUTF16(ui_font_size_scaler_id),
                         &scaler100))
    return false;

  // We use the OS default in two cases:
  // 1) The resource bundle has 'default' and '100' for font family and
  //    font scaler.
  // 2) The resource bundle is not available for some reason and
  //    ui_font_family is empty.
  if (ui_font_family == L"default" && scaler100 == 100 ||
      ui_font_family.empty())
    return false;
  if (override_font_family && font_size_scaler) {
    override_font_family->swap(ui_font_family);
    *font_size_scaler = scaler100 / 100.0;
  }
  return true;
}

void AdjustUIFont(LOGFONT* logfont) {
#if defined(ENABLE_HIDPI)
  float dpi_scale = ui::GetDPIScale();
#else
  float dpi_scale = 1;
#endif
  AdjustUIFontForDIP(dpi_scale, logfont);
}

void AdjustUIFontForDIP(float dpi_scale, LOGFONT* logfont) {
  string16 ui_font_family = L"default";
  double ui_font_size_scaler = 1;
  if (NeedOverrideDefaultUIFont(&ui_font_family, &ui_font_size_scaler) ||
      dpi_scale != 1) {
    AdjustLogFont(ui_font_family, ui_font_size_scaler, dpi_scale, logfont);
  }
}

void AdjustUIFontForWindow(HWND hwnd) {
  string16 ui_font_family;
  double ui_font_size_scaler;
  if (NeedOverrideDefaultUIFont(&ui_font_family, &ui_font_size_scaler)) {
    LOGFONT logfont;
    if (GetObject(GetWindowFont(hwnd), sizeof(logfont), &logfont)) {
      double dpi_scale = 1;
      AdjustLogFont(ui_font_family, ui_font_size_scaler, dpi_scale, &logfont);
      HFONT hfont = CreateFontIndirect(&logfont);
      if (hfont)
        SetWindowFont(hwnd, hfont, FALSE);
    }
  }
}

void OverrideLocaleWithUILanguageList() {
  std::vector<std::wstring> ui_languages;
  if (base::win::i18n::GetThreadPreferredUILanguageList(&ui_languages)) {
    std::vector<std::string> ascii_languages;
    ascii_languages.reserve(ui_languages.size());
    std::transform(ui_languages.begin(), ui_languages.end(),
                   std::back_inserter(ascii_languages), &WideToASCII);
    override_locale_holder.Get().swap_value(&ascii_languages);
  } else {
    NOTREACHED() << "Failed to determine the UI language for locale override.";
  }
}

const std::vector<std::string>& GetLocaleOverrides() {
  return override_locale_holder.Get().value();
}

}  // namespace l10n_util
<|endoftext|>


<commit_before>#include <iostream>

int main (int argc, char* argv[])
{
    std::cout << "The number of the line is: " << argc<< argv[0] << std::endl;

    return 0;
}
<commit_msg>Created header comments. closes #82<commit_after>/*
 * Args - Programs that calculates the number od inputs.
 *
 * Author - Moses Olawoyin <m.bastford@gmail.com>
 *
 * Date - March 20th, 2015.
 *
 */

#include <iostream>

int main (int argc, char* argv[])
{
    std::cout << "The number of the line is: " << argc<< argv[0] << std::endl;

    return 0;
}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd and/or its subsidiary(-ies).
** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtSystems module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qbatteryinfo.h"

#include <QtCore/qnumeric.h>

#if defined(QT_SIMULATOR)
#  include "simulator/qsysteminfo_simulator_p.h"
#elif defined(Q_OS_LINUX)
#if defined(QT_NO_UPOWER)
#include "linux/qbatteryinfo_linux_p.h"
#else
#include "linux/qbatteryinfo_upower_p.h"
#endif
#elif defined(Q_OS_WIN)
#  include "windows/qbatteryinfo_win_p.h"
#elif defined(Q_OS_MAC)
#  include "mac/qbatteryinfo_mac_p.h"
#else
QT_BEGIN_NAMESPACE
class QBatteryInfoPrivate
{
public:
    QBatteryInfoPrivate(QBatteryInfo *) {}
    QBatteryInfoPrivate(int batteryIndex, QBatteryInfo *): index(batteryIndex) {}

    int batteryCount() { return -1; }
    int batteryIndex() { return index; }
    bool isValid() { return false; }
    void setBatteryIndex(int batteryIndex) { index = batteryIndex; }
    int currentFlow() { return 0; }
    int cycleCount() { return -1; }
    int maximumCapacity() { return -1; }
    int remainingCapacity() { return -1; }
    int remainingChargingTime() { return -1; }
    int voltage() { return -1; }
    QBatteryInfo::ChargerType chargerType() { return QBatteryInfo::UnknownCharger; }
    QBatteryInfo::ChargingState chargingState() { return QBatteryInfo::UnknownChargingState; }
    QBatteryInfo::LevelStatus levelStatus() { return QBatteryInfo::LevelUnknown; }
    QBatteryInfo::Health health() { return QBatteryInfo::HealthUnknown; }
    float temperature() { return qQNaN(); }
private:
    int index;
};
QT_END_NAMESPACE
#endif

#include <QtCore/qmetaobject.h>

QT_BEGIN_NAMESPACE

/*!
    \class QBatteryInfo
    \inmodule QtSystemInfo
    \brief The QBatteryInfo class provides various information about the batteries.
    \ingroup systeminfo

    Note that on some platforms, listening to the signals could lead to a heavy CPU usage. Therefore,
    you are strongly suggested to disconnect the signals when no longer needed in your application.

    Battery index starts at \c 0, which indicates the first battery.
*/

/*!
    \enum QBatteryInfo::ChargerType
    This enum describes the type of charger used.

    \value UnknownCharger           The charger type is unknown, or no charger.
    \value WallCharger              Using wall (mains) charger.
    \value USBCharger               Using USB charger when the system cannot differentiate the current.
    \value VariableCurrentCharger   Using variable current charger such as bicycle or solar.
*/

/*!
    \enum QBatteryInfo::ChargingState
    This enum describes the charging state.

    \value UnknownChargingState  The charging state is unknown or charging error occured.
    \value Charging              The battery is charging.
    \value IdleChargingState     The battery is idle (neither Charging nor Discharging)
    \value Discharging           The battery is discharging.
*/

/*!
    \enum QBatteryInfo::LevelStatus
    This enum describes the level status of the battery.

    \value LevelUnknown              Battery level undetermined.
    \value LevelEmpty                Battery is considered be empty and device needs to shut down.
    \value LevelLow                  Battery level is low and warnings need to be issued to the user.
    \value LevelOk                   Battery level is Ok. It is above "Low" but not "Full".
    \value LevelFull                 Battery is fully charged.
*/

/*!
    \enum QBatteryInfo::Health
    This enum describes the health of the battery.

    \value HealthUnknown    Battery health undetermined
    \value HealthOk         Battery health is OK
    \value HealthBad        Battery health is bad
*/

/*!
    Constructs a \l QBatteryInfo object with the given \a parent. The \l batteryIndex()
    will default to \c 0.
*/
QBatteryInfo::QBatteryInfo(QObject *parent)
    : QObject(parent)
#if !defined(QT_SIMULATOR)
    , d_ptr(new QBatteryInfoPrivate(this))
#else
    , d_ptr(new QBatteryInfoSimulator(this))
#endif // QT_SIMULATOR

{
}

/*!
    Constructs a \l QBatteryInfo object with the given \a batteryIndex and \a parent.
*/
QBatteryInfo::QBatteryInfo(int batteryIndex, QObject *parent)
    : QObject(parent)
#if !defined(QT_SIMULATOR)
    , d_ptr(new QBatteryInfoPrivate(batteryIndex, this))
#else
    , d_ptr(new QBatteryInfoSimulator(this))
#endif // QT_SIMULATOR

{
}

/*!
    Destroys the object
*/
QBatteryInfo::~QBatteryInfo()
{
}

/*!
    \property QBatteryInfo::batteryCount
    \brief The number of batteries available.

    In case of an error or if the information is not available \c -1 is returned.
*/
int QBatteryInfo::batteryCount() const
{
    return d_ptr->batteryCount();
}

/*!
  \property QBatteryInfo::batteryIndex
  \brief The current battery index

  The first battery is represented by \c 0.
*/
int QBatteryInfo::batteryIndex() const
{
    return d_ptr->batteryIndex();
}

void QBatteryInfo::setBatteryIndex(int batteryIndex)
{
    d_ptr->setBatteryIndex(batteryIndex);
}

/*!
  \property QBatteryInfo::valid
  \brief The validity of this instance

  If this property returns \c false \l batteryIndex() is the only other method that will return
  a valid value. All other methods will return default or invalid values and should not be relied
  upon for displaying to the user or for comparisons.
*/
bool QBatteryInfo::isValid() const
{
    return d_ptr->isValid();
}

/*!
  \property QBatteryInfo::currentFlow
  \brief The current flow of the battery

  This value is measured in milliamperes (mA). A positive returned value means the battery is
  discharging, while a negative value means the battery is charging. In case of an error or if the
  information is not available \c 0 is returned.
*/
int QBatteryInfo::currentFlow() const
{
    return d_ptr->currentFlow();
}

/*!
  \property QBatteryInfo::level
  \brief The level of the battery as a percentage

  In case of an error or if the information is not available \c -1 is returned.

  \sa maximumCapacity(), remainingCapacity(), levelStatus()
*/
int QBatteryInfo::level() const
{
    return d_ptr->level();
}

/*!
  \property QBatteryInfo::cycleCount
  \brief The cycle count of the battery

  In case of an error or if the information is not available \c -1 is returned.
 */
int QBatteryInfo::cycleCount() const
{
    return d_ptr->cycleCount();
}

/*!
  \property QBatteryInfo::maximumCapacity
  \brief The maximum capacity of the battery

  This value is measured in mAh. In case of an error or if the information is not available \c -1
  is returned.

  \sa remainingCapacity(), level(), levelStatus()
*/
int QBatteryInfo::maximumCapacity() const
{
    return d_ptr->maximumCapacity();
}

/*!
  \property QBatteryInfo::remainingCapacity
  \brief The remaining capacity of the battery

  This value is measured in mAh. In case of an error or if the information is not available \c -1
  is returned.

  \sa maximumCapacity(), level(), levelStatus()
*/
int QBatteryInfo::remainingCapacity() const
{
    return d_ptr->remainingCapacity();
}

/*!
  \property QBatteryInfo::remainingChargingTime
  \brief The remaining charging time needed for the battery

  This value is measured in seconds. If the battery is full or not charging \c 0 is returned. In
  case of an error or if the information is not available \c -1 is returned.
*/
int QBatteryInfo::remainingChargingTime() const
{
    return d_ptr->remainingChargingTime();
}

/*!
  \property QBatteryInfo::voltage
  \brief The voltage of the battery

  This value is measured in millivolts (mV). In case of an error or if the information is not
  available \c -1 is returned.
*/
int QBatteryInfo::voltage() const
{
    return d_ptr->voltage();
}

/*!
  \property QBatteryInfo::chargerType
  \brief The type of the charger
*/
QBatteryInfo::ChargerType QBatteryInfo::chargerType() const
{
    return d_ptr->chargerType();
}

/*!
  \property QBatteryInfo::chargingState
  \brief The charging state of the battery
*/
QBatteryInfo::ChargingState QBatteryInfo::chargingState() const
{
    return d_ptr->chargingState();
}

/*!
  \property QBatteryInfo::levelStatus
  \brief The level status of the battery

  This represents an Empty/Low/Full style representation of the \l level().

  \sa maximumCapacity(), remainingCapacity(), level()
*/
QBatteryInfo::LevelStatus QBatteryInfo::levelStatus() const
{
    return d_ptr->levelStatus();
}

/*!
  \property QBatteryInfo::health
  \brief The health of the battery
*/
QBatteryInfo::Health QBatteryInfo::health() const
{
    return d_ptr->health();
}

/*!
  \property QBatteryInfo::temperature
  \brief The temperature of the battery

  This value is measured in Celsius. In case of an error or if the information is not available,
  \c NaN is returned.

  \sa qQNaN()
 */
float QBatteryInfo::temperature() const
{
    return d_ptr->temperature();
}

/*!
    \internal

    Returns the signal that corresponds to \a proxySignal in the
    meta-object of the \a sourceObject.
*/
QMetaMethod proxyToSourceSignal(const QMetaMethod &proxySignal, QObject *sourceObject)
{
    if (!proxySignal.isValid())
        return proxySignal;
    Q_ASSERT(proxySignal.methodType() == QMetaMethod::Signal);
    Q_ASSERT(sourceObject != 0);
    const QMetaObject *sourceMeta = sourceObject->metaObject();
    int sourceIndex = sourceMeta->indexOfSignal(proxySignal.methodSignature());
    Q_ASSERT(sourceIndex != -1);
    return sourceMeta->method(sourceIndex);
}

/*!
    \internal
*/
void QBatteryInfo::connectNotify(const QMetaMethod &signal)
{
#if defined(Q_OS_LINUX) || defined(Q_OS_WIN) || defined(QT_SIMULATOR) || defined(Q_OS_MAC)
    QMetaMethod sourceSignal = proxyToSourceSignal(signal, d_ptr);
    connect(d_ptr, sourceSignal, this, signal, Qt::UniqueConnection);
#else
    Q_UNUSED(signal)
#endif
}

/*!
    \internal
*/
void QBatteryInfo::disconnectNotify(const QMetaMethod &signal)
{
#if defined(Q_OS_LINUX) || defined(Q_OS_WIN) || defined(QT_SIMULATOR) || defined(Q_OS_MAC)
    // We can only disconnect with the private implementation, when there is no receivers for the signal.
    if (isSignalConnected(signal))
        return;

    QMetaMethod sourceSignal = proxyToSourceSignal(signal, d_ptr);
    disconnect(d_ptr, sourceSignal, this, signal);
#else
    Q_UNUSED(signal)
#endif
}

QT_END_NAMESPACE
<commit_msg>simulator: Fix compile warning<commit_after>/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd and/or its subsidiary(-ies).
** Copyright (C) 2014 BlackBerry Limited. All rights reserved.
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtSystems module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qbatteryinfo.h"

#include <QtCore/qnumeric.h>

#if defined(QT_SIMULATOR)
#  include "simulator/qsysteminfo_simulator_p.h"
#elif defined(Q_OS_LINUX)
#if defined(QT_NO_UPOWER)
#include "linux/qbatteryinfo_linux_p.h"
#else
#include "linux/qbatteryinfo_upower_p.h"
#endif
#elif defined(Q_OS_WIN)
#  include "windows/qbatteryinfo_win_p.h"
#elif defined(Q_OS_MAC)
#  include "mac/qbatteryinfo_mac_p.h"
#else
QT_BEGIN_NAMESPACE
class QBatteryInfoPrivate
{
public:
    QBatteryInfoPrivate(QBatteryInfo *) {}
    QBatteryInfoPrivate(int batteryIndex, QBatteryInfo *): index(batteryIndex) {}

    int batteryCount() { return -1; }
    int batteryIndex() { return index; }
    bool isValid() { return false; }
    void setBatteryIndex(int batteryIndex) { index = batteryIndex; }
    int currentFlow() { return 0; }
    int cycleCount() { return -1; }
    int maximumCapacity() { return -1; }
    int remainingCapacity() { return -1; }
    int remainingChargingTime() { return -1; }
    int voltage() { return -1; }
    QBatteryInfo::ChargerType chargerType() { return QBatteryInfo::UnknownCharger; }
    QBatteryInfo::ChargingState chargingState() { return QBatteryInfo::UnknownChargingState; }
    QBatteryInfo::LevelStatus levelStatus() { return QBatteryInfo::LevelUnknown; }
    QBatteryInfo::Health health() { return QBatteryInfo::HealthUnknown; }
    float temperature() { return qQNaN(); }
private:
    int index;
};
QT_END_NAMESPACE
#endif

#include <QtCore/qmetaobject.h>

QT_BEGIN_NAMESPACE

/*!
    \class QBatteryInfo
    \inmodule QtSystemInfo
    \brief The QBatteryInfo class provides various information about the batteries.
    \ingroup systeminfo

    Note that on some platforms, listening to the signals could lead to a heavy CPU usage. Therefore,
    you are strongly suggested to disconnect the signals when no longer needed in your application.

    Battery index starts at \c 0, which indicates the first battery.
*/

/*!
    \enum QBatteryInfo::ChargerType
    This enum describes the type of charger used.

    \value UnknownCharger           The charger type is unknown, or no charger.
    \value WallCharger              Using wall (mains) charger.
    \value USBCharger               Using USB charger when the system cannot differentiate the current.
    \value VariableCurrentCharger   Using variable current charger such as bicycle or solar.
*/

/*!
    \enum QBatteryInfo::ChargingState
    This enum describes the charging state.

    \value UnknownChargingState  The charging state is unknown or charging error occured.
    \value Charging              The battery is charging.
    \value IdleChargingState     The battery is idle (neither Charging nor Discharging)
    \value Discharging           The battery is discharging.
*/

/*!
    \enum QBatteryInfo::LevelStatus
    This enum describes the level status of the battery.

    \value LevelUnknown              Battery level undetermined.
    \value LevelEmpty                Battery is considered be empty and device needs to shut down.
    \value LevelLow                  Battery level is low and warnings need to be issued to the user.
    \value LevelOk                   Battery level is Ok. It is above "Low" but not "Full".
    \value LevelFull                 Battery is fully charged.
*/

/*!
    \enum QBatteryInfo::Health
    This enum describes the health of the battery.

    \value HealthUnknown    Battery health undetermined
    \value HealthOk         Battery health is OK
    \value HealthBad        Battery health is bad
*/

/*!
    Constructs a \l QBatteryInfo object with the given \a parent. The \l batteryIndex()
    will default to \c 0.
*/
QBatteryInfo::QBatteryInfo(QObject *parent)
    : QObject(parent)
#if !defined(QT_SIMULATOR)
    , d_ptr(new QBatteryInfoPrivate(this))
#else
    , d_ptr(new QBatteryInfoSimulator(this))
#endif // QT_SIMULATOR

{
}

/*!
    Constructs a \l QBatteryInfo object with the given \a batteryIndex and \a parent.
*/
QBatteryInfo::QBatteryInfo(int batteryIndex, QObject *parent)
    : QObject(parent)
#if !defined(QT_SIMULATOR)
    , d_ptr(new QBatteryInfoPrivate(batteryIndex, this))
#else
    , d_ptr(new QBatteryInfoSimulator(batteryIndex, this))
#endif // QT_SIMULATOR

{
}

/*!
    Destroys the object
*/
QBatteryInfo::~QBatteryInfo()
{
}

/*!
    \property QBatteryInfo::batteryCount
    \brief The number of batteries available.

    In case of an error or if the information is not available \c -1 is returned.
*/
int QBatteryInfo::batteryCount() const
{
    return d_ptr->batteryCount();
}

/*!
  \property QBatteryInfo::batteryIndex
  \brief The current battery index

  The first battery is represented by \c 0.
*/
int QBatteryInfo::batteryIndex() const
{
    return d_ptr->batteryIndex();
}

void QBatteryInfo::setBatteryIndex(int batteryIndex)
{
    d_ptr->setBatteryIndex(batteryIndex);
}

/*!
  \property QBatteryInfo::valid
  \brief The validity of this instance

  If this property returns \c false \l batteryIndex() is the only other method that will return
  a valid value. All other methods will return default or invalid values and should not be relied
  upon for displaying to the user or for comparisons.
*/
bool QBatteryInfo::isValid() const
{
    return d_ptr->isValid();
}

/*!
  \property QBatteryInfo::currentFlow
  \brief The current flow of the battery

  This value is measured in milliamperes (mA). A positive returned value means the battery is
  discharging, while a negative value means the battery is charging. In case of an error or if the
  information is not available \c 0 is returned.
*/
int QBatteryInfo::currentFlow() const
{
    return d_ptr->currentFlow();
}

/*!
  \property QBatteryInfo::level
  \brief The level of the battery as a percentage

  In case of an error or if the information is not available \c -1 is returned.

  \sa maximumCapacity(), remainingCapacity(), levelStatus()
*/
int QBatteryInfo::level() const
{
    return d_ptr->level();
}

/*!
  \property QBatteryInfo::cycleCount
  \brief The cycle count of the battery

  In case of an error or if the information is not available \c -1 is returned.
 */
int QBatteryInfo::cycleCount() const
{
    return d_ptr->cycleCount();
}

/*!
  \property QBatteryInfo::maximumCapacity
  \brief The maximum capacity of the battery

  This value is measured in mAh. In case of an error or if the information is not available \c -1
  is returned.

  \sa remainingCapacity(), level(), levelStatus()
*/
int QBatteryInfo::maximumCapacity() const
{
    return d_ptr->maximumCapacity();
}

/*!
  \property QBatteryInfo::remainingCapacity
  \brief The remaining capacity of the battery

  This value is measured in mAh. In case of an error or if the information is not available \c -1
  is returned.

  \sa maximumCapacity(), level(), levelStatus()
*/
int QBatteryInfo::remainingCapacity() const
{
    return d_ptr->remainingCapacity();
}

/*!
  \property QBatteryInfo::remainingChargingTime
  \brief The remaining charging time needed for the battery

  This value is measured in seconds. If the battery is full or not charging \c 0 is returned. In
  case of an error or if the information is not available \c -1 is returned.
*/
int QBatteryInfo::remainingChargingTime() const
{
    return d_ptr->remainingChargingTime();
}

/*!
  \property QBatteryInfo::voltage
  \brief The voltage of the battery

  This value is measured in millivolts (mV). In case of an error or if the information is not
  available \c -1 is returned.
*/
int QBatteryInfo::voltage() const
{
    return d_ptr->voltage();
}

/*!
  \property QBatteryInfo::chargerType
  \brief The type of the charger
*/
QBatteryInfo::ChargerType QBatteryInfo::chargerType() const
{
    return d_ptr->chargerType();
}

/*!
  \property QBatteryInfo::chargingState
  \brief The charging state of the battery
*/
QBatteryInfo::ChargingState QBatteryInfo::chargingState() const
{
    return d_ptr->chargingState();
}

/*!
  \property QBatteryInfo::levelStatus
  \brief The level status of the battery

  This represents an Empty/Low/Full style representation of the \l level().

  \sa maximumCapacity(), remainingCapacity(), level()
*/
QBatteryInfo::LevelStatus QBatteryInfo::levelStatus() const
{
    return d_ptr->levelStatus();
}

/*!
  \property QBatteryInfo::health
  \brief The health of the battery
*/
QBatteryInfo::Health QBatteryInfo::health() const
{
    return d_ptr->health();
}

/*!
  \property QBatteryInfo::temperature
  \brief The temperature of the battery

  This value is measured in Celsius. In case of an error or if the information is not available,
  \c NaN is returned.

  \sa qQNaN()
 */
float QBatteryInfo::temperature() const
{
    return d_ptr->temperature();
}

/*!
    \internal

    Returns the signal that corresponds to \a proxySignal in the
    meta-object of the \a sourceObject.
*/
QMetaMethod proxyToSourceSignal(const QMetaMethod &proxySignal, QObject *sourceObject)
{
    if (!proxySignal.isValid())
        return proxySignal;
    Q_ASSERT(proxySignal.methodType() == QMetaMethod::Signal);
    Q_ASSERT(sourceObject != 0);
    const QMetaObject *sourceMeta = sourceObject->metaObject();
    int sourceIndex = sourceMeta->indexOfSignal(proxySignal.methodSignature());
    Q_ASSERT(sourceIndex != -1);
    return sourceMeta->method(sourceIndex);
}

/*!
    \internal
*/
void QBatteryInfo::connectNotify(const QMetaMethod &signal)
{
#if defined(Q_OS_LINUX) || defined(Q_OS_WIN) || defined(QT_SIMULATOR) || defined(Q_OS_MAC)
    QMetaMethod sourceSignal = proxyToSourceSignal(signal, d_ptr);
    connect(d_ptr, sourceSignal, this, signal, Qt::UniqueConnection);
#else
    Q_UNUSED(signal)
#endif
}

/*!
    \internal
*/
void QBatteryInfo::disconnectNotify(const QMetaMethod &signal)
{
#if defined(Q_OS_LINUX) || defined(Q_OS_WIN) || defined(QT_SIMULATOR) || defined(Q_OS_MAC)
    // We can only disconnect with the private implementation, when there is no receivers for the signal.
    if (isSignalConnected(signal))
        return;

    QMetaMethod sourceSignal = proxyToSourceSignal(signal, d_ptr);
    disconnect(d_ptr, sourceSignal, this, signal);
#else
    Q_UNUSED(signal)
#endif
}

QT_END_NAMESPACE
<|endoftext|>


<commit_before>/*
 * PrimitiveExample.cc
 *
 * Example code showing how declare a C++ method so that it can
 * be called from scheme.
 *
 * Copyright (C) 2009 Linas Vepstas
 */

#include <opencog/atomspace/AtomSpace.h>
#include <opencog/guile/SchemeEval.h>
#include <opencog/guile/SchemePrimitive.h>

using namespace opencog;

// Some example class
class MyTestClass
{
	private:
		AtomSpace *_as;
		int _id;  // some value in the instance
	public:

		MyTestClass(AtomSpace* as, int id) : _as(as), _id(id) {}

		// An example method -- accepts a handle, and wraps it
		// with a ListLink.
		Handle my_func(Handle h)
		{
			Handle hlist;
			Type t = h->getType();
			if (classserver().isA(t, NODE))
			{
				NodePtr n = NodeCast(h);
				std::string name = n->getName();
				printf("Info: my_func instance %d received the node: %s\n",
				       _id, name.c_str());
				hlist = _as->add_link(LIST_LINK, h);
			}
			else
			{
				printf("Warning: my_func instance %d called with invalid handle\n", _id);
			}
			return hlist;
		}

		Handle my_other_func(Handle h)
		{
			throw (RuntimeException(TRACE_INFO, "I threw an exception %d", _id));
			return Handle::UNDEFINED;
		}
};

int main ()
{
	// Need to access the atomspace to get it to initialize itself.
	AtomSpace* as = new AtomSpace();

	// Do this early, so that guile is initialized.
	SchemeEval* eval = new SchemeEval(as);

	printf("\nInfo: Start creating a scheme call into C++\n");

	// Create the example class, and define a scheme function,
	// named "bingo", that will call one of its methods
	MyTestClass *mtc = new MyTestClass(as, 42);
	define_scheme_primitive("bingo", &MyTestClass::my_func, mtc);

	// Now, call bingo, with a reasonable argument. Since
	// MyTestClass::my_func is expecting a handle, we better pass
	// bingo a handle.
	eval->eval("(define nnn (cog-new-node 'ConceptNode \"Hello World!\"))");
	std::string rslt = eval->eval("(bingo nnn)");
	if (eval->eval_error())
	{
		printf("Error: failed evaluation\n");
	}

	// Print the result of calling MyTestClass::my_func
	printf("Info: Result of scheme evaluation is %s", rslt.c_str());

	// Now try throwing an exception.
	define_scheme_primitive("whoops", &MyTestClass::my_other_func, mtc);

	rslt = eval->eval("(whoops nnn)");
	if (!eval->eval_error())
	{
		printf("XXX ERROR XXX: an error should have been thrown, but wasn't!\n");
	}

	// Print the result of calling MyTestClass::my_func
	printf("Info: Intentional throw gave the following output:\n%s", rslt.c_str());

	delete eval;
	printf("\nInfo: We are done, bye!\n");
	return  0;
}
<commit_msg>Include missing header file<commit_after>/*
 * PrimitiveExample.cc
 *
 * Example code showing how declare a C++ method so that it can
 * be called from scheme.
 *
 * Copyright (C) 2009 Linas Vepstas
 */

#include <opencog/atomspace/AtomSpace.h>
#include <opencog/atoms/base/Node.h>
#include <opencog/guile/SchemeEval.h>
#include <opencog/guile/SchemePrimitive.h>

using namespace opencog;

// Some example class
class MyTestClass
{
	private:
		AtomSpace *_as;
		int _id;  // some value in the instance
	public:

		MyTestClass(AtomSpace* as, int id) : _as(as), _id(id) {}

		// An example method -- accepts a handle, and wraps it
		// with a ListLink.
		Handle my_func(Handle h)
		{
			Handle hlist;
			Type t = h->getType();
			if (classserver().isA(t, NODE))
			{
				NodePtr n = NodeCast(h);
				std::string name = n->getName();
				printf("Info: my_func instance %d received the node: %s\n",
				       _id, name.c_str());
				hlist = _as->add_link(LIST_LINK, h);
			}
			else
			{
				printf("Warning: my_func instance %d called with invalid handle\n", _id);
			}
			return hlist;
		}

		Handle my_other_func(Handle h)
		{
			throw (RuntimeException(TRACE_INFO, "I threw an exception %d", _id));
			return Handle::UNDEFINED;
		}
};

int main ()
{
	// Need to access the atomspace to get it to initialize itself.
	AtomSpace* as = new AtomSpace();

	// Do this early, so that guile is initialized.
	SchemeEval* eval = new SchemeEval(as);

	printf("\nInfo: Start creating a scheme call into C++\n");

	// Create the example class, and define a scheme function,
	// named "bingo", that will call one of its methods
	MyTestClass *mtc = new MyTestClass(as, 42);
	define_scheme_primitive("bingo", &MyTestClass::my_func, mtc);

	// Now, call bingo, with a reasonable argument. Since
	// MyTestClass::my_func is expecting a handle, we better pass
	// bingo a handle.
	eval->eval("(define nnn (cog-new-node 'ConceptNode \"Hello World!\"))");
	std::string rslt = eval->eval("(bingo nnn)");
	if (eval->eval_error())
	{
		printf("Error: failed evaluation\n");
	}

	// Print the result of calling MyTestClass::my_func
	printf("Info: Result of scheme evaluation is %s", rslt.c_str());

	// Now try throwing an exception.
	define_scheme_primitive("whoops", &MyTestClass::my_other_func, mtc);

	rslt = eval->eval("(whoops nnn)");
	if (!eval->eval_error())
	{
		printf("XXX ERROR XXX: an error should have been thrown, but wasn't!\n");
	}

	// Print the result of calling MyTestClass::my_func
	printf("Info: Intentional throw gave the following output:\n%s", rslt.c_str());

	delete eval;
	printf("\nInfo: We are done, bye!\n");
	return  0;
}
<|endoftext|>


<commit_before>/*
   TCPConnector.h

   TCPConnector class definition. TCPConnector provides methods to actively
   establish TCP/IP connections with a server.

   ------------------------------------------

   Copyright  2013 [Vic Hargrave - http://vichargrave.com]

   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 "TCPConnector.h"

#include <errno.h>
#include <fcntl.h>
#include <cstdio>
#include <cstring>
#ifdef _WIN32
#include <WinSock2.h>
#include <WS2tcpip.h>
#else
#include <netdb.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#endif

#include "TCPStream.h"

#include "llvm/SmallString.h"
#include "../Log.h"
#include "SocketError.h"

using namespace tcpsockets;

static int ResolveHostName(const char* hostname, struct in_addr* addr) {
  struct addrinfo* res;

  int result = getaddrinfo(hostname, nullptr, nullptr, &res);
  if (result == 0) {
    std::memcpy(addr, &((struct sockaddr_in*)res->ai_addr)->sin_addr,
                sizeof(struct in_addr));
    freeaddrinfo(res);
  }
  return result;
}

std::unique_ptr<NetworkStream> TCPConnector::connect(const char* server,
                                                     int port, int timeout) {
#ifdef _WIN32
  struct WSAHelper {
    WSAHelper() {
      WSAData wsaData;
      WORD wVersionRequested = MAKEWORD(2, 2);
      WSAStartup(wVersionRequested, &wsaData);
    }
    ~WSAHelper() { WSACleanup(); }
  };
  static WSAHelper helper;
#endif
  struct sockaddr_in address;

  std::memset(&address, 0, sizeof(address));
  address.sin_family = AF_INET;
  if (ResolveHostName(server, &(address.sin_addr)) != 0) {
#ifdef _WIN32
    llvm::SmallString<128> addr_copy(server);
    addr_copy.push_back('\0');
    int size = sizeof(address);
    WSAStringToAddress(addr_copy.data(), PF_INET, nullptr, (struct sockaddr*)&address, &size);
#else
    inet_pton(PF_INET, server, &(address.sin_addr));
#endif
  }
  address.sin_port = htons(port);

  if (timeout == 0) {
    int sd = socket(AF_INET, SOCK_STREAM, 0);
    if (::connect(sd, (struct sockaddr*)&address, sizeof(address)) != 0) {
      DEBUG("connect() to " << server << " port " << port << " failed: " << SocketStrerror());
      return nullptr;
    }
    return std::unique_ptr<NetworkStream>(new TCPStream(sd, &address));
  }

  fd_set sdset;
  struct timeval tv;
  socklen_t len;
  int result = -1, valopt, sd = socket(AF_INET, SOCK_STREAM, 0);

  // Set socket to non-blocking
#ifdef _WIN32
  u_long mode = 1;
  ioctlsocket(sd, FIONBIO, &mode);
#else
  long arg;
  arg = fcntl(sd, F_GETFL, nullptr);
  arg |= O_NONBLOCK;
  fcntl(sd, F_SETFL, arg);
#endif

  // Connect with time limit
  if ((result = ::connect(sd, (struct sockaddr*)&address, sizeof(address))) <
      0) {
    int my_errno = SocketErrno();
#ifdef _WIN32
    if (my_errno == WSAEWOULDBLOCK || my_errno == WSAEINPROGRESS) {
#else
    if (my_errno == EWOULDBLOCK || my_errno == EINPROGRESS) {
#endif
      tv.tv_sec = timeout;
      tv.tv_usec = 0;
      FD_ZERO(&sdset);
      FD_SET(sd, &sdset);
      if (select(sd + 1, nullptr, &sdset, nullptr, &tv) > 0) {
        len = sizeof(int);
        getsockopt(sd, SOL_SOCKET, SO_ERROR, (char*)(&valopt), &len);
        if (valopt) {
          DEBUG("select() to " << server << " port " << port << " error " << valopt << " - " << SocketStrerror(valopt));
        }
        // connection established
        else
          result = 0;
      } else
        DEBUG("connect() timed out");
    } else
      DEBUG("connect() to " << server << " port " << port << " error " << SocketErrno() << " - " << SocketStrerror());
  }

  // Return socket to blocking mode
#ifdef _WIN32
  mode = 0;
  ioctlsocket(sd, FIONBIO, &mode);
#else
  arg = fcntl(sd, F_GETFL, nullptr);
  arg &= (~O_NONBLOCK);
  fcntl(sd, F_SETFL, arg);
#endif

  // Create stream object if connected
  if (result == -1) return nullptr;
  return std::unique_ptr<NetworkStream>(new TCPStream(sd, &address));
}
<commit_msg>TCPConnector: Select only IPv4 addresses.<commit_after>/*
   TCPConnector.h

   TCPConnector class definition. TCPConnector provides methods to actively
   establish TCP/IP connections with a server.

   ------------------------------------------

   Copyright  2013 [Vic Hargrave - http://vichargrave.com]

   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 "TCPConnector.h"

#include <errno.h>
#include <fcntl.h>
#include <cstdio>
#include <cstring>
#ifdef _WIN32
#include <WinSock2.h>
#include <WS2tcpip.h>
#else
#include <netdb.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#endif

#include "TCPStream.h"

#include "llvm/SmallString.h"
#include "../Log.h"
#include "SocketError.h"

using namespace tcpsockets;

static int ResolveHostName(const char* hostname, struct in_addr* addr) {
  struct addrinfo hints;
  struct addrinfo* res;

  hints.ai_flags = 0;
  hints.ai_family = AF_INET;
  hints.ai_socktype = SOCK_STREAM;
  hints.ai_protocol = 0;
  hints.ai_addrlen = 0;
  hints.ai_addr = nullptr;
  hints.ai_canonname = nullptr;
  hints.ai_next = nullptr;
  int result = getaddrinfo(hostname, nullptr, &hints, &res);
  if (result == 0) {
    std::memcpy(addr, &((struct sockaddr_in*)res->ai_addr)->sin_addr,
                sizeof(struct in_addr));
    freeaddrinfo(res);
  }
  return result;
}

std::unique_ptr<NetworkStream> TCPConnector::connect(const char* server,
                                                     int port, int timeout) {
#ifdef _WIN32
  struct WSAHelper {
    WSAHelper() {
      WSAData wsaData;
      WORD wVersionRequested = MAKEWORD(2, 2);
      WSAStartup(wVersionRequested, &wsaData);
    }
    ~WSAHelper() { WSACleanup(); }
  };
  static WSAHelper helper;
#endif
  struct sockaddr_in address;

  std::memset(&address, 0, sizeof(address));
  address.sin_family = AF_INET;
  if (ResolveHostName(server, &(address.sin_addr)) != 0) {
#ifdef _WIN32
    llvm::SmallString<128> addr_copy(server);
    addr_copy.push_back('\0');
    int size = sizeof(address);
    if (WSAStringToAddress(addr_copy.data(), PF_INET, nullptr, (struct sockaddr*)&address, &size) != 0) {
      ERROR("could not resolve " << server << " address");
      return nullptr;
    }
#else
    inet_pton(PF_INET, server, &(address.sin_addr));
#endif
  }
  address.sin_port = htons(port);

  if (timeout == 0) {
    int sd = socket(AF_INET, SOCK_STREAM, 0);
    if (::connect(sd, (struct sockaddr*)&address, sizeof(address)) != 0) {
      DEBUG("connect() to " << server << " port " << port << " failed: " << SocketStrerror());
      return nullptr;
    }
    return std::unique_ptr<NetworkStream>(new TCPStream(sd, &address));
  }

  fd_set sdset;
  struct timeval tv;
  socklen_t len;
  int result = -1, valopt, sd = socket(AF_INET, SOCK_STREAM, 0);

  // Set socket to non-blocking
#ifdef _WIN32
  u_long mode = 1;
  ioctlsocket(sd, FIONBIO, &mode);
#else
  long arg;
  arg = fcntl(sd, F_GETFL, nullptr);
  arg |= O_NONBLOCK;
  fcntl(sd, F_SETFL, arg);
#endif

  // Connect with time limit
  if ((result = ::connect(sd, (struct sockaddr*)&address, sizeof(address))) <
      0) {
    int my_errno = SocketErrno();
#ifdef _WIN32
    if (my_errno == WSAEWOULDBLOCK || my_errno == WSAEINPROGRESS) {
#else
    if (my_errno == EWOULDBLOCK || my_errno == EINPROGRESS) {
#endif
      tv.tv_sec = timeout;
      tv.tv_usec = 0;
      FD_ZERO(&sdset);
      FD_SET(sd, &sdset);
      if (select(sd + 1, nullptr, &sdset, nullptr, &tv) > 0) {
        len = sizeof(int);
        getsockopt(sd, SOL_SOCKET, SO_ERROR, (char*)(&valopt), &len);
        if (valopt) {
          DEBUG("select() to " << server << " port " << port << " error " << valopt << " - " << SocketStrerror(valopt));
        }
        // connection established
        else
          result = 0;
      } else
        DEBUG("connect() timed out");
    } else
      DEBUG("connect() to " << server << " port " << port << " error " << SocketErrno() << " - " << SocketStrerror());
  }

  // Return socket to blocking mode
#ifdef _WIN32
  mode = 0;
  ioctlsocket(sd, FIONBIO, &mode);
#else
  arg = fcntl(sd, F_GETFL, nullptr);
  arg &= (~O_NONBLOCK);
  fcntl(sd, F_SETFL, arg);
#endif

  // Create stream object if connected
  if (result == -1) return nullptr;
  return std::unique_ptr<NetworkStream>(new TCPStream(sd, &address));
}
<|endoftext|>