text:
#include <sim_ros_interface.h>
#include <simPlusPlus/Plugin.h>
#include <simPlusPlus/Handle.h>

#include <tf/transform_broadcaster.h>
#include <sensor_msgs/image_encodings.h>
#include <image_transport/image_transport.h>
#include <cv_bridge/cv_bridge.h>
#include <boost/bind.hpp>
#include <cstdlib>

void ros_imtr_callback(const sensor_msgs::ImageConstPtr& msg, SubscriberProxy *subscriberProxy)
{
    if(msg->is_bigendian)
    {
        std::cerr << "ros_imtr_callback: error: big endian image not supported" << std::endl;
        return;
    }

    int data_len = msg->step * msg->height;

    imageTransportCallback_in in_args;
    imageTransportCallback_out out_args;

    in_args.width = msg->width;
    in_args.height = msg->height;
    in_args.data.resize(data_len);

    for(unsigned int i = 0; i < msg->height; i++)
    {
        int msg_idx = (msg->height - i - 1) * msg->step;
        int buf_idx = i * msg->step;
        for(unsigned int j = 0; j < msg->step; j++)
        {
            in_args.data[buf_idx + j] = msg->data[msg_idx + j];
        }
    }

    if(!imageTransportCallback(subscriberProxy->topicCallback.scriptId, subscriberProxy->topicCallback.name.c_str(), &in_args, &out_args))
    {
        std::cerr << "ros_imtr_callback: error: failed to call callback" << std::endl;
        return;
    }
}

class Plugin : public sim::Plugin
{
public:
    void onStart()
    {
        if(!getenv("ROS_MASTER_URI"))
            throw std::runtime_error("ROS_MASTER_URI is not set");

        if(!initialize())
            throw std::runtime_error("ROS master is not running");

        if(!registerScriptStuff())
            throw std::runtime_error("failed to register script stuff");

        setExtVersion("ROS Interface Plugin");
        setBuildDate(BUILD_DATE);
    }

    void onEnd()
    {
        shutdown();
    }

    void onScriptStateDestroyed(int scriptID)
    {
        for(auto proxy : publisherHandles.find(scriptID))
        {
            if(proxy->publisher)
            {
                shutdownPublisher_in in;
                in.publisherHandle = proxy->handle;
                shutdownPublisher_out out;
                shutdownPublisher(&in, &out);
            }
            if(proxy->imageTransportPublisher)
            {
                imageTransportShutdownPublisher_in in;
                in.publisherHandle = proxy->handle;
                imageTransportShutdownPublisher_out out;
                imageTransportShutdownPublisher(&in, &out);
            }
        }
        for(auto proxy : subscriberHandles.find(scriptID))
        {
            if(proxy->subscriber)
            {
                shutdownSubscriber_in in;
                in.subscriberHandle = proxy->handle;
                shutdownSubscriber_out out;
                shutdownSubscriber(&in, &out);
            }
            if(proxy->imageTransportSubscriber)
            {
                imageTransportShutdownSubscriber_in in;
                in.subscriberHandle = proxy->handle;
                imageTransportShutdownSubscriber_out out;
                imageTransportShutdownSubscriber(&in, &out);
            }
        }
        for(auto proxy : serviceClientHandles.find(scriptID))
        {
            shutdownServiceClient_in in;
            in.serviceClientHandle = proxy->handle;
            shutdownServiceClient_out out;
            shutdownServiceClient(&in, &out);
        }
        for(auto proxy : serviceServerHandles.find(scriptID))
        {
            shutdownServiceServer_in in;
            in.serviceServerHandle = proxy->handle;
            shutdownServiceServer_out out;
            shutdownServiceServer(&in, &out);
        }
    }

    void onInstancePass(const sim::InstancePassFlags &flags, bool first)
    {
        ros::spinOnce();
    }

    void onMainScriptAboutToBeCalled(int &out)
    {

        int stopSimulationRequestCounter;
        simGetIntegerParameter(sim_intparam_stop_request_counter, &stopSimulationRequestCounter);
        simBool doNotRun = simGetBoolParameter(sim_boolparam_rosinterface_donotrunmainscript);
        if(doNotRun > 0)
        {
            if(previousStopSimulationRequestCounter == -1)
                previousStopSimulationRequestCounter = stopSimulationRequestCounter;
            if(previousStopSimulationRequestCounter == stopSimulationRequestCounter)
                out = 0; // this tells CoppeliaSim that we don't wanna execute the main script
        }
        else
            previousStopSimulationRequestCounter = -1;
    }

    void onSimulationAboutToStart()
    {
        previousStopSimulationRequestCounter = -1;
    }

    void subscribe(subscribe_in *in, subscribe_out *out)
    {
        SubscriberProxy *subscriberProxy = new SubscriberProxy();
        subscriberProxy->topicName = in->topicName;
        subscriberProxy->topicType = in->topicType;
        subscriberProxy->topicCallback.scriptId = in->_.scriptID;
        subscriberProxy->topicCallback.name = in->topicCallback;

        ros::TransportHints th;
        th.tcpNoDelay(in->transportHints.tcpNoDelay);
        th.maxDatagramSize(in->transportHints.maxDatagramSize);
        for(const auto &t : in->transportHints.transports)
        {
            if(t == "reliable") th.reliable();
            else if(t == "unreliable") th.unreliable();
            else if(t == "tcp") th.tcp();
            else if(t == "udp") th.udp();
            else throw sim::exception("invalid transport: '%s'", t);
        }

        if(0) {}
#include <sub.cpp>
        else
        {
            throw sim::exception("unsupported message type. please edit and recompile ROS plugin");
        }

        if(!subscriberProxy->subscriber)
        {
            throw sim::exception("failed creation of ROS subscriber");
        }

        out->subscriberHandle = subscriberProxy->handle = subscriberHandles.add(subscriberProxy, in->_.scriptID);
    }

    void shutdownSubscriber(shutdownSubscriber_in *in, shutdownSubscriber_out *out)
    {
        SubscriberProxy *subscriberProxy = subscriberHandles.get(in->subscriberHandle);
        subscriberProxy->subscriber.shutdown();
        delete subscriberHandles.remove(subscriberProxy);
    }

    void subscriberTreatUInt8ArrayAsString(subscriberTreatUInt8ArrayAsString_in *in, subscriberTreatUInt8ArrayAsString_out *out)
    {
        SubscriberProxy *subscriberProxy = subscriberHandles.get(in->subscriberHandle);
        subscriberProxy->wr_opt.uint8array_as_string = true;
    }

    void advertise(advertise_in *in, advertise_out *out)
    {
        PublisherProxy *publisherProxy = new PublisherProxy();
        publisherProxy->topicName = in->topicName;
        publisherProxy->topicType = in->topicType;

        if(0) {}
#include <adv.cpp>
        else
        {
            throw sim::exception("unsupported message type. please edit and recompile ROS plugin");
        }

        if(!publisherProxy->publisher)
        {
            throw sim::exception("failed creation of ROS publisher");
        }

        out->publisherHandle = publisherProxy->handle = publisherHandles.add(publisherProxy, in->_.scriptID);
    }

    void shutdownPublisher(shutdownPublisher_in *in, shutdownPublisher_out *out)
    {
        PublisherProxy *publisherProxy = publisherHandles.get(in->publisherHandle);
        publisherProxy->publisher.shutdown();
        delete publisherHandles.remove(publisherProxy);
    }

    void publisherTreatUInt8ArrayAsString(publisherTreatUInt8ArrayAsString_in *in, publisherTreatUInt8ArrayAsString_out *out)
    {
        PublisherProxy *publisherProxy = publisherHandles.get(in->publisherHandle);
        publisherProxy->rd_opt.uint8array_as_string = true;
    }

    void publish(publish_in *in, publish_out *out)
    {
        PublisherProxy *publisherProxy = publisherHandles.get(in->publisherHandle);

        simMoveStackItemToTop(in->_.stackID, 0);

        if(0) {}
#include <pub.cpp>
        else
        {
            throw sim::exception("unsupported message type. please edit and recompile ROS plugin");
        }
    }

    void serviceClient(serviceClient_in *in, serviceClient_out *out)
    {
        ServiceClientProxy *serviceClientProxy = new ServiceClientProxy();
        serviceClientProxy->serviceName = in->serviceName;
        serviceClientProxy->serviceType = in->serviceType;

        if(0) {}
#include <srvcli.cpp>
        else
        {
            throw sim::exception("unsupported service type. please edit and recompile ROS plugin");
        }

        if(!serviceClientProxy->client)
        {
            throw sim::exception("failed creation of ROS service client");
        }

        out->serviceClientHandle = serviceClientProxy->handle = serviceClientHandles.add(serviceClientProxy, in->_.scriptID);
    }

    void shutdownServiceClient(shutdownServiceClient_in *in, shutdownServiceClient_out *out)
    {
        ServiceClientProxy *serviceClientProxy = serviceClientHandles.get(in->serviceClientHandle);
        serviceClientProxy->client.shutdown();
        delete serviceClientHandles.remove(serviceClientProxy);
    }

    void serviceClientTreatUInt8ArrayAsString(serviceClientTreatUInt8ArrayAsString_in *in, serviceClientTreatUInt8ArrayAsString_out *out)
    {
        ServiceClientProxy *serviceClientProxy = serviceClientHandles.get(in->serviceClientHandle);
        serviceClientProxy->rd_opt.uint8array_as_string = true;
        serviceClientProxy->wr_opt.uint8array_as_string = true;
    }

    void call(call_in *in, call_out *out)
    {
        ServiceClientProxy *serviceClientProxy = serviceClientHandles.get(in->serviceClientHandle);

        simMoveStackItemToTop(in->_.stackID, 0);

        if(0) {}
#include <srvcall.cpp>
        else
        {
            throw sim::exception("unsupported service type. please edit and recompile ROS plugin");
        }
    }

    void advertiseService(advertiseService_in *in, advertiseService_out *out)
    {
        ServiceServerProxy *serviceServerProxy = new ServiceServerProxy();
        serviceServerProxy->serviceName = in->serviceName;
        serviceServerProxy->serviceType = in->serviceType;
        serviceServerProxy->serviceCallback.scriptId = in->_.scriptID;
        serviceServerProxy->serviceCallback.name = in->serviceCallback;

        if(0) {}
#include <srvsrv.cpp>
        else
        {
            throw sim::exception("unsupported service type. please edit and recompile ROS plugin");
        }

        if(!serviceServerProxy->server)
        {
            throw sim::exception("failed creation of ROS service server");
        }

        out->serviceServerHandle = serviceServerProxy->handle = serviceServerHandles.add(serviceServerProxy, in->_.scriptID);
    }

    void shutdownServiceServer(shutdownServiceServer_in *in, shutdownServiceServer_out *out)
    {
        ServiceServerProxy *serviceServerProxy = serviceServerHandles.get(in->serviceServerHandle);
        serviceServerProxy->server.shutdown();
        delete serviceServerHandles.remove(serviceServerProxy);
    }

    void serviceServerTreatUInt8ArrayAsString(serviceServerTreatUInt8ArrayAsString_in *in, serviceServerTreatUInt8ArrayAsString_out *out)
    {
        ServiceServerProxy *serviceServerProxy = serviceServerHandles.get(in->serviceServerHandle);
        serviceServerProxy->rd_opt.uint8array_as_string = true;
        serviceServerProxy->wr_opt.uint8array_as_string = true;
    }

    void sendTransform(sendTransform_in *in, sendTransform_out *out)
    {
        geometry_msgs::TransformStamped t;
        read__geometry_msgs__TransformStamped(in->_.stackID, &t);
        tfbr->sendTransform(t);
    }

    void sendTransforms(sendTransforms_in *in, sendTransforms_out *out)
    {
        std::vector<geometry_msgs::TransformStamped> v;

        sim::moveStackItemToTop(in->_.stackID, 0);
        int i = sim::getStackTableInfo(in->_.stackID, 0);
        if(i < 0)
            throw sim::exception("error reading input argument 1 (origin): expected array");
        int oldsz = sim::getStackSize(in->_.stackID);
        sim::unfoldStackTable(in->_.stackID);
        int sz = (sim::getStackSize(in->_.stackID) - oldsz + 1) / 2;
        for(int i = 0; i < sz; i++)
        {
            sim::moveStackItemToTop(in->_.stackID, oldsz - 1);
            int j;
            read__int32(in->_.stackID, &j);
            simMoveStackItemToTop(in->_.stackID, oldsz - 1);
            geometry_msgs::TransformStamped t;
            read__geometry_msgs__TransformStamped(in->_.stackID, &t);
            v.push_back(t);
        }

        tfbr->sendTransform(v);
    }

    void imageTransportSubscribe(imageTransportSubscribe_in *in, imageTransportSubscribe_out *out)
    {
        SubscriberProxy *subscriberProxy = new SubscriberProxy();
        subscriberProxy->topicName = in->topicName;
        subscriberProxy->topicType = "@image_transport";
        subscriberProxy->topicCallback.scriptId = in->_.scriptID;
        subscriberProxy->topicCallback.name = in->topicCallback;

        subscriberProxy->imageTransportSubscriber = imtr->subscribe(in->topicName, in->queueSize, boost::bind(ros_imtr_callback, _1, subscriberProxy));

        if(!subscriberProxy->imageTransportSubscriber)
        {
            throw sim::exception("failed creation of ROS ImageTransport subscriber");
        }

        out->subscriberHandle = subscriberProxy->handle = subscriberHandles.add(subscriberProxy, in->_.scriptID);
    }

    void imageTransportShutdownSubscriber(imageTransportShutdownSubscriber_in *in, imageTransportShutdownSubscriber_out *out)
    {
        SubscriberProxy *subscriberProxy = subscriberHandles.get(in->subscriberHandle);
        subscriberProxy->imageTransportSubscriber.shutdown();
        delete subscriberHandles.remove(subscriberProxy);
    }

    void imageTransportAdvertise(imageTransportAdvertise_in *in, imageTransportAdvertise_out *out)
    {
        PublisherProxy *publisherProxy = new PublisherProxy();
        publisherProxy->topicName = in->topicName;
        publisherProxy->topicType = "@image_transport";

        publisherProxy->imageTransportPublisher = imtr->advertise(in->topicName, in->queueSize);

        if(!publisherProxy->imageTransportPublisher)
        {
            throw sim::exception("failed creation of ROS ImageTransport publisher");
        }

        out->publisherHandle = publisherProxy->handle = publisherHandles.add(publisherProxy, in->_.scriptID);
    }

    void imageTransportShutdownPublisher(imageTransportShutdownPublisher_in *in, imageTransportShutdownPublisher_out *out)
    {
        PublisherProxy *publisherProxy = publisherHandles.get(in->publisherHandle);
        publisherProxy->imageTransportPublisher.shutdown();
        delete publisherHandles.remove(publisherProxy);
    }

    void imageTransportPublish(imageTransportPublish_in *in, imageTransportPublish_out *out)
    {
        PublisherProxy *publisherProxy = publisherHandles.get(in->publisherHandle);

        sensor_msgs::Image image_msg;
        image_msg.header.stamp = ros::Time::now();
        image_msg.header.frame_id = in->frame_id;
        image_msg.encoding = sensor_msgs::image_encodings::RGB8;
        image_msg.width = in->width;
        image_msg.height = in->height;
        image_msg.step = image_msg.width * 3;

        int data_len = image_msg.step * image_msg.height;
        image_msg.data.resize(data_len);
        image_msg.is_bigendian = 0;

        for(unsigned int i = 0; i < image_msg.height; i++)
        {
            int msg_idx = (image_msg.height - i - 1) * image_msg.step;
            int buf_idx = i * image_msg.step;
            for(unsigned int j = 0; j < image_msg.step; j++)
            {
                image_msg.data[msg_idx + j] = in->data[buf_idx + j];
            }
        }

        publisherProxy->imageTransportPublisher.publish(image_msg);
    }

    void getTime(getTime_in *in, getTime_out *out)
    {
        if(in->flag == 0)
            out->time = ros::Time::now().toSec();
    }

    void getParamString(getParamString_in *in, getParamString_out *out)
    {
        out->value = in->defaultValue;
        out->exists = ros::param::get(in->name, out->value);
    }

    void getParamInt(getParamInt_in *in, getParamInt_out *out)
    {
        out->value = in->defaultValue;
        out->exists = ros::param::get(in->name, out->value);
    }

    void getParamDouble(getParamDouble_in *in, getParamDouble_out *out)
    {
        out->value = in->defaultValue;
        out->exists = ros::param::get(in->name, out->value);
    }

    void getParamBool(getParamBool_in *in, getParamBool_out *out)
    {
        out->value = in->defaultValue;
        out->exists = ros::param::get(in->name, out->value);
    }

    void setParamString(setParamString_in *in, setParamString_out *out)
    {
        ros::param::set(in->name, in->value);
    }

    void setParamInt(setParamInt_in *in, setParamInt_out *out)
    {
        ros::param::set(in->name, in->value);
    }

    void setParamDouble(setParamDouble_in *in, setParamDouble_out *out)
    {
        ros::param::set(in->name, in->value);
    }

    void setParamBool(setParamBool_in *in, setParamBool_out *out)
    {
        ros::param::set(in->name, in->value);
    }

    void hasParam(hasParam_in *in, hasParam_out *out)
    {
        out->exists = ros::param::has(in->name);
    }

    void deleteParam(deleteParam_in *in, deleteParam_out *out)
    {
        ros::param::del(in->name);
    }

    void searchParam(searchParam_in *in, searchParam_out *out)
    {
        out->found = ros::param::search(in->name, out->name);
    }

    bool initialize()
    {
        int argc = 0;
#if _MSC_VER
        char **argv = nullptr;
#else
        char *argv[] = {};
#endif

        int node_name_length = 0;
        char *node_name = nullptr;
        node_name = simGetStringNamedParam("ROSInterface.nodeName", &node_name_length);

        ros::init(argc, argv, node_name && node_name_length ? node_name : "sim_ros_interface");

        if(node_name) simReleaseBuffer(node_name);

        if(!ros::master::check())
            return false;

        nh = new ros::NodeHandle("~");
        tfbr = new tf::TransformBroadcaster();
        imtr = new image_transport::ImageTransport(*nh);

        return true;
    }

    void shutdown()
    {
        ros::shutdown();

        delete imtr;
        delete tfbr;
        delete nh;
    }

private:
    int previousStopSimulationRequestCounter = -1;

    ros::NodeHandle *nh = NULL;

    tf::TransformBroadcaster *tfbr = NULL;
    image_transport::ImageTransport *imtr = NULL;

    sim::Handles<SubscriberProxy> subscriberHandles;
    sim::Handles<PublisherProxy> publisherHandles;
    sim::Handles<ServiceClientProxy> serviceClientHandles;
    sim::Handles<ServiceServerProxy> serviceServerHandles;
};

SIM_PLUGIN(PLUGIN_NAME, PLUGIN_VERSION, Plugin)
#include "stubsPlusPlus.cpp"

max_stars_repo_name: antoronson/turnConveyor

max_issues_repo_name: antoronson/turnConveyor

max_forks_repo_name: antoronson/turnConveyor


text:
/******************************************************************
 *
 * Round for C++
 *
 * Copyright (C) Satoshi Konno 2015
 *
 * This is licensed under BSD-style license, see file COPYING.
 *
 ******************************************************************/

#include <boost/test/unit_test.hpp>

#include <round/common/encoding/URL.h>

using namespace Round;

BOOST_AUTO_TEST_SUITE(common)

BOOST_AUTO_TEST_CASE(URLEncodeTest) {
  std::vector<std::string> testStrings;

  testStrings.push_back("");
  testStrings.push_back("a");
  testStrings.push_back("ab");
  testStrings.push_back("abc");
  testStrings.push_back("0123456789");
  testStrings.push_back("abcdefghijklmnopqrstuvwxyz");
  testStrings.push_back("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
  testStrings.push_back("+-=~`!@#$%^&*()_+{}[]|\\:;\"'<>,.?/");
  testStrings.push_back("あかさたなはまやらわん");

  for (std::vector<std::string>::iterator testString = testStrings.begin(); testString != testStrings.end(); testString++) {
    std::string sourceStr = *testString;
    std::string encodedStr;
    BOOST_CHECK(URL::Encode(sourceStr, &encodedStr));

    std::string decordedStr;
    BOOST_CHECK(URL::Decode(encodedStr, &decordedStr));

    BOOST_CHECK_EQUAL((*testString).compare(decordedStr), 0);
    if ((*testString).compare(decordedStr) != 0) {
      BOOST_MESSAGE("\"" << (*testString) << "\"" << "is not equals \"" << decordedStr << "\"");
    }
  }
}

BOOST_AUTO_TEST_SUITE_END()

ext: cpp

max_stars_repo_name: cybergarage/round-cc

max_issues_repo_name: cybergarage/round-cc

max_forks_repo_name: cybergarage/round-cc


text:
/*******************************************************************************
** Toolbox-base                                                               **
** MIT License                                                                **
** Copyright (c) [2018] [Florian Lance]                                       **
**                                                                            **
** Permission is hereby granted, free of charge, to any person obtaining a    **
** copy of this software and associated documentation files (the "Software"), **
** to deal in the Software without restriction, including without limitation  **
** the rights to use, copy, modify, merge, publish, distribute, sublicense,   **
** and/or sell copies of the Software, and to permit persons to whom the      **
** Software is furnished to do so, subject to the following conditions:       **
**                                                                            **
** The above copyright notice and this permission notice shall be included in **
** all copies or substantial portions of the Software.                        **
**                                                                            **
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR **
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,   **
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL    **
** THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER **
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING    **
** FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER        **
** DEALINGS IN THE SOFTWARE.                                                  **
**                                                                            **
********************************************************************************/

#include "network_interface.hpp"

// std
#include <iostream>

// boost
#include <boost/asio.hpp>

using namespace tool::network;

std::vector<Interface> Interface::list_local_interfaces(Protocol protocol){

    using namespace boost::asio;
    using namespace boost::asio::ip;

    io_service ioService;
    udp::resolver resolver(ioService);
    udp::resolver::query query(host_name(),"");

    std::vector<Interface> interfaces;
    try{
        udp::resolver::iterator it = resolver.resolve(query);

        while(it!=udp::resolver::iterator()){
            address addr =(it++)->endpoint().address();
            if((addr.is_v6() ? Protocol::ipv6 : (addr.is_v4() ? Protocol::ipv4 : Protocol::unknow)) == protocol){
                interfaces.emplace_back(Interface{protocol,addr.to_string()});
            }
        }
    }catch (const boost::system::system_error&){
        std::cerr << "NetworkUtility::list_local_interfaces\n";
    }

    return interfaces;
}

max_stars_repo_name: FlorianLance/toolbox

max_issues_repo_name: FlorianLance/toolbox

max_forks_repo_name: FlorianLance/toolbox


text:
/* Copyright (c) Members of the EGEE Collaboration. 2004.
See http://www.eu-egee.org/partners/ for details on the copyright
holders.

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 <cstdio>
#include <ctime>
#include <cstring>

#include <sys/resource.h>

#include <algorithm>
#include <string>
#include <list>

#include <boost/lexical_cast.hpp>

#include <user_log.c++.h>

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "jobcontrol_namespace.h"
#include "Timer.h"

using namespace std;

JOBCONTROL_NAMESPACE_BEGIN {

namespace logmonitor {

namespace {

class NullString {
public:
  NullString( const char *c );
  NullString( const std::string &s );
  ~NullString( void );

  inline operator const string &( void ) const { return this->ns_string; }
  inline operator string &( void ) { return this->ns_string; }

private:
  string   ns_string;
};

NullString::NullString( const char *c ) : ns_string( c ? c : "" ) {}

NullString::NullString( const string &s ) : ns_string( s ) {}

NullString::~NullString( void ) {}

char *myStrdup( const string &s )
{
  char   *pc = new char[ s.length() + 1 ];

  strcpy( pc, s.c_str() );

  return pc;
}

} // Anonymous namespace

const char   *TimeoutEvent::te_s_Timeout = "Timeout", *TimeoutEvent::te_s_EventNumber = "EventNumber";
const char   *TimeoutEvent::te_s_EventTime = "EventTime", *TimeoutEvent::te_s_Cluster = "Cluster";
const char   *TimeoutEvent::te_s_Proc = "Proc", *TimeoutEvent::te_s_SubProc = "SubProc";
const char   *TimeoutEvent::te_s_LogNotes = "LogNotes";
const char   *TimeoutEvent::te_s_ExecuteHost = "ExecuteHost", *TimeoutEvent::te_s_Node = "Node";
const char   *TimeoutEvent::te_s_ExecErrorType = "ExecErrorType";
const char   *TimeoutEvent::te_s_RunLocalRusage = "RunLocalRusage", *TimeoutEvent::te_s_RunRemoteRusage = "RunRemoteRusage";
const char   *TimeoutEvent::te_s_TotalLocalRusage = "TotalLocalRusage", *TimeoutEvent::te_s_TotalRemoteRusage = "TotalRemoteRusage";
const char   *TimeoutEvent::te_s_SentBytes = "SentBytes", *TimeoutEvent::te_s_RecvdBytes = "RecvdBytes";
const char   *TimeoutEvent::te_s_Terminate = "Terminate", *TimeoutEvent::te_s_Normal = "Normal";
const char   *TimeoutEvent::te_s_ReturnValue = "ReturnValue", *TimeoutEvent::te_s_SignalNumber = "SignalNumber";
const char   *TimeoutEvent::te_s_Reason = "Reason", *TimeoutEvent::te_s_CoreFile = "CoreFile";
const char   *TimeoutEvent::te_s_TotalSentBytes = "TotalSentBytes", *TimeoutEvent::te_s_TotalRecvdBytes = "TotalRecvdBytes";
const char   *TimeoutEvent::te_s_Size = "Size", *TimeoutEvent::te_s_NumPids = "NumPids";
const char   *TimeoutEvent::te_s_Message = "Message", *TimeoutEvent::te_s_Info = "Info";
const char   *TimeoutEvent::te_s_RmContact = "RmContact", *TimeoutEvent::te_s_JmContact = "JmContact";
const char   *TimeoutEvent::te_s_RestartableJM = "RestartableJM", *TimeoutEvent::te_s_CheckPointed = "CheckPointed";
  const char   *TimeoutEvent::te_s_DaemonName = "DaemonName", *TimeoutEvent::te_s_ErrorStr = "ErrorText";
  const char   *TimeoutEvent::te_s_CriticalError = "CriticalError";
  const char   *TimeoutEvent::te_s_ReasonCode = "ReasonCode", *TimeoutEvent::te_s_ReasonSubCode = "ReasonSubCode";
  const char   *TimeoutEvent::te_s_UserNotes = "UserNotes";
  const char   *TimeoutEvent::te_s_StartdAddr = "StartdAddr", *TimeoutEvent::te_s_StartdName = "StartdName";
  const char   *TimeoutEvent::te_s_StarterAddr = "StartesAddr", *TimeoutEvent::te_s_DisconnReason = "DisconnReason";
  const char   *TimeoutEvent::te_s_NoReconnReason = "NoReconnReason", *TimeoutEvent::te_s_CanReconn = "CanReconn";
  const char   *TimeoutEvent::te_s_ResourceName= "GridResource", *TimeoutEvent::te_s_JobId = "GridJobId";

namespace {

typedef  struct rusage   Rusage;

classad::ClassAd *toClassAd( rusage &ru )
{
  classad::ClassAd    *answer = new classad::ClassAd();

  answer->InsertAttr( "ru_maxrss", boost::lexical_cast<string>(ru.ru_maxrss) );
  answer->InsertAttr( "ru_ixrss", boost::lexical_cast<string>(ru.ru_ixrss) );
  answer->InsertAttr( "ru_idrss", boost::lexical_cast<string>(ru.ru_idrss) );
  answer->InsertAttr( "ru_isrss", boost::lexical_cast<string>(ru.ru_isrss) );
  answer->InsertAttr( "ru_minflt", boost::lexical_cast<string>(ru.ru_minflt) );
  answer->InsertAttr( "ru_majflt", boost::lexical_cast<string>(ru.ru_majflt) );
  answer->InsertAttr( "ru_nswap", boost::lexical_cast<string>(ru.ru_nswap) );
  answer->InsertAttr( "ru_inblock", boost::lexical_cast<string>(ru.ru_inblock) );
  answer->InsertAttr( "ru_oublock", boost::lexical_cast<string>(ru.ru_oublock) );
  answer->InsertAttr( "ru_msgsnd", boost::lexical_cast<string>(ru.ru_msgsnd) );
  answer->InsertAttr( "ru_msgrcv", boost::lexical_cast<string>(ru.ru_msgrcv) );
  answer->InsertAttr( "ru_nsignals", boost::lexical_cast<string>(ru.ru_nsignals) );
  answer->InsertAttr( "ru_nvcsw", boost::lexical_cast<string>(ru.ru_nvcsw) );
  answer->InsertAttr( "ru_nivcsw", boost::lexical_cast<string>(ru.ru_nivcsw) );
  answer->InsertAttr( "ru_utime", boost::lexical_cast<string>(ru.ru_utime.tv_sec) );
  answer->InsertAttr( "ru_stime", boost::lexical_cast<string>(ru.ru_stime.tv_sec) );

  return answer;
}

Rusage toRusage( const classad::ClassAd *ad )
{
  double    val;
  Rusage    ru;

  ad->EvaluateAttrNumber( "ru_maxrss", val );   ru.ru_maxrss = static_cast<long int>( val );
  ad->EvaluateAttrNumber( "ru_ixrss", val );    ru.ru_ixrss = static_cast<long int>( val );
  ad->EvaluateAttrNumber( "ru_idrss", val );    ru.ru_idrss = static_cast<long int>( val );
  ad->EvaluateAttrNumber( "ru_isrss", val );    ru.ru_isrss = static_cast<long int>( val );
  ad->EvaluateAttrNumber( "ru_minflt", val );   ru.ru_minflt = static_cast<long int>( val );
  ad->EvaluateAttrNumber( "ru_majflt", val );   ru.ru_majflt = static_cast<long int>( val );
  ad->EvaluateAttrNumber( "ru_nswap", val );    ru.ru_nswap = static_cast<long int>( val );
  ad->EvaluateAttrNumber( "ru_inblock", val );  ru.ru_inblock = static_cast<long int>( val );
  ad->EvaluateAttrNumber( "ru_oublock", val );  ru.ru_oublock = static_cast<long int>( val );
  ad->EvaluateAttrNumber( "ru_msgsnd", val );   ru.ru_msgsnd = static_cast<long int>( val );
  ad->EvaluateAttrNumber( "ru_msgrcv", val );   ru.ru_msgrcv = static_cast<long int>( val );
  ad->EvaluateAttrNumber( "ru_nsignals", val ); ru.ru_nsignals = static_cast<long int>( val );
  ad->EvaluateAttrNumber( "ru_nvcsw", val );    ru.ru_nvcsw = static_cast<long int>( val );
  ad->EvaluateAttrNumber( "ru_nivcsw", val );   ru.ru_nivcsw = static_cast<long int>( val );
  ad->EvaluateAttrNumber( "ru_utime", val );    ru.ru_utime.tv_sec = static_cast<long int>( val ); ru.ru_utime.tv_usec = 0;
  ad->EvaluateAttrNumber( "ru_stime", val );    ru.ru_stime.tv_sec = static_cast<long int>( val ); ru.ru_stime.tv_usec = 0;

  return ru;
}

} // Anonymous namespace

TimeoutEvent::TimeoutEvent( time_t epoch, ULogEvent *event ) : te_epoch( epoch ), te_event( event ), te_classad(), te_pointer()
{}

TimeoutEvent::TimeoutEvent( const classad::ClassAd &ad ) : te_epoch( 0 ), te_event(), te_classad(static_cast<classad::ClassAd*>(ad.Copy())), te_pointer()
{}

TimeoutEvent::~TimeoutEvent( void ) {}

bool TimeoutEvent::expired( void )
{
  time_t    now = time( NULL );

  if( !this->te_event ) this->to_event();

  return( this->te_epoch <= now );
}

classad::ClassAd *TimeoutEvent::to_classad( void )
{
  time_t     epoch;

  if( !this->te_classad ) {
    epoch = mktime( &this->te_event->eventTime );

    this->te_classad.reset( new classad::ClassAd() );

    this->te_classad->InsertAttr( te_s_Timeout, boost::lexical_cast<string>(this->te_epoch) );
    this->te_classad->InsertAttr( te_s_EventNumber, static_cast<int>(this->te_event->eventNumber) );
    this->te_classad->InsertAttr( te_s_EventTime, boost::lexical_cast<string>(epoch) );
    this->te_classad->InsertAttr( te_s_Cluster, static_cast<int>(this->te_event->cluster) );
    this->te_classad->InsertAttr( te_s_Proc, static_cast<int>(this->te_event->proc) );
    this->te_classad->InsertAttr( te_s_SubProc, static_cast<int>(this->te_event->subproc) );

    switch( this->te_event->eventNumber ) {
    case ULOG_SUBMIT: {
      SubmitEvent    *sev = dynamic_cast<SubmitEvent *>( this->te_event.get() );

      if( sev->submitEventLogNotes ) {
	NullString    lnotes( sev->submitEventLogNotes );

	this->te_classad->InsertAttr( te_s_LogNotes, lnotes );
      }
      if( sev->submitEventUserNotes ) {
	NullString    unotes( sev->submitEventUserNotes );

	this->te_classad->InsertAttr( te_s_UserNotes, unotes );
      }
      break;
    }
    case ULOG_EXECUTE: {
      break;
    }
    case ULOG_EXECUTABLE_ERROR: {
      ExecutableErrorEvent   *eeev = dynamic_cast<ExecutableErrorEvent *>( this->te_event.get() );

      this->te_classad->InsertAttr( te_s_ExecErrorType, static_cast<int>(eeev->errType) );

      break;
    }
    case ULOG_CHECKPOINTED: {
      CheckpointedEvent   *chev = dynamic_cast<CheckpointedEvent *>( this->te_event.get() );

      this->te_classad->Insert( te_s_RunLocalRusage, toClassAd(chev->run_local_rusage) );
      this->te_classad->Insert( te_s_RunRemoteRusage, toClassAd(chev->run_remote_rusage) );

      break;
    }
    case ULOG_JOB_EVICTED: {
      JobEvictedEvent   *jev = dynamic_cast<JobEvictedEvent *>( this->te_event.get() );
      NullString         reason( jev->getReason() ), corefile( jev->getCoreFile() );

      this->te_classad->InsertAttr( te_s_CheckPointed, jev->checkpointed );
      this->te_classad->InsertAttr( te_s_SentBytes, jev->sent_bytes );
      this->te_classad->InsertAttr( te_s_RecvdBytes, jev->recvd_bytes );
      this->te_classad->InsertAttr( te_s_Terminate, jev->terminate_and_requeued );
      this->te_classad->InsertAttr( te_s_Normal, jev->normal );
      this->te_classad->InsertAttr( te_s_ReturnValue, jev->return_value );
      this->te_classad->InsertAttr( te_s_SignalNumber, jev->signal_number );
      this->te_classad->InsertAttr( te_s_Reason, reason );
      this->te_classad->InsertAttr( te_s_CoreFile, corefile );
      this->te_classad->Insert( te_s_RunLocalRusage, toClassAd(jev->run_local_rusage) );
      this->te_classad->Insert( te_s_RunRemoteRusage, toClassAd(jev->run_remote_rusage) );

      break;
    }
    case ULOG_JOB_TERMINATED: {
      JobTerminatedEvent   *te = dynamic_cast<JobTerminatedEvent *>( this->te_event.get() );
      NullString            corefile( te->getCoreFile() );

      this->te_classad->InsertAttr( te_s_Normal, te->normal );
      this->te_classad->InsertAttr( te_s_ReturnValue, te->returnValue );
      this->te_classad->InsertAttr( te_s_SignalNumber, te->signalNumber );
      this->te_classad->InsertAttr( te_s_SentBytes, te->sent_bytes );
      this->te_classad->InsertAttr( te_s_RecvdBytes, te->recvd_bytes );
      this->te_classad->InsertAttr( te_s_TotalSentBytes, te->total_sent_bytes );
      this->te_classad->InsertAttr( te_s_TotalRecvdBytes, te->total_recvd_bytes );
      this->te_classad->InsertAttr( te_s_CoreFile, corefile );
      this->te_classad->Insert( te_s_RunLocalRusage, toClassAd(te->run_local_rusage) );
      this->te_classad->Insert( te_s_RunRemoteRusage, toClassAd(te->run_remote_rusage) );
      this->te_classad->Insert( te_s_TotalLocalRusage, toClassAd(te->total_local_rusage) );
      this->te_classad->Insert( te_s_TotalRemoteRusage, toClassAd(te->total_remote_rusage) );

      break;
    }
    case ULOG_IMAGE_SIZE: {
      JobImageSizeEvent   *jisev = dynamic_cast<JobImageSizeEvent *>( this->te_event.get() );
      int size = jisev->image_size_kb;
      this->te_classad->InsertAttr(te_s_Size, size);

      break;
    }
    case ULOG_SHADOW_EXCEPTION: {
      ShadowExceptionEvent   *sev = dynamic_cast<ShadowExceptionEvent *>( this->te_event.get() );
      NullString              message( sev->message );

      this->te_classad->InsertAttr( te_s_Message, message );
      this->te_classad->InsertAttr( te_s_SentBytes, sev->sent_bytes );
      this->te_classad->InsertAttr( te_s_RecvdBytes, sev->recvd_bytes );

      break;
    }
    case ULOG_GENERIC: {
      GenericEvent  *gev = dynamic_cast<GenericEvent *>( this->te_event.get() );
      NullString     info( gev->info );

      this->te_classad->InsertAttr( te_s_Info, info );

      break;
    }
    case ULOG_JOB_ABORTED: {
      JobAbortedEvent  *jaev = dynamic_cast<JobAbortedEvent *>( this->te_event.get() );
      NullString        reason( jaev->getReason() );

      this->te_classad->InsertAttr( te_s_Reason, reason );

      break;
    }
    case ULOG_JOB_SUSPENDED: {
      JobSuspendedEvent   *jsev = dynamic_cast<JobSuspendedEvent *>( this->te_event.get() );

      this->te_classad->InsertAttr( te_s_NumPids, jsev->num_pids );

      break;
    }
    case ULOG_JOB_UNSUSPENDED: break; // Nothing seems to be done
    case ULOG_JOB_HELD: {
      JobHeldEvent   *jhev = dynamic_cast<JobHeldEvent *>( this->te_event.get() );
      NullString      reason( jhev->getReason() );

      this->te_classad->InsertAttr( te_s_Reason, reason );
      this->te_classad->InsertAttr( te_s_ReasonCode, jhev->getReasonCode() );
      this->te_classad->InsertAttr( te_s_ReasonSubCode, jhev->getReasonSubCode() );

      break;
    }
    case ULOG_JOB_RELEASED: {
      JobReleasedEvent  *jrev = dynamic_cast<JobReleasedEvent *>( this->te_event.get() );
      NullString         reason( jrev->getReason() );

      this->te_classad->InsertAttr( te_s_Reason, reason );

      break;
    }
    case ULOG_NODE_EXECUTE: {
      NodeExecuteEvent    *neev = dynamic_cast<NodeExecuteEvent *>( this->te_event.get() );
      this->te_classad->InsertAttr( te_s_Node, neev->node );

      break;
    }
    case ULOG_NODE_TERMINATED: {
      NodeTerminatedEvent   *ntev = dynamic_cast<NodeTerminatedEvent *>( this->te_event.get() );
      NullString             corefile( ntev->getCoreFile() );

      this->te_classad->InsertAttr( te_s_Normal, ntev->normal );
      this->te_classad->InsertAttr( te_s_ReturnValue, ntev->returnValue );
      this->te_classad->InsertAttr( te_s_SignalNumber, ntev->signalNumber );
      this->te_classad->InsertAttr( te_s_Node, ntev->node );
      this->te_classad->InsertAttr( te_s_SentBytes, ntev->sent_bytes );
      this->te_classad->InsertAttr( te_s_RecvdBytes, ntev->recvd_bytes );
      this->te_classad->InsertAttr( te_s_TotalSentBytes, ntev->total_sent_bytes );
      this->te_classad->InsertAttr( te_s_TotalRecvdBytes, ntev->total_recvd_bytes );
      this->te_classad->InsertAttr( te_s_CoreFile, corefile );
      this->te_classad->Insert( te_s_RunLocalRusage, toClassAd(ntev->run_local_rusage) );
      this->te_classad->Insert( te_s_RunRemoteRusage, toClassAd(ntev->run_remote_rusage) );
      this->te_classad->Insert( te_s_TotalLocalRusage, toClassAd(ntev->total_local_rusage) );
      this->te_classad->Insert( te_s_TotalRemoteRusage, toClassAd(ntev->total_remote_rusage) );

      break;
    }
    case ULOG_POST_SCRIPT_TERMINATED: {
      PostScriptTerminatedEvent  *pstev = dynamic_cast<PostScriptTerminatedEvent *>( this->te_event.get() );

      this->te_classad->InsertAttr( te_s_Normal, pstev->normal );
      this->te_classad->InsertAttr( te_s_ReturnValue, pstev->returnValue );
      this->te_classad->InsertAttr( te_s_SignalNumber, pstev->signalNumber );

      break;
    }
    case ULOG_GLOBUS_SUBMIT: {
      GlobusSubmitEvent   *gsev = dynamic_cast<GlobusSubmitEvent *>( this->te_event.get() );
      NullString           rmContact( gsev->rmContact ), jmContact( gsev->jmContact );

      this->te_classad->InsertAttr( te_s_RmContact, rmContact );
      this->te_classad->InsertAttr( te_s_JmContact, jmContact );
      this->te_classad->InsertAttr( te_s_RestartableJM, gsev->restartableJM );

      break;
    }
    case ULOG_GLOBUS_SUBMIT_FAILED: {
      GlobusSubmitFailedEvent   *gsfev = dynamic_cast<GlobusSubmitFailedEvent *>( this->te_event.get() );
      NullString                 reason( gsfev->reason );

      this->te_classad->InsertAttr( te_s_Reason, reason );

      break;
    }
    case ULOG_GLOBUS_RESOURCE_UP: {
      GlobusResourceUpEvent     *gruev = dynamic_cast<GlobusResourceUpEvent *>( this->te_event.get() );
      NullString                 rmContact( gruev->rmContact );

      this->te_classad->InsertAttr( te_s_RmContact, rmContact );

      break;
    }
    case ULOG_GLOBUS_RESOURCE_DOWN: {
      GlobusResourceDownEvent   *grdev = dynamic_cast<GlobusResourceDownEvent *>( this->te_event.get() );
      NullString                 rmContact( grdev->rmContact );

      this->te_classad->InsertAttr( te_s_RmContact, rmContact );

      break;
    }
    case ULOG_REMOTE_ERROR: {
      RemoteErrorEvent          *reev = dynamic_cast<RemoteErrorEvent *>( this->te_event.get() );
      NullString                 exeHost( reev->getExecuteHost() );
      NullString                 daemonName( reev->getDaemonName() );
      NullString                 errorStr( reev->getErrorText() );

      this->te_classad->InsertAttr( te_s_ExecuteHost, exeHost );
      this->te_classad->InsertAttr( te_s_DaemonName, daemonName );
      this->te_classad->InsertAttr( te_s_ErrorStr, errorStr );
      this->te_classad->InsertAttr( te_s_CriticalError, reev->isCriticalError() );

      break;
    }
    case ULOG_JOB_DISCONNECTED: {
      JobDisconnectedEvent     *jdcev = dynamic_cast<JobDisconnectedEvent *>( this->te_event.get() );
      NullString                startdAddr( jdcev->getStartdAddr() );
      NullString                startdName( jdcev->getStartdName() );
      NullString                disconnReason( jdcev->getDisconnectReason() );
      NullString                noreconnReason( jdcev->getNoReconnectReason() );

      this->te_classad->InsertAttr( te_s_StartdAddr, startdAddr );
      this->te_classad->InsertAttr( te_s_StartdName, startdName );
      this->te_classad->InsertAttr( te_s_DisconnReason, disconnReason );
      this->te_classad->InsertAttr( te_s_NoReconnReason, noreconnReason );
      this->te_classad->InsertAttr( te_s_CanReconn, jdcev->canReconnect() );

      break;
    }
    case ULOG_JOB_RECONNECTED: {
      JobReconnectedEvent      *jrcev = dynamic_cast<JobReconnectedEvent *>( this->te_event.get() );
      NullString                startdAddr( jrcev->getStartdAddr() );
      NullString                startdName( jrcev->getStartdName() );
      NullString                starterAddr( jrcev->getStarterAddr() );

      this->te_classad->InsertAttr( te_s_StartdAddr, startdAddr );
      this->te_classad->InsertAttr( te_s_StartdName, startdName );
      this->te_classad->InsertAttr( te_s_StarterAddr, starterAddr );

      break;
    }
    case ULOG_JOB_RECONNECT_FAILED: {
      JobReconnectFailedEvent *jrcfev = dynamic_cast<JobReconnectFailedEvent *>( this->te_event.get() );
      NullString                startdName( jrcfev->getStartdName() );
      NullString                reason( jrcfev->getReason() );

      this->te_classad->InsertAttr( te_s_StartdName, startdName );
      this->te_classad->InsertAttr( te_s_Reason, reason );

      break;
    }
    case ULOG_GRID_SUBMIT: {
      GridSubmitEvent     *gsev = dynamic_cast<GridSubmitEvent *>( this->te_event.get() );
      NullString           resourceName( gsev->resourceName ), jobId( gsev->jobId );

      this->te_classad->InsertAttr( te_s_ResourceName, resourceName );
      this->te_classad->InsertAttr( te_s_JobId, jobId );

      break;
    }
    case ULOG_GRID_RESOURCE_UP: {
      GridResourceUpEvent       *gruev = dynamic_cast<GridResourceUpEvent *>( this->te_event.get() );
      NullString                 resourceName( gruev->resourceName );

      this->te_classad->InsertAttr( te_s_ResourceName, resourceName );

      break;
    }
    case ULOG_GRID_RESOURCE_DOWN: {
      GridResourceDownEvent     *grdev = dynamic_cast<GridResourceDownEvent *>( this->te_event.get() );
      NullString                 resourceName( grdev->resourceName );

      this->te_classad->InsertAttr( te_s_ResourceName, resourceName );

      break;
    }
    }
  }
  return this->te_classad.get();
}

ULogEvent *TimeoutEvent::to_event( void )
{
  int     ival;
  time_t  tval;
  double  dval;
  string  sval;

  if( !this->te_event ) {
    this->te_classad->EvaluateAttrNumber( te_s_EventNumber, ival );
    this->te_classad->EvaluateAttrString( te_s_Timeout, sval );

    this->te_epoch = boost::lexical_cast<time_t>( sval );

    this->te_event.reset( instantiateEvent(static_cast<ULogEventNumber>(ival)) );

    this->te_classad->EvaluateAttrString( te_s_EventTime, sval );
    tval = boost::lexical_cast<time_t>( sval ); localtime_r( &tval, &this->te_event->eventTime );

    this->te_classad->EvaluateAttrNumber( te_s_Cluster, this->te_event->cluster );
    this->te_classad->EvaluateAttrNumber( te_s_Proc, this->te_event->proc );
    this->te_classad->EvaluateAttrNumber( te_s_SubProc, this->te_event->subproc );

    switch( this->te_event->eventNumber ) {
    case ULOG_SUBMIT: {
      SubmitEvent   *sev = dynamic_cast<SubmitEvent *>( this->te_event.get() );

      if( this->te_classad->EvaluateAttrString(te_s_LogNotes, sval) )
	sev->submitEventLogNotes = myStrdup( sval );
      if( this->te_classad->EvaluateAttrString(te_s_UserNotes, sval) )
	sev->submitEventUserNotes = myStrdup( sval );

      break;
    }
    case ULOG_EXECUTE: {
      ExecuteEvent   *eev = dynamic_cast<ExecuteEvent *>( this->te_event.get() );

      this->te_classad->EvaluateAttrString( te_s_ExecuteHost, sval );
      eev->setExecuteHost(myStrdup(sval.substr(0, 128)));

      break;
    }
    case ULOG_EXECUTABLE_ERROR: {
      ExecutableErrorEvent  *eeev = dynamic_cast<ExecutableErrorEvent *>( this->te_event.get() );

      this->te_classad->EvaluateAttrNumber( te_s_ExecErrorType, ival );
      eeev->errType = static_cast<ExecErrorType>( ival );

      break;
    }
    case ULOG_CHECKPOINTED: {
      CheckpointedEvent   *chev = dynamic_cast<CheckpointedEvent *>( this->te_event.get() );
      classad::ClassAd    *tmp;

      tmp = dynamic_cast<classad::ClassAd *>( this->te_classad->Lookup(te_s_RunLocalRusage) );
      chev->run_local_rusage = toRusage( tmp );

      tmp = dynamic_cast<classad::ClassAd *>( this->te_classad->Lookup(te_s_RunRemoteRusage) );
      chev->run_remote_rusage = toRusage( tmp );

      break;
    }
    case ULOG_JOB_EVICTED: {
      JobEvictedEvent   *jeev = dynamic_cast<JobEvictedEvent *>( this->te_event.get() );
      classad::ClassAd  *tmp;

      this->te_classad->EvaluateAttrBool( te_s_CheckPointed, jeev->checkpointed );
      this->te_classad->EvaluateAttrNumber( te_s_SentBytes, dval ); jeev->sent_bytes = static_cast<float>( dval );
      this->te_classad->EvaluateAttrNumber( te_s_RecvdBytes, dval ); jeev->recvd_bytes = static_cast<float>( dval );
      this->te_classad->EvaluateAttrBool( te_s_Terminate, jeev->terminate_and_requeued );
      this->te_classad->EvaluateAttrBool( te_s_Normal, jeev->normal );
      this->te_classad->EvaluateAttrNumber( te_s_ReturnValue, jeev->return_value );
      this->te_classad->EvaluateAttrNumber( te_s_SignalNumber, jeev->signal_number );
      this->te_classad->EvaluateAttrString( te_s_Reason, sval ); jeev->setReason( myStrdup(sval) );
      this->te_classad->EvaluateAttrString( te_s_CoreFile, sval ); jeev->setCoreFile( myStrdup(sval) );

      tmp = dynamic_cast<classad::ClassAd *>( this->te_classad->Lookup(te_s_RunLocalRusage) );
      jeev->run_local_rusage = toRusage( tmp );

      tmp = dynamic_cast<classad::ClassAd *>( this->te_classad->Lookup(te_s_RunRemoteRusage) );
      jeev->run_remote_rusage = toRusage( tmp );

      break;
    }
    case ULOG_JOB_TERMINATED: {
      JobTerminatedEvent *jtev = dynamic_cast<JobTerminatedEvent *>( this->te_event.get() );
      classad::ClassAd   *tmp;

      this->te_classad->EvaluateAttrBool( te_s_Normal, jtev->normal );
      this->te_classad->EvaluateAttrNumber( te_s_ReturnValue, jtev->returnValue );
      this->te_classad->EvaluateAttrNumber( te_s_SignalNumber, jtev->signalNumber );
      this->te_classad->EvaluateAttrNumber( te_s_SentBytes, dval ); jtev->sent_bytes = static_cast<float>( dval );
      this->te_classad->EvaluateAttrNumber( te_s_RecvdBytes, dval ); jtev->recvd_bytes = static_cast<float>( dval );
      this->te_classad->EvaluateAttrNumber( te_s_TotalSentBytes, dval ); jtev->total_sent_bytes = static_cast<float>( dval );
      this->te_classad->EvaluateAttrNumber( te_s_TotalRecvdBytes, dval ); jtev->total_recvd_bytes = static_cast<float>( dval );
      this->te_classad->EvaluateAttrString( te_s_CoreFile, sval ); jtev->setCoreFile( myStrdup(sval) );

      tmp = dynamic_cast<classad::ClassAd *>( this->te_classad->Lookup(te_s_RunLocalRusage) );
      jtev->run_local_rusage = toRusage( tmp );

      tmp = dynamic_cast<classad::ClassAd *>( this->te_classad->Lookup(te_s_RunRemoteRusage) );
      jtev->run_remote_rusage = toRusage( tmp );

      tmp = dynamic_cast<classad::ClassAd *>( this->te_classad->Lookup(te_s_TotalLocalRusage) );
      jtev->total_local_rusage = toRusage( tmp );

      tmp = dynamic_cast<classad::ClassAd *>( this->te_classad->Lookup(te_s_TotalRemoteRusage) );
      jtev->total_remote_rusage = toRusage( tmp );

      break;
    }
    case ULOG_IMAGE_SIZE: {
      JobImageSizeEvent   *jisev = dynamic_cast<JobImageSizeEvent *>( this->te_event.get() );

      int size = jisev->image_size_kb;
      this->te_classad->EvaluateAttrNumber(te_s_Size, size);

      break;
    }
    case ULOG_SHADOW_EXCEPTION: {
      ShadowExceptionEvent  *seev = dynamic_cast<ShadowExceptionEvent *>( this->te_event.get() );

      this->te_classad->EvaluateAttrString( te_s_Message, sval );
      strncpy( seev->message, sval.c_str(), BUFSIZ );

      this->te_classad->EvaluateAttrNumber( te_s_SentBytes, dval ); seev->sent_bytes = static_cast<float>( dval );
      this->te_classad->EvaluateAttrNumber( te_s_RecvdBytes, dval ); seev->recvd_bytes = static_cast<float>( dval );

      break;
    }
    case ULOG_GENERIC: {
      GenericEvent   *gev = dynamic_cast<GenericEvent *>( this->te_event.get() );

      this->te_classad->EvaluateAttrString( te_s_Info, sval );
      strncpy( gev->info, sval.c_str(), 128 );

      break;
    }
    case ULOG_JOB_ABORTED: {
      JobAbortedEvent  *jaev = dynamic_cast<JobAbortedEvent *>( this->te_event.get() );

      this->te_classad->EvaluateAttrString( te_s_Reason, sval );
      jaev->setReason( myStrdup(sval) );

      break;
    }
    case ULOG_JOB_SUSPENDED: {
      JobSuspendedEvent  *jseev = dynamic_cast<JobSuspendedEvent *>( this->te_event.get() );

      this->te_classad->EvaluateAttrNumber( te_s_NumPids, jseev->num_pids );

      break;
    }
    case ULOG_JOB_UNSUSPENDED: break; // Nothing seems to be done
    case ULOG_JOB_HELD: {
      JobHeldEvent   *jhev = dynamic_cast<JobHeldEvent *>( this->te_event.get() );

      this->te_classad->EvaluateAttrString( te_s_Reason, sval );
      jhev->setReason( myStrdup(sval) );
      this->te_classad->EvaluateAttrNumber( te_s_ReasonCode, ival );
      jhev->setReasonCode( ival );
      this->te_classad->EvaluateAttrNumber( te_s_ReasonSubCode, ival );
      jhev->setReasonSubCode( ival );

      break;
    }
    case ULOG_JOB_RELEASED: {
      JobReleasedEvent   *jrev = dynamic_cast<JobReleasedEvent *>( this->te_event.get() );

      this->te_classad->EvaluateAttrString( te_s_Reason, sval );
      jrev->setReason( myStrdup(sval) );

      break;
    }
    case ULOG_NODE_EXECUTE: {
      NodeExecuteEvent   *neev = dynamic_cast<NodeExecuteEvent *>( this->te_event.get() );

      this->te_classad->EvaluateAttrNumber( te_s_Node, neev->node );

      this->te_classad->EvaluateAttrString( te_s_ExecuteHost, sval );
      neev->setExecuteHost(myStrdup(sval.substr(0, 128)));

      break;
    }
    case ULOG_NODE_TERMINATED: {
      NodeTerminatedEvent *ntev = dynamic_cast<NodeTerminatedEvent *>( this->te_event.get() );
      classad::ClassAd   *tmp;

      this->te_classad->EvaluateAttrBool( te_s_Normal, ntev->normal );
      this->te_classad->EvaluateAttrNumber( te_s_ReturnValue, ntev->returnValue );
      this->te_classad->EvaluateAttrNumber( te_s_SignalNumber, ntev->signalNumber );
      this->te_classad->EvaluateAttrNumber( te_s_Node, ntev->node );
      this->te_classad->EvaluateAttrNumber( te_s_SentBytes, dval ); ntev->sent_bytes = static_cast<float>( dval );
      this->te_classad->EvaluateAttrNumber( te_s_RecvdBytes, dval ); ntev->recvd_bytes = static_cast<float>( dval );
      this->te_classad->EvaluateAttrNumber( te_s_TotalSentBytes, dval ); ntev->total_sent_bytes = static_cast<float>( dval );
      this->te_classad->EvaluateAttrNumber( te_s_TotalRecvdBytes, dval ); ntev->total_recvd_bytes = static_cast<float>( dval );
      this->te_classad->EvaluateAttrString( te_s_CoreFile, sval ); ntev->setCoreFile( myStrdup(sval) );

      tmp = dynamic_cast<classad::ClassAd *>( this->te_classad->Lookup(te_s_RunLocalRusage) );
      ntev->run_local_rusage = toRusage( tmp );

      tmp = dynamic_cast<classad::ClassAd *>( this->te_classad->Lookup(te_s_RunRemoteRusage) );
      ntev->run_remote_rusage = toRusage( tmp );

      tmp = dynamic_cast<classad::ClassAd *>( this->te_classad->Lookup(te_s_TotalLocalRusage) );
      ntev->total_local_rusage = toRusage( tmp );

      tmp = dynamic_cast<classad::ClassAd *>( this->te_classad->Lookup(te_s_TotalRemoteRusage) );
      ntev->total_remote_rusage = toRusage( tmp );

      break;
    }
    case ULOG_POST_SCRIPT_TERMINATED: {
      PostScriptTerminatedEvent   *pstev = dynamic_cast<PostScriptTerminatedEvent *>( this->te_event.get() );

      this->te_classad->EvaluateAttrBool( te_s_Normal, pstev->normal );
      this->te_classad->EvaluateAttrNumber( te_s_ReturnValue, pstev->returnValue );
      this->te_classad->EvaluateAttrNumber( te_s_SignalNumber, pstev->signalNumber );

      break;
    }
    case ULOG_GLOBUS_SUBMIT: {
      GlobusSubmitEvent    *gsev = dynamic_cast<GlobusSubmitEvent *>( this->te_event.get() );

      this->te_classad->EvaluateAttrBool( te_s_RestartableJM, gsev->restartableJM );

      this->te_classad->EvaluateAttrString( te_s_RmContact, sval );
      gsev->rmContact = myStrdup( sval );

      this->te_classad->EvaluateAttrString( te_s_JmContact, sval );
      gsev->jmContact = myStrdup( sval );

      break;
    }
    case ULOG_GLOBUS_SUBMIT_FAILED: {
      GlobusSubmitFailedEvent   *gsfev = dynamic_cast<GlobusSubmitFailedEvent *>( this->te_event.get() );

      this->te_classad->EvaluateAttrString( te_s_Reason, sval );
      gsfev->reason = myStrdup( sval );

      break;
    }
    case ULOG_GLOBUS_RESOURCE_UP: {
      GlobusResourceUpEvent   *gruev = dynamic_cast<GlobusResourceUpEvent *>( this->te_event.get() );

      this->te_classad->EvaluateAttrString( te_s_RmContact, sval );
      gruev->rmContact = myStrdup( sval );

      break;
    }
    case ULOG_GLOBUS_RESOURCE_DOWN: {
      GlobusResourceDownEvent  *grdev = dynamic_cast<GlobusResourceDownEvent *>( this->te_event.get() );

      this->te_classad->EvaluateAttrString( te_s_RmContact, sval );
      grdev->rmContact = myStrdup( sval );

      break;
    }
    case ULOG_REMOTE_ERROR: {
      bool                     bval;
      RemoteErrorEvent        *reev = dynamic_cast<RemoteErrorEvent *>( this->te_event.get() );

      this->te_classad->EvaluateAttrString( te_s_ExecuteHost, sval );
      reev->setExecuteHost( myStrdup( sval ) );
      this->te_classad->EvaluateAttrString( te_s_DaemonName, sval );
      reev->setDaemonName( myStrdup ( sval ) );
      this->te_classad->EvaluateAttrString( te_s_ErrorStr, sval );
      reev->setErrorText( myStrdup ( sval ) );
      this->te_classad->EvaluateAttrBool( te_s_CriticalError, bval );
      reev->setCriticalError( bval );

      break;
    }
    case ULOG_JOB_DISCONNECTED: {
      JobDisconnectedEvent     *jdcev = dynamic_cast<JobDisconnectedEvent *>( this->te_event.get() );

      this->te_classad->EvaluateAttrString( te_s_StartdAddr, sval );
      jdcev->setStartdAddr( myStrdup( sval ) );
      this->te_classad->EvaluateAttrString( te_s_StartdName, sval );
      jdcev->setStartdName( myStrdup( sval ) );
      this->te_classad->EvaluateAttrString( te_s_DisconnReason, sval );
      jdcev->setDisconnectReason( myStrdup( sval ) );
      this->te_classad->EvaluateAttrString( te_s_NoReconnReason, sval );
      jdcev->setNoReconnectReason( myStrdup( sval ) );

      break;
    }
    case ULOG_JOB_RECONNECTED: {
      JobReconnectedEvent      *jrcev = dynamic_cast<JobReconnectedEvent *>( this->te_event.get() );

      this->te_classad->EvaluateAttrString( te_s_StartdAddr, sval );
      jrcev->setStartdAddr( myStrdup( sval ) );
      this->te_classad->EvaluateAttrString( te_s_StartdName, sval );
      jrcev->setStartdName( myStrdup( sval ) );
      this->te_classad->EvaluateAttrString( te_s_StarterAddr, sval );
      jrcev->setStarterAddr( myStrdup( sval ) );

      break;
    }
    case ULOG_JOB_RECONNECT_FAILED: {
      JobReconnectFailedEvent *jrcfev = dynamic_cast<JobReconnectFailedEvent *>( this->te_event.get() );

      this->te_classad->EvaluateAttrString( te_s_StartdName, sval );
      jrcfev->setStartdName( myStrdup( sval ) );
      this->te_classad->EvaluateAttrString( te_s_Reason, sval );
      jrcfev->setReason( myStrdup( sval ) );

      break;
    }
    case ULOG_GRID_SUBMIT: {
      GridSubmitEvent    *gsev = dynamic_cast<GridSubmitEvent *>( this->te_event.get() );

      this->te_classad->EvaluateAttrString( te_s_ResourceName, sval );
      gsev->resourceName = myStrdup( sval );

      this->te_classad->EvaluateAttrString( te_s_JobId, sval );
      gsev->jobId = myStrdup( sval );

      break;
    }
    case ULOG_GRID_RESOURCE_UP: {
      GridResourceUpEvent   *gruev = dynamic_cast<GridResourceUpEvent *>( this->te_event.get() );

      this->te_classad->EvaluateAttrString( te_s_ResourceName, sval );
      gruev->resourceName = myStrdup( sval );

      break;
    }
    case ULOG_GRID_RESOURCE_DOWN: {
      GridResourceDownEvent  *grdev = dynamic_cast<GridResourceDownEvent *>( this->te_event.get() );

      this->te_classad->EvaluateAttrString( te_s_ResourceName, sval );
      grdev->resourceName = myStrdup( sval );

      break;
    }
    }
  }

  return this->te_event.get();
}

Timer::Timer( const string &backup ) : t_filename( backup ), t_events(), t_backup( backup )
{
  string                   val;
  FileContainer::iterator  fileIt, end = this->t_backup.end();
  EventPointer             ptr;

  if( !this->t_backup.empty() )
    for( fileIt = this->t_backup.begin(); fileIt != end; ++fileIt ) {
      ptr.reset( new TimeoutEvent(*fileIt) );

      ptr->pointer( fileIt );
      this->t_events.insert( EventMap::value_type(ptr->timeout(), ptr) );
    }
  // Let's save an open file descriptor.
  this->t_backup.close();
}

Timer::~Timer( void )
{}

Timer &Timer::start_timer( time_t expire, ULogEvent *ptr )
{
  EventPointer               event( new TimeoutEvent(expire, ptr) );
  FileContainer::iterator    fIt;

  this->t_backup.open(this->t_filename);

  this->t_backup.push_back( *event->to_classad() );
  fIt = this->t_backup.end(); --fIt;

  event->pointer( fIt );
  this->t_events.insert( EventMap::value_type(expire, event) );

  // Let's save an open file descriptor.
  this->t_backup.close();

  return *this;
}

Timer &Timer::remove_timeout( EventIterator &evIt )
{
  FileContainer::iterator     ptr;

  if( evIt != this->t_events.end() ) {
    ptr = evIt->second->pointer();

    this->t_backup.open(this->t_filename);
    this->t_backup.erase( ptr );
    // Let's save an open file descriptor.
    this->t_backup.close();

    this->t_events.erase( evIt );
  }

  return *this;
}

// remove _all_ the timeouts associated with the given eventcode
Timer &Timer::remove_timeout( int condorid, int eventcode )
{
  EventIterator    it, end = this->t_events.end();
  list<EventIterator>            evList;
  list<EventIterator>::iterator  evIt;

  for( it = this->t_events.begin(); it != end; ++it )
    if( (it->second->to_event()->cluster == condorid ) &&
	( it->second->to_event()->eventNumber == static_cast<ULogEventNumber>(eventcode) ) )
      evList.push_back( it );

  if( !evList.empty() )
     for( evIt = evList.begin(); evIt != evList.end(); ++evIt )
       this->remove_timeout( *evIt );

  return *this;
}

Timer &Timer::remove_all_timeouts( int condorid )
{
  EventIterator                  it, end = this->t_events.end();
  list<EventIterator>            evList;
  list<EventIterator>::iterator  evIt;

  for( it = this->t_events.begin(); it != end; ++it )
    if( it->second->to_event()->cluster == condorid )
      evList.push_back( it );

  if( !evList.empty() )
    for( evIt = evList.begin(); evIt != evList.end(); ++evIt )
      this->remove_timeout( *evIt );

  return *this;
}

} // Namespace logmonitor

} JOBCONTROL_NAMESPACE_END

max_stars_repo_name: italiangrid/wms

max_issues_repo_name: italiangrid/wms

max_forks_repo_name: italiangrid/wms


text:
#if !defined DACHS_CODEGEN_LLVMIR_IR_BUILDER_HELPER_HPP_INCLUDED
#define      DACHS_CODEGEN_LLVMIR_IR_BUILDER_HELPER_HPP_INCLUDED

#include <memory>
#include <algorithm>
#include <utility>
#include <cstddef>

#include <boost/range/irange.hpp>
#include <boost/range/adaptor/filtered.hpp>

#include "dachs/exception.hpp"
#include "dachs/fatal.hpp"
#include "dachs/semantics/type.hpp"
#include "dachs/semantics/semantics_context.hpp"
#include "dachs/codegen/llvmir/ir_utility.hpp"
#include "dachs/codegen/llvmir/context.hpp"
#include "dachs/codegen/llvmir/type_ir_emitter.hpp"
#include "dachs/codegen/llvmir/gc_alloc_emitter.hpp"
#include "dachs/helper/util.hpp"
#include "dachs/helper/llvm.hpp"
#include "dachs/helper/probable.hpp"

namespace dachs {
namespace codegen {
namespace llvmir {
namespace builder {

using boost::adaptors::filtered;
using boost::irange;
using helper::dump;

template<class Node>
class block_branch_helper {
    using node_type = std::shared_ptr<Node>;
    using parent_ptr_type = decltype(std::declval<llvm::IRBuilder<>>().GetInsertBlock()->getParent());

    node_type const& node;
    context &ctx;
    parent_ptr_type const parent;

    template<class String>
    [[noreturn]]
    void error(String const& msg) const
    {
        llvmir::error(node, msg);
    }

    template<class T, class String>
    T check(T const v, String const& feature) const
    {
        return llvmir::check(node, v, feature);
    }

public:
    block_branch_helper(node_type const& n, context &c) noexcept
        : node(n), ctx(c), parent(c.builder.GetInsertBlock()->getParent())
    {}

    parent_ptr_type get_parent() const noexcept
    {
        return parent;
    }

    bool has_parent() const noexcept
    {
        return parent;
    }

    // If current block is not terminated, create br
    llvm::BranchInst *terminate_with_br(llvm::BasicBlock *const dest, llvm::BasicBlock *const next = nullptr)
    {
        llvm::BranchInst *br = nullptr;

        if (!ctx.builder.GetInsertBlock()->getTerminator()) {
            br = check(ctx.builder.CreateBr(dest), "branch instruction");
        }

        if (next) {
            ctx.builder.SetInsertPoint(next);
        }
        return br;
    }

    void append_block(llvm::BasicBlock *const b)
    {
        if (!parent) {
            error("No parent found");
        }

        auto *current_block = ctx.builder.GetInsertBlock();
        parent->getBasicBlockList().insertAfter(current_block, b);
        ctx.builder.SetInsertPoint(b);
    }

    void append_block(llvm::BasicBlock *const b, llvm::BasicBlock *const next)
    {
        if (!parent) {
            error("No parent found");
        }

        auto *const current_block = ctx.builder.GetInsertBlock();
        parent->getBasicBlockList().insertAfter(current_block, b);
        if (next) {
            ctx.builder.SetInsertPoint(next);
        }
    }

    llvm::BranchInst *create_br(llvm::BasicBlock *const b)
    {
        auto const br = check(ctx.builder.CreateBr(b), "branch instruction");
        ctx.builder.SetInsertPoint(b);
        return br;
    }

    llvm::BranchInst *create_br(llvm::BasicBlock *const b, llvm::BasicBlock *const next)
    {
        auto const br = check(ctx.builder.CreateBr(b), "branch instruction");
        if (next) {
            ctx.builder.SetInsertPoint(next);
        }
        return br;
    }

    llvm::BranchInst *create_cond_br(llvm::Value *const cond_val, llvm::BasicBlock *const if_true, llvm::BasicBlock *const if_false, llvm::BasicBlock *const next)
    {
        auto const cond_br = check(ctx.builder.CreateCondBr(cond_val, if_true, if_false), "condition branch");
        if (next) {
            ctx.builder.SetInsertPoint(next);
        }
        return cond_br;
    }

    llvm::BranchInst *create_cond_br(llvm::Value *const cond_val, llvm::BasicBlock *const if_true, llvm::BasicBlock *const if_false)
    {
        auto const cond_br = check(ctx.builder.CreateCondBr(cond_val, if_true, if_false), "condition branch");
        ctx.builder.SetInsertPoint(if_true);
        return cond_br;
    }

    template<class String>
    llvm::BasicBlock *create_block_for_parent(String const& name = "", bool const move_to_the_block = false)
    {
        if (!parent) {
            error("No parent found");
        }

        auto const the_block = check(llvm::BasicBlock::Create(ctx.llvm_context, name, parent), "basic block");
        if (move_to_the_block) {
            ctx.builder.SetInsertPoint(the_block);
        }
        return the_block;
    }

    template<class String = char const* const>
    auto create_block(String const& name = "", bool const move_to_the_block = false) const
    {
        auto const the_block = check(llvm::BasicBlock::Create(ctx.llvm_context, name), "basic block");
        if (move_to_the_block) {
            ctx.builder.SetInsertPoint(the_block);
        }
        return the_block;
    }

};

class inst_emit_helper {
    context &ctx;
    type_ir_emitter &type_emitter;
    llvm::Module &module;

    using probable_type = helper::probable<llvm::Value *>;

public:

    inst_emit_helper(context &c, type_ir_emitter &e, llvm::Module &m) noexcept
        : ctx(c), type_emitter(e), module(m)
    {}

    llvm::Value *emit_elem_value(llvm::Value *const v, type::type const& t)
    {
        // Note:
        // When the element is pointer, pointer should be loaded
        if (t.is_builtin()) {
            return v;
        }

        auto *const ty = type_emitter.emit(t);
        if (ty == v->getType()) {
            return v;
        } else {
            return ctx.builder.CreateLoad(v);
        }
    }

    probable_type emit_builtin_element_access(llvm::Value *const aggregate, llvm::Value *const index, type::type const& t)
    {
        index->setName("idx");
        if (auto const tuple = type::get<type::tuple_type>(t)) {
            return emit_builtin_element_access(aggregate, index, *tuple);
        } else if (auto const array = type::get<type::array_type>(t)) {
            return emit_builtin_element_access(aggregate, index, *array);
        } else if (auto const ptr = type::get<type::pointer_type>(t)) {
            return emit_builtin_element_access(aggregate, index, *ptr);
        }

        return helper::oops("Value is not tuple, static_array and pointer");
    }

    probable_type emit_builtin_element_access(llvm::Value *const aggregate, llvm::Value *const index, type::tuple_type const& t)
    {
        assert(aggregate->getType()->isPointerTy());
        assert(aggregate->getType()->getPointerElementType()->isStructTy());

        auto *const constant_index = llvm::dyn_cast<llvm::ConstantInt>(index);
        if (!constant_index) {
            return helper::oops("Index is not a constant");
        }

        auto const idx = constant_index->getZExtValue();
        assert(t->element_types.size() > idx);
        return emit_elem_value(ctx.builder.CreateStructGEP(aggregate, idx), t->element_types[idx]);
    }

    probable_type emit_builtin_element_access(llvm::Value *const aggregate, llvm::Value *const index, type::array_type const& t)
    {
        assert(aggregate->getType()->isPointerTy());
        assert(t->size);

        auto *const constant_index = llvm::dyn_cast<llvm::ConstantInt>(index);
        if (constant_index) {
            auto const idx = constant_index->getZExtValue();
            auto const size = *t->size;

            if (idx >= size) {
                return helper::oops_fmt("Array index is out of bounds %1% for 0..%2%", idx, size);
            }
        }

        return emit_elem_value(
                ctx.builder.CreateInBoundsGEP(
                    aggregate,
                    index
                ), t->element_type
            );
    }

    probable_type emit_builtin_element_access(llvm::Value *const ptr_value, llvm::Value *const index, type::pointer_type const& t)
    {
        assert(ptr_value->getType()->isPointerTy());

        // Note:
        // Pointer's type may be T** because 'alloca T*' is executed to make pointer instance.
        // It is necessary to load it before access to its contents.
        return emit_elem_value(
                ctx.builder.CreateInBoundsGEP(
                    ptr_value,
                    index
                ),
                t->pointee_type
            );
    }

    llvm::GlobalVariable *emit_unit_constant()
    {
        auto *unit_constant
            = module.getGlobalVariable("const.unit", true /*Allow internal*/);

        if (!unit_constant) {
            unit_constant = new llvm::GlobalVariable(
                    module,
                    llvm::StructType::get(ctx.llvm_context, {}),
                    true,
                    llvm::GlobalValue::PrivateLinkage,
                    llvm::ConstantStruct::getAnon(ctx.llvm_context, {}),
                    "const.unit"
                );
            unit_constant->setUnnamedAddr(true);
        }

        return unit_constant;
    }
};

class allocation_helper {
    context &ctx;
    type_ir_emitter &type_emitter;
    detail::gc_alloc_emitter &gc_emitter;
    semantics::lambda_captures_type const& lambda_captures;
    semantics::semantics_context const& semantics_ctx;
    llvm::Module &module;

public:

    allocation_helper(
            context &c,
            type_ir_emitter &e,
            detail::gc_alloc_emitter &ge,
            decltype(lambda_captures) const& cs,
            decltype(semantics_ctx) const& sctx,
            llvm::Module &m
    ) noexcept
        : ctx(c)
        , type_emitter(e)
        , gc_emitter(ge)
        , lambda_captures(cs)
        , semantics_ctx(sctx)
        , module(m)
    {}

    template<class Ptr>
    llvm::CallInst *create_memset(Ptr *const p, llvm::Type *const ty, type::type const& t)
    {
        auto const emit_memset
            = [p, ty, this](auto const size, auto const align)
            {
                return ctx.builder.CreateMemSet(
                        p,
                        ctx.builder.getInt8(0u),
                        size,
                        align
                    );
            };

        if (type::is_a<type::pointer_type>(t)) {
            return nullptr;
        }

        if (auto const a = type::get<type::array_type>(t)) {
            assert((*a)->size);
            auto const s = *(*a)->size;
            if (s == 0u) {
                return nullptr;
            }

            auto *const elem_ty = ty->getPointerElementType();
            assert(elem_ty);
            auto const size = ctx.data_layout->getTypeAllocSize(elem_ty) * s;
            auto *const array_ty = llvm::ArrayType::get(elem_ty, s);

            return emit_memset(
                    size,
                    ctx.data_layout->getPrefTypeAlignment(array_ty)
                );
        } else {
            return emit_memset(
                    ctx.data_layout->getTypeAllocSize(ty),
                    ctx.data_layout->getPrefTypeAlignment(ty)
                );
        }
    }

    template<class Dest, class Src>
    llvm::CallInst *create_memcpy_array(Dest *const dest_val, Src *const src_val, type::array_type const& t)
    {
        assert(dest_val->getType()->isPointerTy());
        assert(src_val->getType()->isPointerTy());
        assert(t->size);

        // Note:
        // There is no element to copy
        if (*t->size == 0u) {
            return nullptr;
        }

        auto const ty = dest_val->getType()->getPointerElementType();
        auto const elem_size = ctx.data_layout->getTypeAllocSize(ty);
        auto const array_ty = llvm::ArrayType::get(ty, elem_size);
        return ctx.builder.CreateMemCpy(
                dest_val,
                src_val,
                elem_size *(*t->size),
                ctx.data_layout->getPrefTypeAlignment(array_ty)
            );
    }

    template<class String = char const* const>
    llvm::Value *create_alloca_impl(type::type const& t, String const& name = "")
    {
        if (auto const a = type::get<type::array_type>(t)) {
            // Note:
            // It reaches here for the special case; 'static_array'.
            assert((*a)->size);
            auto *const allocated = ctx.builder.CreateAlloca(type_emitter.emit_alloc_fixed_array(*a), nullptr /*size*/, name);
            return ctx.builder.CreateConstInBoundsGEP2_32(allocated, 0u, 0u);
        }

        return gc_emitter.emit_alloc(t, name);
    }

    // TODO:
    // Use visitor which visits type::type
    template<class String = char const* const>
    llvm::Value *create_alloca(type::type const& t, bool const init_by_zero = true, String const& name = "")
    {
        auto *const allocated = create_alloca_impl(t, name);

        if (init_by_zero) {
            create_memset(allocated, allocated->getType(), t);
        }

        if (auto const array = type::get<type::array_type>(t)) {
            auto const& elem_type = (*array)->element_type;
            if (!elem_type.is_aggregate()) {
                return allocated;
            }

            // Note:
            // Why doesn't this assertion fail in tests?
            assert((*array)->size);
            for (uint32_t const idx : helper::indices(*(*array)->size)) {
                ctx.builder.CreateStore(
                        create_alloca(elem_type, init_by_zero),
                        ctx.builder.CreateConstInBoundsGEP1_32(allocated, idx)
                    );
            }
        } else if (auto const ptr = type::get<type::pointer_type>(t)) {
            return allocated;
        } else if (auto const tuple = type::get<type::tuple_type>(t)) {
            // TODO:
            // If all members are built-in type, use memcpy to copy all elements
            for (auto const idx : helper::indices((*tuple)->element_types)) {
                auto const& elem_type = (*tuple)->element_types[idx];
                if (!elem_type.is_aggregate()) {
                    continue;
                }

                ctx.builder.CreateStore(
                        create_alloca(elem_type, init_by_zero),
                        ctx.builder.CreateStructGEP(allocated, idx)
                    );
            }
        } else if (auto const clazz = type::get<type::class_type>(t)) {
            auto const& c = *clazz;
            assert(c->param_types.empty());
            auto const scope = c->ref.lock();
            assert(!scope->is_template());
            for (auto const idx : helper::indices(scope->instance_var_symbols)) {
                auto const& var_type = scope->instance_var_symbols[idx]->type;
                if (!var_type.is_aggregate()) {
                    continue;
                }

                ctx.builder.CreateStore(
                        create_alloca(var_type, init_by_zero),
                        ctx.builder.CreateStructGEP(allocated, idx)
                    );
            }
        } else if (auto const generic_func = type::get<type::generic_func_type>(t)) {
            auto const& g = *generic_func;
            if (!g->ref || g->ref->expired()) {
                return allocated;
            }

            auto const itr = lambda_captures.find(g);
            if (itr == std::end(lambda_captures)) {
                return allocated;
            }

            auto const& captures = itr->second;
            for (auto const& capture : captures) {
                auto const& capture_type = capture.introduced->type;
                if (!capture_type.is_aggregate()) {
                    continue;
                }

                ctx.builder.CreateStore(
                        create_alloca(capture_type, init_by_zero),
                        ctx.builder.CreateStructGEP(allocated, capture.offset)
                    );
            }
        }

        return allocated;
    }

    template<class V, class String = char const* const>
    llvm::Value *alloc_and_deep_copy(V *const from, type::type const& t, String const& name = "")
    {
        // TODO:
        // Do allocate and copy from 'from' at once.
        // It enables to use memcpy instead of load and store insts for each element of aggregates
        // by calling memset() at first and then emitting alloc inst for each aggregate elements.
        auto *const allocated = create_alloca(t, false, name);
        assert(allocated);

        create_deep_copy(from, allocated, t);

        return allocated;
    }

    template<class V1, class V2>
    llvm::StoreInst *copy_non_aggregate_value(V1 *const from, V2 *const to)
    {
        auto *const from_ty = from->getType();
        auto *const to_ty = to->getType();

        assert(to_ty->isPointerTy());

        if (!from_ty->isPointerTy()) {
            assert(from_ty == to_ty->getPointerElementType());
            return ctx.builder.CreateStore(from, to);
        }

        if (from_ty->getPointerTo() == to_ty) {
            return ctx.builder.CreateStore(from, to);
        }

        assert(from_ty == to_ty);

        return ctx.builder.CreateStore(ctx.builder.CreateLoad(from), to);
    }

    template<class V1, class V2>
    void user_defined_copy(scope::func_scope const& copier, V1 *const from, V2 *const to)
    {
        ctx.builder.CreateStore(
            ctx.builder.CreateCall(
                    module.getFunction(copier->to_string()),
                    ctx.builder.CreateLoad(from),
                    "copier_call"
                ),
            to
        );
    }

    template<class V1, class V2>
    void deep_copy_recursively(V1 *const from, V2 *const to, type::type const& t)
    {
        if (auto const copier = semantics_ctx.copier_of(t)) {
            user_defined_copy(*copier, from, to);
            return;
        }

        create_deep_copy(
                ctx.builder.CreateLoad(from),
                ctx.builder.CreateLoad(to),
                t
            );
    }

    // TODO:
    // Use visitor which visits type::type
    template<class V1, class V2>
    void create_deep_copy_impl(V1 *const from, V2 *const to, type::type const& t)
    {
        assert(to->getType()->isPointerTy());
        assert(from->getType()->isPointerTy());
        assert(!t.is_builtin());

        if (auto const tuple_ = type::get<type::tuple_type>(t)) {
            auto const& tuple = *tuple_;

            for (auto const idx : helper::indices(tuple->element_types)) {
                auto const& elem_type = tuple->element_types[idx];
                auto *const elem_from = ctx.builder.CreateStructGEP(from, idx);
                auto *const elem_to = ctx.builder.CreateStructGEP(to, idx);

                if (!elem_type.is_aggregate()) {
                    copy_non_aggregate_value(elem_from, elem_to);
                    continue;
                }

                deep_copy_recursively(elem_from, elem_to, elem_type);
            }
        } else if (auto const array_ = type::get<type::array_type>(t)) {
            auto const& array = *array_;
            auto const& elem_type = array->element_type;

            if (elem_type.is_builtin()) {
                create_memcpy_array(to, from, array);
                return;
            }

            assert(array->size);

            for (uint64_t const idx : helper::indices(*array->size)) {
                auto *const elem_from =
                            ctx.builder.CreateConstInBoundsGEP1_32(from, idx);
                auto *const elem_to =
                            ctx.builder.CreateConstInBoundsGEP1_32(to, idx);

                deep_copy_recursively(elem_from, elem_to, elem_type);
            }
        } else if (type::is_a<type::pointer_type>(t)) {
            // Note:
            // Shallow copy
            ctx.builder.CreateStore(from, to);
        } else if (auto const clazz_ = type::get<type::class_type>(t)) {
            auto const& clazz = *clazz_;
            assert(clazz->param_types.empty());
            auto const scope = clazz->ref.lock();
            assert(!scope->is_template());

            for (auto const idx : helper::indices(scope->instance_var_symbols)) {
                auto const& var_type = scope->instance_var_symbols[idx]->type;
                auto *const elem_from = ctx.builder.CreateStructGEP(from, idx);
                auto *const elem_to = ctx.builder.CreateStructGEP(to, idx);

                elem_from->setName("copy." + scope->name + "." + scope->instance_var_symbols[idx]->name + ".from");
                elem_to->setName("copy." + scope->name + "." + scope->instance_var_symbols[idx]->name + ".to");

                if (!var_type.is_aggregate()) {
                    copy_non_aggregate_value(elem_from, elem_to);
                    continue;
                }

                deep_copy_recursively(elem_from, elem_to, var_type);
            }
        } else if (auto const generic_func = type::get<type::generic_func_type>(t)){
            auto const& g = *generic_func;
            if (!g->ref || g->ref->expired()) {
                return;
            }

            auto const itr = lambda_captures.find(g);
            if (itr == std::end(lambda_captures)) {
                return;
            }

            auto const& captures = itr->second;
            for (auto const& capture : captures) {
                auto const& capture_type = capture.introduced->type;
                auto *const elem_from = ctx.builder.CreateStructGEP(from, capture.offset);
                auto *const elem_to = ctx.builder.CreateStructGEP(to, capture.offset);

                elem_from->setName("copy.lambda." + capture.refered_symbol->name + ".from");
                elem_to->setName("copy.lambda." + capture.refered_symbol->name + ".to");

                if (!capture_type.is_aggregate()) {
                    copy_non_aggregate_value(elem_from, elem_to);
                    continue;
                }

                deep_copy_recursively(elem_from, elem_to, capture_type);
            }
        } else if (type::is_a<type::func_type>(t)){
            ctx.builder.CreateStore(from, to);
        } else {
            DACHS_RAISE_INTERNAL_COMPILATION_ERROR
        }
    }

    template<class V1, class V2>
    void create_deep_copy(V1 *const from, V2 *const to, type::type const& t)
    {
        if (!t.is_aggregate()) {
            copy_non_aggregate_value(from, to);
            return;
        }

        create_deep_copy_impl(from, to, t);
    }

};

} // namespace builder
} // namespace llvmir
} // namespace codegen
} // namespace dachs

#endif    // DACHS_CODEGEN_LLVMIR_IR_BUILDER_HELPER_HPP_INCLUDED

ext: hpp

max_stars_repo_name: rhysd/Dachs

max_stars_repo_licenses: NCSA MIT

max_issues_repo_name: maekawatoshiki/Dachs

max_issues_repo_licenses: NCSA MIT

max_forks_repo_name: maekawatoshiki/Dachs

max_forks_repo_licenses: NCSA MIT


text:
////////////////////////////////////////////////////////////////////////////////////////////////////
// action.hpp
// Helpers for building Proto actions.
//
//  Copyright 2012 Eric Niebler. Distributed under the Boost
//  Software License, Version 1.0. (See accompanying file
//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#ifndef BOOST_PROTO_V5_ACTION_BASIC_ACTION_HPP_INCLUDED
#define BOOST_PROTO_V5_ACTION_BASIC_ACTION_HPP_INCLUDED

#include <utility>
#include <type_traits>
#include <boost/proto/v5/proto_fwd.hpp>
#include <boost/proto/v5/utility.hpp>

namespace boost
{
    namespace proto
    {
        inline namespace v5
        {
            namespace detail
            {
                ////////////////////////////////////////////////////////////////////////////////////
                // return_
                using return_ = utility::identity;

                ////////////////////////////////////////////////////////////////////////////////////
                template<typename Action>
                struct call_action_
                {
                    template<typename ...Args, typename A = Action>
                    constexpr auto operator()(Args &&... args) const
                    BOOST_PROTO_AUTO_RETURN(
                        BOOST_PROTO_TRY_CALL(as_action_<A>())(static_cast<Args &&>(args)...)
                    )
                };

                ////////////////////////////////////////////////////////////////////////////////////
                struct not_an_action
                {};

                ////////////////////////////////////////////////////////////////////////////////////
                template<typename BoolAction, typename ...Args>
                struct eval_bool_action_
                  : std::integral_constant<
                        bool
                      , static_cast<bool>(
                            std::remove_reference<
                                decltype(call_action_<BoolAction>()(std::declval<Args>()...))
                            >::type::value
                        )
                    >
                {};

                ////////////////////////////////////////////////////////////////////////////////////
                // normalize_action_
                template<typename T, typename Enable = void>
                struct normalize_action_
                {
                    using type = T;
                };

                template<typename Ret, typename ...Args>
                struct normalize_action_<Ret(Args...), utility::always_void<typename Ret::proto_action_type>>
                {
                    using type = typename Ret::proto_action_type(Args...);
                };

                template<typename Ret, typename ...Args>
                struct normalize_action_<Ret(Args......), utility::always_void<typename Ret::proto_action_type>>
                {
                    using type = typename Ret::proto_action_type(Args......);
                };

                ////////////////////////////////////////////////////////////////////////////////////
                // as_action_impl_
                template<typename T>
                struct as_action_impl_
                {
                    using type = T;
                };

                template<typename Ret, typename ...Args>
                struct as_action_impl_<Ret(Args...)>
                {
                    using type =
                        extension::action_impl<typename normalize_action_<Ret(Args...)>::type>;
                };

                template<typename Ret, typename ...Args>
                struct as_action_impl_<Ret(Args......)>
                {
                    using type =
                        extension::action_impl<typename normalize_action_<Ret(Args......)>::type>;
                };

                template<typename Ret, typename ...Args>
                struct as_action_impl_<Ret(*)(Args...)>
                  : as_action_impl_<Ret(Args...)>
                {};

                template<typename Ret, typename ...Args>
                struct as_action_impl_<Ret(*)(Args......)>
                  : as_action_impl_<Ret(Args......)>
                {};
            }

            namespace extension
            {
                template<typename T>
                struct not_an_action
                  : detail::not_an_action
                {
                    template<typename ...Args>
                    constexpr utility::any operator()(Args &&...) const noexcept
                    {
                        static_assert(
                            utility::never<T>::value
                          , "Unknown action pattern used in proto::action"
                        );
                        return utility::any();
                    }
                };

                template<typename Action, typename Enable>
                struct action_impl
                  : not_an_action<Action>
                {};
            }

            ////////////////////////////////////////////////////////////////////////////////////////
            // action_base
            struct action_base
            {};

            ////////////////////////////////////////////////////////////////////////////////////////
            // basic_action
            // CRTP base class for all primitive actions
            template<typename Action>
            struct basic_action
              : action_base
            {};

            ////////////////////////////////////////////////////////////////////////////////////////
            // is_action
            template<typename T>
            struct is_action
              : std::integral_constant<
                    bool
                  , std::is_base_of<action_base, T>::value ||
                    (
                        std::is_base_of<detail::def_base, T>::value &&
                       !std::is_base_of<detail::not_an_action, T>::value
                    )
                >
            {};

            template<typename T>
            struct is_action<T &>
              : is_action<T>
            {};

            template<typename T>
            struct is_action<T &&>
              : is_action<T>
            {};

            template<typename Ret, typename ...Args>
            struct is_action<Ret(Args...)>
              : std::integral_constant<
                    bool
                  , !std::is_base_of<
                        detail::not_an_action
                      , detail::as_action_<Ret(Args...)>
                    >::value
                >
            {};

            template<typename Ret, typename ...Args>
            struct is_action<Ret(Args......)>
              : std::integral_constant<
                    bool
                  , !std::is_base_of<
                        detail::not_an_action
                      , detail::as_action_<Ret(Args......)>
                    >::value
                >
            {};

            template<typename Ret, typename ...Args>
            struct is_action<Ret(*)(Args...)>
              : is_action<Ret(Args...)>
            {};

            template<typename Ret, typename ...Args>
            struct is_action<Ret(*)(Args......)>
              : is_action<Ret(Args......)>
            {};
        }
    }
}

#endif