<commit_before>/*
 *  MT_RobotFrameBase.cpp
 *
 *  Created by Daniel Swain on 1/4/10.
 *
 */

#include "MT_RobotFrameBase.h"

MT_RobotFrameBase::MT_RobotFrameBase(wxFrame* parent,
                                     wxWindowID id,
                                     const wxString& title,
                                     const wxPoint& pos,
                                     const wxSize& size,
                                     long style)
  : MT_TrackerFrameBase(parent, id, title, pos, size, style),
    m_pRobotControlFrame(NULL),
    m_pJoyStickFrame(NULL),
    m_bAutoIdentify(false),
    m_bRobotsIdentified(false),
    m_Robots(),
    m_pTrackedObjects(NULL)
{
	MT_RobotConnectDialog* dlg = new MT_RobotConnectDialog(&m_Robots, this);
    registerDialogForXML(dlg);
    dlg->Show(true);
}

MT_RobotFrameBase::~MT_RobotFrameBase()
{

}

void MT_RobotFrameBase::handleCommandLineArguments(int argc, wxChar** argv)
{
    MT_TrackerFrameBase::handleCommandLineArguments(argc, argv);
}

void MT_RobotFrameBase::handleOpenWithFile(const wxString& filename)
{
    MT_TrackerFrameBase::handleOpenWithFile(filename);
}

bool MT_RobotFrameBase::doKeyboardCallback(wxKeyEvent& event)
{
    bool tresult = MT_TrackerFrameBase::doKeyboardCallback(event);
    return tresult && MT_DO_BASE_KEY;
}

bool MT_RobotFrameBase::doMouseCallback(wxMouseEvent& event, double viewport_x, double viewport_y)
{
    bool tresult = MT_TrackerFrameBase::doMouseCallback(event, viewport_x, viewport_y);
    return tresult && MT_DO_BASE_MOUSE;
}

void MT_RobotFrameBase::onMenuRobotsConnect(wxCommandEvent& event)
{
    MT_RobotConnectDialog* dlg = new MT_RobotConnectDialog(&m_Robots, this);
    registerDialogForXML(dlg);
    dlg->Show(true);
}

void MT_RobotFrameBase::onMenuRobotsJoystick(wxCommandEvent& event)
{
    m_pJoyStickFrame->Show(true);
    registerDialogForXML(m_pJoyStickFrame);
    m_pJoyStickFrame->EnableEvents();
}

void MT_RobotFrameBase::onMenuRobotsCommand(wxCommandEvent& event)
{
    MT_RobotCommandDialog* dlg = new MT_RobotCommandDialog(&m_Robots, this);
    registerDialogForXML(dlg);
    dlg->Show(true);
}

void MT_RobotFrameBase::readUserXML()
{
    MT_TrackerFrameBase::readUserXML();

    float maxspeed = MT_DEFAULT_MAX_SPEED;
    float maxturningrate = MT_DEFAULT_MAX_TURNING_RATE;
    MT_ReadRobotXML(&m_Robots, &maxspeed, &maxturningrate, &m_XMLSettingsFile, false);
    m_Robots.MaxGamePadSpeed = maxspeed;
    m_Robots.MaxGamePadTurningRate = maxturningrate;

}

void MT_RobotFrameBase::writeUserXML()
{
    MT_WriteRobotXML(&m_Robots,
                  m_Robots.MaxGamePadSpeed,
                  m_Robots.MaxGamePadTurningRate,
                  &m_XMLSettingsFile,
                  false);
    MT_TrackerFrameBase::writeUserXML();
}

void MT_RobotFrameBase::initUserData()
{
    MT_RobotFrameBase::initRobotFrameData();
    MT_TrackerFrameBase::initUserData();
}

void MT_RobotFrameBase::initRobotFrameData()
{
    m_pJoyStickFrame = new MT_JoyStickFrame(this, &m_Robots);
}

void MT_RobotFrameBase::createUserMenus(wxMenuBar* menubar)
{
    wxMenu* robot_menu = new wxMenu;
    makeRobotMenu(robot_menu);
    menubar->Append(robot_menu, wxT("Robots"));

    /* adds tracker menu */
    MT_TrackerFrameBase::createUserMenus(menubar);
}

void MT_RobotFrameBase::makeRobotMenu(wxMenu* robot_menu)
{
    robot_menu->Append(MT_RFB_ID_MENU_ROBOTS_CONNECT, wxT("&Connections..."));
    Connect(MT_RFB_ID_MENU_ROBOTS_CONNECT,
            wxEVT_COMMAND_MENU_SELECTED,
            wxCommandEventHandler(MT_RobotFrameBase::onMenuRobotsConnect));
    robot_menu->Append(MT_RFB_ID_MENU_ROBOTS_JOYSTICK, wxT("&Joystick Control..."));
    Connect(MT_RFB_ID_MENU_ROBOTS_JOYSTICK,
            wxEVT_COMMAND_MENU_SELECTED,
            wxCommandEventHandler(MT_RobotFrameBase::onMenuRobotsJoystick));
    robot_menu->Append(MT_RFB_ID_MENU_ROBOTS_COMMAND, wxT("&Send Command..."));
    Connect(MT_RFB_ID_MENU_ROBOTS_COMMAND,
            wxEVT_COMMAND_MENU_SELECTED,
            wxCommandEventHandler(MT_RobotFrameBase::onMenuRobotsCommand));
}

MT_ControlFrameBase* MT_RobotFrameBase::createControlDialog()
{
    m_pRobotControlFrame = new MT_RobotControlFrameBase(this);
    m_pTrackerControlFrame = (MT_TrackerControlFrameBase *) m_pRobotControlFrame;
    return (MT_ControlFrameBase*) m_pRobotControlFrame;
}

void MT_RobotFrameBase::doUserTimedEvents()
{

}

void MT_RobotFrameBase::doUserStep()
{
    /* do tracking first, then control */
    MT_TrackerFrameBase::doUserStep();

    if(m_bAutoIdentify)
    {
        doAutoIdentify();
    }

    updateRobotStatesFromTracker();

    doControl();
}

void MT_RobotFrameBase::updateRobotStatesFromTracker()
{
    int ti;
    for(unsigned int i = 0; i < MT_MAX_NROBOTS; i++)
    {
        ti = m_Robots.TrackingIndex[i];
        if(ti != MT_NOT_TRACKED)
        {
            m_Robots.UpdateState(i,
                                 m_pTrackedObjects->getX(ti),
                                 m_pTrackedObjects->getY(ti),
                                 m_pTrackedObjects->getOrientation(ti));
        }
    }
}

void MT_RobotFrameBase::doControl()
{
    doUserControl();
}

bool MT_RobotFrameBase::startTracking()
{
    bool now_tracking = MT_TrackerFrameBase::startTracking();

    if(now_tracking && m_pTracker)
    {
        /* grab the tracked objects from the tracker */
        m_pTrackedObjects = m_pTracker->getTrackedObjects();
    }

    return now_tracking;
}

bool MT_RobotFrameBase::toggleAutoIdentify()
{

    // it only makes sense to do any of this if the tracker is up and running
    if(getIsTracking())
    {

        // toggle the value of the auto id flag
        if(m_bAutoIdentify)
        {
            m_bAutoIdentify = false;
            // stop the auto-id process
            doAutoIdentify(false);
        }
        else
        {
            m_bAutoIdentify = true;
            m_bRobotsIdentified = false;
        }

    }

    return m_bAutoIdentify;

}

void MT_RobotFrameBase::doAutoIdentify(bool DoAutoID)
{

    /* we'll want to know if this has changed */
    static int RobotToID = MT_NONE_AVAILABLE;

    /* if we're flagged to stop, then stop whichever robot may be moving for autoID */
    if(!DoAutoID)
    {
        if(RobotToID != MT_NONE_AVAILABLE)
        {
            m_Robots.GetRobot(RobotToID)->SetSpeedOmega(0,0);
        }
        RobotToID = MT_NONE_AVAILABLE;
        return;
    }

    /* first, make sure there's a robot to identify */
    int newRobotToID = m_Robots.GetNextUntracked();

    if(newRobotToID == MT_NONE_AVAILABLE)
    {
        /* none available! */
        RobotToID = MT_NONE_AVAILABLE;
        m_bRobotsIdentified = true;
        m_bAutoIdentify = false;
        /* change the label on the control frame  */
        m_pRobotControlFrame->onAutoIDToggle(false);
        return;
    }

    /* if the robots have been previously identified, reset the IDs */
    if(m_bRobotsIdentified)
    {
        m_Robots.ClearTrackingIDs();
    }

    /* OK, now we've got a robot to identify
       if it's new, we want to start it moving slowly */
    if(newRobotToID != RobotToID)
    {
        /* remember which robot for next time */
        RobotToID = newRobotToID;
        /* start it moving */
        m_Robots.GetRobot(RobotToID)->SetSpeedOmega(0.1,0);
    }

    /* loop through tracked objects (until match is found) */
    for(unsigned int i = 0; i < m_pTrackedObjects->getNumObjects(); i++)
    {
        /* if this TO has been in 5 or more frames and not attached to a robot
           and is moving */
        if( (m_pTrackedObjects->getNumConsecutiveFrames(i) > 5) &&
            (m_pTrackedObjects->getRobotIndex(i) == MT_NO_ROBOT) &&
            (m_pTrackedObjects->getIsMoving(i)) )
        {
            /* stop the robot */
            m_Robots.GetRobot(RobotToID)->SetSpeedOmega(0,0);
            /* attach the current robot */
            m_pTrackedObjects->setRobotIndex(i, RobotToID);
            /* assign the TO ID to the robot */
            m_Robots.TrackingIndex[RobotToID] = i;
        }
    }

}

void MT_RobotFrameBase::doUserQuit()
{
    MT_TrackerFrameBase::doUserQuit();
}

void MT_RobotFrameBase::doUserGLDrawing()
{
    MT_TrackerFrameBase::doUserGLDrawing();
}

MT_RobotControlFrameBase::MT_RobotControlFrameBase(MT_RobotFrameBase* parent,
                                                   const int Buttons,
                                                   const wxPoint& pos,
                                                   const wxSize& size)
  : MT_TrackerControlFrameBase(parent, Buttons, pos, size)
{
    m_pParentRobotFrame = parent;
}

void MT_RobotControlFrameBase::doMasterInitialization()
{
    MT_TrackerControlFrameBase::doMasterInitialization();
}

unsigned int MT_RobotControlFrameBase::createButtons(wxBoxSizer* pSizer, wxPanel* pPanel)
{
    unsigned int nbuttons = MT_TrackerControlFrameBase::createButtons(pSizer, pPanel);

    if(getButtons() & MT_RCF_AUTOID)
    {
        m_pButtonAutoIdentify = new wxButton(pPanel,
                                             MT_RCF_ID_BUTTON_AUTOIDENTIFY,
                                             wxT("AutoID Robots"));
        pSizer->Add(m_pButtonAutoIdentify, 0, wxALL | wxCENTER, 10);
        m_pButtonAutoIdentify->Disable();
        Connect(MT_RCF_ID_BUTTON_AUTOIDENTIFY,
                wxEVT_COMMAND_BUTTON_CLICKED,
                wxCommandEventHandler(
                    MT_RobotControlFrameBase::onButtonAutoIdentifyPressed));
        nbuttons++;
    }
    return nbuttons;
}

void MT_RobotControlFrameBase::onButtonAutoIdentifyPressed(wxCommandEvent& WXUNUSED(event))
{
    onAutoIDToggle(m_pParentRobotFrame->toggleAutoIdentify());
}

void MT_RobotControlFrameBase::onAutoIDToggle(bool AutoID)
{

    if(AutoID == false)
    {
        m_pButtonAutoIdentify->SetLabel(wxT("Reset Auto Identify"));
    }
    else
    {
        m_pButtonAutoIdentify->SetLabel(wxT("Stop Auto Identify"));
    }

}

void MT_RobotControlFrameBase::onTrackingToggle(bool tracking)
{

    MT_TrackerControlFrameBase::onTrackingToggle(tracking);

    if(m_pButtonAutoIdentify)
    {
        if(tracking)
        {
            m_pButtonAutoIdentify->Enable();
        }
        else
        {
            m_pButtonAutoIdentify->Disable();
        }
    }

}

void MT_RobotControlFrameBase::enableButtons()
{
    if(m_pButtonAutoIdentify)
    {
        m_pButtonAutoIdentify->Enable();
    }
    MT_TrackerControlFrameBase::enableButtons();
}
<commit_msg>[MT_Robot] Removed automatic controller connect dialog<commit_after>/*
 *  MT_RobotFrameBase.cpp
 *
 *  Created by Daniel Swain on 1/4/10.
 *
 */

#include "MT_RobotFrameBase.h"

MT_RobotFrameBase::MT_RobotFrameBase(wxFrame* parent,
                                     wxWindowID id,
                                     const wxString& title,
                                     const wxPoint& pos,
                                     const wxSize& size,
                                     long style)
  : MT_TrackerFrameBase(parent, id, title, pos, size, style),
    m_pRobotControlFrame(NULL),
    m_pJoyStickFrame(NULL),
    m_bAutoIdentify(false),
    m_bRobotsIdentified(false),
    m_Robots(),
    m_pTrackedObjects(NULL)
{
}

MT_RobotFrameBase::~MT_RobotFrameBase()
{

}

void MT_RobotFrameBase::handleCommandLineArguments(int argc, wxChar** argv)
{
    MT_TrackerFrameBase::handleCommandLineArguments(argc, argv);
}

void MT_RobotFrameBase::handleOpenWithFile(const wxString& filename)
{
    MT_TrackerFrameBase::handleOpenWithFile(filename);
}

bool MT_RobotFrameBase::doKeyboardCallback(wxKeyEvent& event)
{
    bool tresult = MT_TrackerFrameBase::doKeyboardCallback(event);
    return tresult && MT_DO_BASE_KEY;
}

bool MT_RobotFrameBase::doMouseCallback(wxMouseEvent& event, double viewport_x, double viewport_y)
{
    bool tresult = MT_TrackerFrameBase::doMouseCallback(event, viewport_x, viewport_y);
    return tresult && MT_DO_BASE_MOUSE;
}

void MT_RobotFrameBase::onMenuRobotsConnect(wxCommandEvent& event)
{
    MT_RobotConnectDialog* dlg = new MT_RobotConnectDialog(&m_Robots, this);
    registerDialogForXML(dlg);
    dlg->Show(true);
}

void MT_RobotFrameBase::onMenuRobotsJoystick(wxCommandEvent& event)
{
    m_pJoyStickFrame->Show(true);
    registerDialogForXML(m_pJoyStickFrame);
    m_pJoyStickFrame->EnableEvents();
}

void MT_RobotFrameBase::onMenuRobotsCommand(wxCommandEvent& event)
{
    MT_RobotCommandDialog* dlg = new MT_RobotCommandDialog(&m_Robots, this);
    registerDialogForXML(dlg);
    dlg->Show(true);
}

void MT_RobotFrameBase::readUserXML()
{
    MT_TrackerFrameBase::readUserXML();

    float maxspeed = MT_DEFAULT_MAX_SPEED;
    float maxturningrate = MT_DEFAULT_MAX_TURNING_RATE;
    MT_ReadRobotXML(&m_Robots, &maxspeed, &maxturningrate, &m_XMLSettingsFile, false);
    m_Robots.MaxGamePadSpeed = maxspeed;
    m_Robots.MaxGamePadTurningRate = maxturningrate;

}

void MT_RobotFrameBase::writeUserXML()
{
    MT_WriteRobotXML(&m_Robots,
                  m_Robots.MaxGamePadSpeed,
                  m_Robots.MaxGamePadTurningRate,
                  &m_XMLSettingsFile,
                  false);
    MT_TrackerFrameBase::writeUserXML();
}

void MT_RobotFrameBase::initUserData()
{
    MT_RobotFrameBase::initRobotFrameData();
    MT_TrackerFrameBase::initUserData();
}

void MT_RobotFrameBase::initRobotFrameData()
{
    m_pJoyStickFrame = new MT_JoyStickFrame(this, &m_Robots);
}

void MT_RobotFrameBase::createUserMenus(wxMenuBar* menubar)
{
    wxMenu* robot_menu = new wxMenu;
    makeRobotMenu(robot_menu);
    menubar->Append(robot_menu, wxT("Robots"));

    /* adds tracker menu */
    MT_TrackerFrameBase::createUserMenus(menubar);
}

void MT_RobotFrameBase::makeRobotMenu(wxMenu* robot_menu)
{
    robot_menu->Append(MT_RFB_ID_MENU_ROBOTS_CONNECT, wxT("&Connections..."));
    Connect(MT_RFB_ID_MENU_ROBOTS_CONNECT,
            wxEVT_COMMAND_MENU_SELECTED,
            wxCommandEventHandler(MT_RobotFrameBase::onMenuRobotsConnect));
    robot_menu->Append(MT_RFB_ID_MENU_ROBOTS_JOYSTICK, wxT("&Joystick Control..."));
    Connect(MT_RFB_ID_MENU_ROBOTS_JOYSTICK,
            wxEVT_COMMAND_MENU_SELECTED,
            wxCommandEventHandler(MT_RobotFrameBase::onMenuRobotsJoystick));
    robot_menu->Append(MT_RFB_ID_MENU_ROBOTS_COMMAND, wxT("&Send Command..."));
    Connect(MT_RFB_ID_MENU_ROBOTS_COMMAND,
            wxEVT_COMMAND_MENU_SELECTED,
            wxCommandEventHandler(MT_RobotFrameBase::onMenuRobotsCommand));
}

MT_ControlFrameBase* MT_RobotFrameBase::createControlDialog()
{
    m_pRobotControlFrame = new MT_RobotControlFrameBase(this);
    m_pTrackerControlFrame = (MT_TrackerControlFrameBase *) m_pRobotControlFrame;
    return (MT_ControlFrameBase*) m_pRobotControlFrame;
}

void MT_RobotFrameBase::doUserTimedEvents()
{

}

void MT_RobotFrameBase::doUserStep()
{
    /* do tracking first, then control */
    MT_TrackerFrameBase::doUserStep();

    if(m_bAutoIdentify)
    {
        doAutoIdentify();
    }

    updateRobotStatesFromTracker();

    doControl();
}

void MT_RobotFrameBase::updateRobotStatesFromTracker()
{
    int ti;
    for(unsigned int i = 0; i < MT_MAX_NROBOTS; i++)
    {
        ti = m_Robots.TrackingIndex[i];
        if(ti != MT_NOT_TRACKED)
        {
            m_Robots.UpdateState(i,
                                 m_pTrackedObjects->getX(ti),
                                 m_pTrackedObjects->getY(ti),
                                 m_pTrackedObjects->getOrientation(ti));
        }
    }
}

void MT_RobotFrameBase::doControl()
{
    doUserControl();
}

bool MT_RobotFrameBase::startTracking()
{
    bool now_tracking = MT_TrackerFrameBase::startTracking();

    if(now_tracking && m_pTracker)
    {
        /* grab the tracked objects from the tracker */
        m_pTrackedObjects = m_pTracker->getTrackedObjects();
    }

    return now_tracking;
}

bool MT_RobotFrameBase::toggleAutoIdentify()
{

    // it only makes sense to do any of this if the tracker is up and running
    if(getIsTracking())
    {

        // toggle the value of the auto id flag
        if(m_bAutoIdentify)
        {
            m_bAutoIdentify = false;
            // stop the auto-id process
            doAutoIdentify(false);
        }
        else
        {
            m_bAutoIdentify = true;
            m_bRobotsIdentified = false;
        }

    }

    return m_bAutoIdentify;

}

void MT_RobotFrameBase::doAutoIdentify(bool DoAutoID)
{

    /* we'll want to know if this has changed */
    static int RobotToID = MT_NONE_AVAILABLE;

    /* if we're flagged to stop, then stop whichever robot may be moving for autoID */
    if(!DoAutoID)
    {
        if(RobotToID != MT_NONE_AVAILABLE)
        {
            m_Robots.GetRobot(RobotToID)->SetSpeedOmega(0,0);
        }
        RobotToID = MT_NONE_AVAILABLE;
        return;
    }

    /* first, make sure there's a robot to identify */
    int newRobotToID = m_Robots.GetNextUntracked();

    if(newRobotToID == MT_NONE_AVAILABLE)
    {
        /* none available! */
        RobotToID = MT_NONE_AVAILABLE;
        m_bRobotsIdentified = true;
        m_bAutoIdentify = false;
        /* change the label on the control frame  */
        m_pRobotControlFrame->onAutoIDToggle(false);
        return;
    }

    /* if the robots have been previously identified, reset the IDs */
    if(m_bRobotsIdentified)
    {
        m_Robots.ClearTrackingIDs();
    }

    /* OK, now we've got a robot to identify
       if it's new, we want to start it moving slowly */
    if(newRobotToID != RobotToID)
    {
        /* remember which robot for next time */
        RobotToID = newRobotToID;
        /* start it moving */
        m_Robots.GetRobot(RobotToID)->SetSpeedOmega(0.1,0);
    }

    /* loop through tracked objects (until match is found) */
    for(unsigned int i = 0; i < m_pTrackedObjects->getNumObjects(); i++)
    {
        /* if this TO has been in 5 or more frames and not attached to a robot
           and is moving */
        if( (m_pTrackedObjects->getNumConsecutiveFrames(i) > 5) &&
            (m_pTrackedObjects->getRobotIndex(i) == MT_NO_ROBOT) &&
            (m_pTrackedObjects->getIsMoving(i)) )
        {
            /* stop the robot */
            m_Robots.GetRobot(RobotToID)->SetSpeedOmega(0,0);
            /* attach the current robot */
            m_pTrackedObjects->setRobotIndex(i, RobotToID);
            /* assign the TO ID to the robot */
            m_Robots.TrackingIndex[RobotToID] = i;
        }
    }

}

void MT_RobotFrameBase::doUserQuit()
{
    MT_TrackerFrameBase::doUserQuit();
}

void MT_RobotFrameBase::doUserGLDrawing()
{
    MT_TrackerFrameBase::doUserGLDrawing();
}

MT_RobotControlFrameBase::MT_RobotControlFrameBase(MT_RobotFrameBase* parent,
                                                   const int Buttons,
                                                   const wxPoint& pos,
                                                   const wxSize& size)
  : MT_TrackerControlFrameBase(parent, Buttons, pos, size)
{
    m_pParentRobotFrame = parent;
}

void MT_RobotControlFrameBase::doMasterInitialization()
{
    MT_TrackerControlFrameBase::doMasterInitialization();
}

unsigned int MT_RobotControlFrameBase::createButtons(wxBoxSizer* pSizer, wxPanel* pPanel)
{
    unsigned int nbuttons = MT_TrackerControlFrameBase::createButtons(pSizer, pPanel);

    if(getButtons() & MT_RCF_AUTOID)
    {
        m_pButtonAutoIdentify = new wxButton(pPanel,
                                             MT_RCF_ID_BUTTON_AUTOIDENTIFY,
                                             wxT("AutoID Robots"));
        pSizer->Add(m_pButtonAutoIdentify, 0, wxALL | wxCENTER, 10);
        m_pButtonAutoIdentify->Disable();
        Connect(MT_RCF_ID_BUTTON_AUTOIDENTIFY,
                wxEVT_COMMAND_BUTTON_CLICKED,
                wxCommandEventHandler(
                    MT_RobotControlFrameBase::onButtonAutoIdentifyPressed));
        nbuttons++;
    }
    return nbuttons;
}

void MT_RobotControlFrameBase::onButtonAutoIdentifyPressed(wxCommandEvent& WXUNUSED(event))
{
    onAutoIDToggle(m_pParentRobotFrame->toggleAutoIdentify());
}

void MT_RobotControlFrameBase::onAutoIDToggle(bool AutoID)
{

    if(AutoID == false)
    {
        m_pButtonAutoIdentify->SetLabel(wxT("Reset Auto Identify"));
    }
    else
    {
        m_pButtonAutoIdentify->SetLabel(wxT("Stop Auto Identify"));
    }

}

void MT_RobotControlFrameBase::onTrackingToggle(bool tracking)
{

    MT_TrackerControlFrameBase::onTrackingToggle(tracking);

    if(m_pButtonAutoIdentify)
    {
        if(tracking)
        {
            m_pButtonAutoIdentify->Enable();
        }
        else
        {
            m_pButtonAutoIdentify->Disable();
        }
    }

}

void MT_RobotControlFrameBase::enableButtons()
{
    if(m_pButtonAutoIdentify)
    {
        m_pButtonAutoIdentify->Enable();
    }
    MT_TrackerControlFrameBase::enableButtons();
}
<|endoftext|>


<commit_before>// @@@LICENSE
//
//      Copyright (c) 2009-2012 Hewlett-Packard Development Company, L.P.
//
// 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.
//
// LICENSE@@@

#include "core/MojObject.h"
#include "ActivityConfigurator.h"
#include "BusClient.h"
#include "core/MojServiceMessage.h"

#include <string.h>

using namespace std;

const char* const ActivityConfigurator::ACTIVITYMGR_BUS_ADDRESS   = "com.palm.activitymanager";
const char* const ActivityConfigurator::ACTIVITYMGR_CREATE_METHOD = "create";
const char* const ActivityConfigurator::ACTIVITYMGR_REMOVE_METHOD = "cancel";
const char* const ActivityConfigurator::ACTIVITY				  = "activity";
const char* const ActivityConfigurator::CREATOR					  = "creator";
const char* const ActivityConfigurator::APPLICATION_ID				  = "appId";
const char* const ActivityConfigurator::SERVICE_ID				  = "serviceId";
const char* const ActivityConfigurator::NAME		  = "name";
const char* const ActivityConfigurator::ACTIVITY_NAME		  = "activityName";
const char* const ActivityConfigurator::FIRST_USE_SAFE		  = "firstUseSafe";
const char* const ActivityConfigurator::APP_DIR		  = "/etc/palm/activities/applications/";
const char* const ActivityConfigurator::SERVICE_DIR		  = "/etc/palm/activities/services/";
const char* const ActivityConfigurator::FIRST_USE_FLAG    = "/var/luna/preferences/ran-first-use";
const char* const ActivityConfigurator::FIRST_USE_PROFILE_FLAG = "/var/luna/preferences/first-use-profile-created";

class ActivityConfigureResponse : public ConfiguratorCallback {
public:
	ActivityConfigureResponse(ActivityConfigurator *conf, const string& path)
		: ConfiguratorCallback(conf, path)
	{
	}

	~ActivityConfigureResponse()
	{
	}

	MojErr Response(MojObject& response, MojErr err)
	{
		bool success = true;
		response.get("returnValue", success);

		if (err || !success) {
			MojInt64 errorCode;
			if (response.get("errorCode", errorCode)) {
				if (errorCode == MojErrExists) {
					MojLogInfo(Logger(), "caching ok negative response for %s", m_config.c_str());
					bool found = false;
					response.del("errorCode", found);
					response.del("errorText", found);
					err = response.putBool("returnValue", true);
					MarkConfigured();
				} else {
					MojLogWarning(Logger(), "Unrecognized errorCode %d", (int)errorCode);
				}
			} else {
				MojLogWarning(Logger(), "errorCode not provided in request failure");
			}
		}
		return DelegateResponse(response, err);
	}
};

const char* ActivityConfigurator::ConfiguratorName() const
{
	 return "ActivityConfigurator";
}

const char* ActivityConfigurator::ServiceName() const
{
	return ACTIVITYMGR_BUS_ADDRESS;
}

ConfiguratorCallback* ActivityConfigurator::CreateCallback(const std::string &filePath)
{
	return new ActivityConfigureResponse(this, filePath);
}

ActivityConfigurator::ActivityConfigurator(const std::string& id, ConfigType confType, RunType type, BusClient& busClient, string configDirectory)
	: Configurator(id, confType, type, busClient, configDirectory),
	  m_firstUseOnly(true)
{
	int err;
	struct stat buf;
	err = stat(FIRST_USE_FLAG, &buf);
	if (err == 0) {
		err = stat(FIRST_USE_PROFILE_FLAG, &buf);
		if (err == 0) {
			MojLogInfo(m_log, "Fist Use has completed, installing all "
				"Activities");
			m_firstUseOnly = false;
		}
	}
}

ActivityConfigurator::~ActivityConfigurator()
{

}

bool ActivityConfigurator::CanCacheConfiguratorStatus(const std::string&) const
{
	MojLogTrace(m_log);
	return false;
}

static void RemoveKey(MojObject& object, const MojChar *key)
{
	bool keydeleted;
	object.del(key, keydeleted);
}

static bool StartsWith(const std::string& s1, const std::string& prefix)
{
	return prefix.length() <= s1.length() && memcmp(s1.c_str(), prefix.c_str(), prefix.length()) == 0;
}

MojErr ActivityConfigurator::ProcessConfig(const string& filePath, MojObject& params)
{
	MojLogTrace(m_log);

	const std::string& creator = ParentId(filePath);

	if (creator.empty()) {
		MojLogError(m_log, "Service id for activity '%s' is empty - needs to be in an appropriate subdirectory or given as part of the service call", filePath.c_str());
		return MojErrInvalidArg;
	}

	if (m_firstUseOnly) {
		bool firstUseSafe;
		if (!params.get(FIRST_USE_SAFE, firstUseSafe) || !firstUseSafe) {
			MojLogDebug(m_log, "Running before first use but activity %s not marked as safe for configuration at this time", filePath.c_str());
			return MojErrInProgress;
		}
	}

	MojLogDebug(m_log, "ActivityConfigurator creator for %s is %s\n", filePath.c_str(), creator.c_str());

	MojObject activity;
	MojErr err;
	err = params.getRequired(ACTIVITY, activity);
	MojErrCheck(err);

	ConfigType confType;

	if (m_confType == ConfigUnknown) {
		if (StartsWith(filePath, APP_DIR)) {
			confType = ConfigApplication;
		} else {
			if (!StartsWith(filePath, SERVICE_DIR)) {
				//Fix for DFISH-14510 turn down logging here
				//MojLogWarning(m_log, "Deprecated usage: %s not in application or service subdirectory as required - assumed to be service", filePath.c_str());
			}
			confType = ConfigService;
		}
	} else {
		confType = m_confType;
	}

	MojObject creatorObj;
	switch (confType) {
	case ConfigApplication:
		err = creatorObj.putString(APPLICATION_ID, creator.c_str());
		break;
	case ConfigService:
		err = creatorObj.putString(SERVICE_ID, creator.c_str());
		break;
	case ConfigUnknown:
		// impossible case
		assert(false);
		break;
	}

	MojErrCheck(err);

	err = activity.put(CREATOR, creatorObj);
	MojErrCheck(err);
	err = params.put(ACTIVITY, activity);
	MojErrCheck(err);

	// strip configurator-specific keys
	// so that the schema on activity manager isn't violated
	RemoveKey(params, FIRST_USE_SAFE);

	return m_busClient.CreateRequest()->send(CreateCallback(filePath)->m_slot, ServiceName(), ACTIVITYMGR_CREATE_METHOD, params);
}

MojErr ActivityConfigurator::ProcessConfigRemoval(const string& filePath, MojObject& params)
{
	MojLogTrace(m_log);
	MojErr err;

	MojObject activity;
	MojString activityName;

	err = params.getRequired(ACTIVITY, activity); MojErrCheck(err);
	err = activity.getRequired(NAME, activityName); MojErrCheck(err);

	MojObject request(MojObject::TypeObject);
	const std::string& creator = ParentId(filePath);

	if (creator.empty()) {
		MojLogError(m_log, "Service id for activity '%s' is empty - needs to be in an appropriate subdirectory or given as part of the service call", filePath.c_str());
		return MojErrInvalidArg;
	}

	// {"activityName": "..."}
	err = request.putString(ACTIVITY_NAME, activityName); MojErrCheck(err);
	// {"activityName": "...", "creator": "..."}
	err = request.putString(CREATOR, creator.c_str()); MojErrCheck(err);

	return m_busClient.CreateRequest()->send(CreateCallback(filePath)->m_slot, ServiceName(), ACTIVITYMGR_REMOVE_METHOD, request);
}
<commit_msg>Disable the FirstUse run check.<commit_after>// @@@LICENSE
//
//      Copyright (c) 2009-2012 Hewlett-Packard Development Company, L.P.
//
// 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.
//
// LICENSE@@@

#include "core/MojObject.h"
#include "ActivityConfigurator.h"
#include "BusClient.h"
#include "core/MojServiceMessage.h"

#include <string.h>

using namespace std;

const char* const ActivityConfigurator::ACTIVITYMGR_BUS_ADDRESS   = "com.palm.activitymanager";
const char* const ActivityConfigurator::ACTIVITYMGR_CREATE_METHOD = "create";
const char* const ActivityConfigurator::ACTIVITYMGR_REMOVE_METHOD = "cancel";
const char* const ActivityConfigurator::ACTIVITY				  = "activity";
const char* const ActivityConfigurator::CREATOR					  = "creator";
const char* const ActivityConfigurator::APPLICATION_ID				  = "appId";
const char* const ActivityConfigurator::SERVICE_ID				  = "serviceId";
const char* const ActivityConfigurator::NAME		  = "name";
const char* const ActivityConfigurator::ACTIVITY_NAME		  = "activityName";
const char* const ActivityConfigurator::FIRST_USE_SAFE		  = "firstUseSafe";
const char* const ActivityConfigurator::APP_DIR		  = "/etc/palm/activities/applications/";
const char* const ActivityConfigurator::SERVICE_DIR		  = "/etc/palm/activities/services/";
const char* const ActivityConfigurator::FIRST_USE_FLAG    = "/var/luna/preferences/ran-first-use";
const char* const ActivityConfigurator::FIRST_USE_PROFILE_FLAG = "/var/luna/preferences/first-use-profile-created";

class ActivityConfigureResponse : public ConfiguratorCallback {
public:
	ActivityConfigureResponse(ActivityConfigurator *conf, const string& path)
		: ConfiguratorCallback(conf, path)
	{
	}

	~ActivityConfigureResponse()
	{
	}

	MojErr Response(MojObject& response, MojErr err)
	{
		bool success = true;
		response.get("returnValue", success);

		if (err || !success) {
			MojInt64 errorCode;
			if (response.get("errorCode", errorCode)) {
				if (errorCode == MojErrExists) {
					MojLogInfo(Logger(), "caching ok negative response for %s", m_config.c_str());
					bool found = false;
					response.del("errorCode", found);
					response.del("errorText", found);
					err = response.putBool("returnValue", true);
					MarkConfigured();
				} else {
					MojLogWarning(Logger(), "Unrecognized errorCode %d", (int)errorCode);
				}
			} else {
				MojLogWarning(Logger(), "errorCode not provided in request failure");
			}
		}
		return DelegateResponse(response, err);
	}
};

const char* ActivityConfigurator::ConfiguratorName() const
{
	 return "ActivityConfigurator";
}

const char* ActivityConfigurator::ServiceName() const
{
	return ACTIVITYMGR_BUS_ADDRESS;
}

ConfiguratorCallback* ActivityConfigurator::CreateCallback(const std::string &filePath)
{
	return new ActivityConfigureResponse(this, filePath);
}

ActivityConfigurator::ActivityConfigurator(const std::string& id, ConfigType confType, RunType type, BusClient& busClient, string configDirectory)
	: Configurator(id, confType, type, busClient, configDirectory),
	  m_firstUseOnly(true)
{
	int err;
	struct stat buf;
	err = stat(FIRST_USE_FLAG, &buf);
	if (err == 0) {
		err = stat(FIRST_USE_PROFILE_FLAG, &buf);
		if (err == 0) {
			MojLogInfo(m_log, "Fist Use has completed, installing all "
				"Activities");
			m_firstUseOnly = false;
		}
	}
#ifdef WEBOS_TARGET_MACHINE_STANDALONE
	//Set the m_firstUseOnly flag to false as there is no first use run in Desktop.
 	m_firstUseOnly = false;
#endif
}

ActivityConfigurator::~ActivityConfigurator()
{

}

bool ActivityConfigurator::CanCacheConfiguratorStatus(const std::string&) const
{
	MojLogTrace(m_log);
	return false;
}

static void RemoveKey(MojObject& object, const MojChar *key)
{
	bool keydeleted;
	object.del(key, keydeleted);
}

static bool StartsWith(const std::string& s1, const std::string& prefix)
{
	return prefix.length() <= s1.length() && memcmp(s1.c_str(), prefix.c_str(), prefix.length()) == 0;
}

MojErr ActivityConfigurator::ProcessConfig(const string& filePath, MojObject& params)
{
	MojLogTrace(m_log);

	const std::string& creator = ParentId(filePath);

	if (creator.empty()) {
		MojLogError(m_log, "Service id for activity '%s' is empty - needs to be in an appropriate subdirectory or given as part of the service call", filePath.c_str());
		return MojErrInvalidArg;
	}

	if (m_firstUseOnly) {
		bool firstUseSafe;
		if (!params.get(FIRST_USE_SAFE, firstUseSafe) || !firstUseSafe) {
			MojLogDebug(m_log, "Running before first use but activity %s not marked as safe for configuration at this time", filePath.c_str());
			return MojErrInProgress;
		}
	}

	MojLogDebug(m_log, "ActivityConfigurator creator for %s is %s\n", filePath.c_str(), creator.c_str());

	MojObject activity;
	MojErr err;
	err = params.getRequired(ACTIVITY, activity);
	MojErrCheck(err);

	ConfigType confType;

	if (m_confType == ConfigUnknown) {
		if (StartsWith(filePath, APP_DIR)) {
			confType = ConfigApplication;
		} else {
			if (!StartsWith(filePath, SERVICE_DIR)) {
				//Fix for DFISH-14510 turn down logging here
				//MojLogWarning(m_log, "Deprecated usage: %s not in application or service subdirectory as required - assumed to be service", filePath.c_str());
			}
			confType = ConfigService;
		}
	} else {
		confType = m_confType;
	}

	MojObject creatorObj;
	switch (confType) {
	case ConfigApplication:
		err = creatorObj.putString(APPLICATION_ID, creator.c_str());
		break;
	case ConfigService:
		err = creatorObj.putString(SERVICE_ID, creator.c_str());
		break;
	case ConfigUnknown:
		// impossible case
		assert(false);
		break;
	}

	MojErrCheck(err);

	err = activity.put(CREATOR, creatorObj);
	MojErrCheck(err);
	err = params.put(ACTIVITY, activity);
	MojErrCheck(err);

	// strip configurator-specific keys
	// so that the schema on activity manager isn't violated
	RemoveKey(params, FIRST_USE_SAFE);

	return m_busClient.CreateRequest()->send(CreateCallback(filePath)->m_slot, ServiceName(), ACTIVITYMGR_CREATE_METHOD, params);
}

MojErr ActivityConfigurator::ProcessConfigRemoval(const string& filePath, MojObject& params)
{
	MojLogTrace(m_log);
	MojErr err;

	MojObject activity;
	MojString activityName;

	err = params.getRequired(ACTIVITY, activity); MojErrCheck(err);
	err = activity.getRequired(NAME, activityName); MojErrCheck(err);

	MojObject request(MojObject::TypeObject);
	const std::string& creator = ParentId(filePath);

	if (creator.empty()) {
		MojLogError(m_log, "Service id for activity '%s' is empty - needs to be in an appropriate subdirectory or given as part of the service call", filePath.c_str());
		return MojErrInvalidArg;
	}

	// {"activityName": "..."}
	err = request.putString(ACTIVITY_NAME, activityName); MojErrCheck(err);
	// {"activityName": "...", "creator": "..."}
	err = request.putString(CREATOR, creator.c_str()); MojErrCheck(err);

	return m_busClient.CreateRequest()->send(CreateCallback(filePath)->m_slot, ServiceName(), ACTIVITYMGR_REMOVE_METHOD, request);
}
<|endoftext|>


<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2011-2012.
// 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)
//=======================================================================

#include <boost/range/adaptors.hpp>

#include "GlobalContext.hpp"
#include "FunctionContext.hpp"
#include "Type.hpp"
#include "Variable.hpp"

#include "ltac/prologue.hpp"
#include "ltac/Utils.hpp"
#include "ltac/Printer.hpp"

using namespace eddic;

namespace {

std::set<ltac::Register> parameter_registers(std::shared_ptr<eddic::Function> function, Platform platform, std::shared_ptr<Configuration> configuration){
    std::set<ltac::Register> overriden_registers;

    auto descriptor = getPlatformDescriptor(platform);

    if(function->standard || configuration->option_defined("fparameter-allocation")){
        unsigned int maxInt = descriptor->numberOfIntParamRegisters();

        for(auto& parameter : function->parameters){
            auto type = function->getParameterType(parameter.name);
            unsigned int position = function->getParameterPositionByType(parameter.name);

            if(mtac::is_single_int_register(type) && position <= maxInt){
                overriden_registers.insert(ltac::Register(descriptor->int_param_register(position)));
            }
        }
    }

    return overriden_registers;
}

std::set<ltac::FloatRegister> float_parameter_registers(std::shared_ptr<eddic::Function> function, Platform platform, std::shared_ptr<Configuration> configuration){
    std::set<ltac::FloatRegister> overriden_float_registers;

    auto descriptor = getPlatformDescriptor(platform);

    if(function->standard || configuration->option_defined("fparameter-allocation")){
        unsigned int maxFloat = descriptor->numberOfFloatParamRegisters();

        for(auto& parameter : function->parameters){
            auto type = function->getParameterType(parameter.name);
            unsigned int position = function->getParameterPositionByType(parameter.name);

            if(mtac::is_single_float_register(type) && position <= maxFloat){
                overriden_float_registers.insert(ltac::FloatRegister(descriptor->float_param_register(position)));
            }
        }
    }

    return overriden_float_registers;
}

bool callee_save(std::shared_ptr<eddic::Function> definition, ltac::Register reg, Platform platform, std::shared_ptr<Configuration> configuration){
    auto return_type = definition->returnType;
    auto descriptor = getPlatformDescriptor(platform);

    if((return_type == INT || return_type == BOOL || return_type == CHAR) && reg.reg == descriptor->int_return_register1()){
        return false;
    } else if(return_type == STRING && (reg.reg == descriptor->int_return_register1() || reg.reg == descriptor->int_return_register2())){
        return false;
    } else if(return_type->is_pointer() && reg.reg == descriptor->int_return_register1()){
        return false;
    }

    auto parameters = parameter_registers(definition, platform, configuration);

    if(parameters.count(reg)){
        return false;
    }

    return true;
}

bool callee_save(std::shared_ptr<eddic::Function> definition, ltac::FloatRegister reg, Platform platform, std::shared_ptr<Configuration> configuration){
    auto return_type = definition->returnType;
    auto descriptor = getPlatformDescriptor(platform);

    if(return_type == FLOAT && reg.reg == descriptor->float_return_register()){
        return false;
    }

    auto parameters = float_parameter_registers(definition, platform, configuration);

    if(parameters.count(reg)){
        return false;
    }

    return true;
}

void callee_save_registers(mtac::function_p function, mtac::basic_block_p bb, Platform platform, std::shared_ptr<Configuration> configuration){
    //Save registers for all other functions than main
    if(!function->is_main()){
        for(auto& reg : function->use_registers()){
            if(callee_save(function->definition, reg, platform, configuration)){
                ltac::add_instruction(bb, ltac::Operator::PUSH, reg);
            }
        }

        for(auto& float_reg : function->use_float_registers()){
            if(callee_save(function->definition, float_reg, platform, configuration)){
                ltac::add_instruction(bb, ltac::Operator::SUB, ltac::SP, static_cast<int>(FLOAT->size(platform)));
                ltac::add_instruction(bb, ltac::Operator::FMOV, ltac::Address(ltac::SP, 0), float_reg);
            }
        }
    }
}

void callee_restore_registers(mtac::function_p function, mtac::basic_block_p bb, Platform platform, std::shared_ptr<Configuration> configuration){
    //Save registers for all other functions than main
    if(!function->is_main()){
        for(auto& float_reg : boost::adaptors::reverse(function->use_float_registers())){
            if(callee_save(function->definition, float_reg, platform, configuration)){
                ltac::add_instruction(bb, ltac::Operator::FMOV, float_reg, ltac::Address(ltac::SP, 0));
                ltac::add_instruction(bb, ltac::Operator::ADD, ltac::SP, static_cast<int>(FLOAT->size(platform)));
            }
        }

        for(auto& reg : boost::adaptors::reverse(function->use_registers())){
            if(callee_save(function->definition, reg, platform, configuration)){
                ltac::add_instruction(bb, ltac::Operator::POP, reg);
            }
        }
    }
}

template<typename It>
void callee_restore_registers(mtac::function_p function, It& it, Platform platform, std::shared_ptr<Configuration> configuration){
    //Save registers for all other functions than main
    if(!function->is_main()){
        for(auto& reg : function->use_registers()){
            if(callee_save(function->definition, reg, platform, configuration)){
                it.insert(std::make_shared<ltac::Instruction>(ltac::Operator::POP, reg));
            }
        }

        for(auto& float_reg : function->use_float_registers()){
            if(callee_save(function->definition, float_reg, platform, configuration)){
                it.insert(std::make_shared<ltac::Instruction>(ltac::Operator::ADD, ltac::SP, static_cast<int>(FLOAT->size(platform))));
                it.insert(std::make_shared<ltac::Instruction>(ltac::Operator::FMOV, float_reg, ltac::Address(ltac::SP, 0)));
            }
        }
    }
}

bool caller_save(std::shared_ptr<eddic::Function> target_definition, ltac::Register reg, Platform platform, std::shared_ptr<Configuration> configuration){
    auto parameters = parameter_registers(target_definition, platform, configuration);

    if(parameters.count(reg)){
        return true;
    }

    return false;
}

bool caller_save(std::shared_ptr<eddic::Function> target_definition, ltac::FloatRegister reg, Platform platform, std::shared_ptr<Configuration> configuration){
    auto parameters = float_parameter_registers(target_definition, platform, configuration);

    if(parameters.count(reg)){
        return true;
    }

    return false;
}

template<typename It>
void caller_save_registers(mtac::function_p function, std::shared_ptr<eddic::Function> target_function, mtac::basic_block_p bb, It it, Platform platform, std::shared_ptr<Configuration> configuration){
    auto pre_it = it.it;

    auto call = boost::get<std::shared_ptr<ltac::Jump>>(*it);

    while(true){
        while(pre_it != bb->l_statements.begin()){
            --pre_it;

            auto statement = *pre_it;

            if(auto* ptr = boost::get<std::shared_ptr<ltac::Instruction>>(&statement)){
                if((*ptr)->op == ltac::Operator::PRE_PARAM){
                    (*ptr)->op = ltac::Operator::NOP;

                    for(auto& float_reg : boost::adaptors::reverse(function->use_float_registers())){
                        if(caller_save(target_function, float_reg, platform, configuration)){
                            pre_it = bb->l_statements.insert(pre_it, std::make_shared<ltac::Instruction>(ltac::Operator::FMOV, ltac::Address(ltac::SP, 0), float_reg));
                            pre_it = bb->l_statements.insert(pre_it, std::make_shared<ltac::Instruction>(ltac::Operator::SUB, ltac::SP, static_cast<int>(FLOAT->size(platform))));
                        }
                    }

                    for(auto& reg : boost::adaptors::reverse(function->use_registers())){
                        if(caller_save(target_function, reg, platform, configuration)){
                            pre_it = bb->l_statements.insert(pre_it, std::make_shared<ltac::Instruction>(ltac::Operator::PUSH, reg));
                        }
                    }

                    return;
                }
            }
        }

        bb = bb->prev;
        pre_it = bb->l_statements.end();
    }
}

template<typename It, typename Type>
void find(It& it, const Type& value){
    while(true){
        if(auto* ptr = boost::get<Type>(&*it)){
            if(*ptr == value){
                return;
            }
        }

        ++it;
    }
}

template<typename It>
void caller_cleanup(mtac::function_p function, std::shared_ptr<eddic::Function> target_function, mtac::basic_block_p bb, It it, Platform platform, std::shared_ptr<Configuration> configuration){
    auto call = boost::get<std::shared_ptr<ltac::Jump>>(*it);

    caller_save_registers(function, target_function, bb, it, platform, configuration);

    //The iterator has been invalidated by the save, find the call again
    it.restart();
    find(it, call);

    if(it.has_next()){
        ++it;

        bool rewind = true;

        if(auto* ptr = boost::get<std::shared_ptr<ltac::Instruction>>(&*it)){
            if((*ptr)->op == ltac::Operator::ADD){
                if(auto* reg_ptr = boost::get<ltac::Register>(&*(*ptr)->arg1)){
                    if(*reg_ptr == ltac::SP){
                       rewind = false;
                    }
                }
            }
        }

        if(rewind){
            --it;
        }
    }

    for(auto& float_reg : boost::adaptors::reverse(function->use_float_registers())){
        if(caller_save(target_function, float_reg, platform, configuration)){
            it.insert_after(std::make_shared<ltac::Instruction>(ltac::Operator::FMOV, float_reg, ltac::Address(ltac::SP, 0)));
            it.insert_after(std::make_shared<ltac::Instruction>(ltac::Operator::ADD, ltac::SP, static_cast<int>(FLOAT->size(platform))));
        }
    }

    for(auto& reg : boost::adaptors::reverse(function->use_registers())){
        if(caller_save(target_function, reg, platform, configuration)){
            it.insert_after(std::make_shared<ltac::Instruction>(ltac::Operator::POP, reg));
        }
    }
}

} //End of anonymous

void ltac::generate_prologue_epilogue(mtac::program_p ltac_program, std::shared_ptr<Configuration> configuration){
    bool omit_fp = configuration->option_defined("fomit-frame-pointer");
    auto platform = ltac_program->context->target_platform();

    for(auto& function : ltac_program->functions){
        auto size = function->context->size();

        //1. Generate prologue

        auto bb = function->entry_bb();

        //Enter stack frame
        if(!omit_fp){
            ltac::add_instruction(bb, ltac::Operator::ENTER);
        }

        //Allocate stack space for locals
        ltac::add_instruction(bb, ltac::Operator::SUB, ltac::SP, size);

        auto iter = function->context->begin();
        auto end = function->context->end();

        //Clear stack variables
        for(; iter != end; iter++){
            auto var = iter->second;

            //Only stack variables needs to be cleared
            if(var->position().isStack()){
                auto type = var->type();
                int position = var->position().offset();

                auto int_size = INT->size(platform);

                if(type->is_array() && type->has_elements()){
                    ltac::add_instruction(bb, ltac::Operator::MOV, ltac::Address(ltac::BP, position), static_cast<int>(type->elements()));
                    ltac::add_instruction(bb, ltac::Operator::MEMSET, ltac::Address(ltac::BP, position + int_size),
                            static_cast<int>((type->data_type()->size(platform) / int_size * type->elements())));
                } else if(type->is_custom_type()){
                    ltac::add_instruction(bb, ltac::Operator::MEMSET, ltac::Address(ltac::BP, position), static_cast<int>(type->size(platform) / int_size));
                }
            }
        }

        callee_save_registers(function, bb, platform, configuration);

        //2. Generate epilogue

        bb = function->exit_bb();

        callee_restore_registers(function, bb, platform, configuration);

        ltac::add_instruction(bb, ltac::Operator::ADD, ltac::SP, size);

        //Leave stack frame
        if(!omit_fp){
            ltac::add_instruction(bb, ltac::Operator::LEAVE);
        }

        ltac::add_instruction(bb, ltac::Operator::RET);

        //3. Generate epilogue for each unresolved RET

        for(auto& bb : function){
            auto it = iterate(bb->l_statements);

            while(it.has_next()){
                auto statement = *it;

                if(auto* ptr = boost::get<std::shared_ptr<ltac::Instruction>>(&statement)){
                    if((*ptr)->op == ltac::Operator::PRE_RET){
                        (*ptr)->op = ltac::Operator::RET;

                        //Leave stack frame
                        if(!omit_fp){
                            it.insert(std::make_shared<ltac::Instruction>(ltac::Operator::LEAVE));
                        }

                        it.insert(std::make_shared<ltac::Instruction>(ltac::Operator::ADD, ltac::SP, size));

                        callee_restore_registers(function, it, platform, configuration);
                    }
                }

                ++it;
            }
        }

        //4. Generate caller save/restore code

        for(auto& bb : function){
            auto it = iterate(bb->l_statements);

            while(it.has_next()){
                auto statement = *it;

                if(auto* ptr = boost::get<std::shared_ptr<ltac::Jump>>(&statement)){
                    if((*ptr)->type == ltac::JumpType::CALL){
                        caller_cleanup(function, (*ptr)->target_function, bb, it, platform, configuration);

                        //The iterator is invalidated by the cleanup, necessary to find the call again
                        it.restart();
                        find(it, *ptr);
                    }
                }

                ++it;
            }
        }
    }
}
<commit_msg>Save registers only when necessary<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2011-2012.
// 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)
//=======================================================================

#include <boost/range/adaptors.hpp>

#include "GlobalContext.hpp"
#include "FunctionContext.hpp"
#include "Type.hpp"
#include "Variable.hpp"

#include "ltac/prologue.hpp"
#include "ltac/Utils.hpp"
#include "ltac/Printer.hpp"

using namespace eddic;

namespace {

std::set<ltac::Register> parameter_registers(std::shared_ptr<eddic::Function> function, Platform platform, std::shared_ptr<Configuration> configuration){
    std::set<ltac::Register> overriden_registers;

    auto descriptor = getPlatformDescriptor(platform);

    if(function->standard || configuration->option_defined("fparameter-allocation")){
        unsigned int maxInt = descriptor->numberOfIntParamRegisters();

        for(auto& parameter : function->parameters){
            auto type = function->getParameterType(parameter.name);
            unsigned int position = function->getParameterPositionByType(parameter.name);

            if(mtac::is_single_int_register(type) && position <= maxInt){
                overriden_registers.insert(ltac::Register(descriptor->int_param_register(position)));
            }
        }
    }

    return overriden_registers;
}

std::set<ltac::FloatRegister> float_parameter_registers(std::shared_ptr<eddic::Function> function, Platform platform, std::shared_ptr<Configuration> configuration){
    std::set<ltac::FloatRegister> overriden_float_registers;

    auto descriptor = getPlatformDescriptor(platform);

    if(function->standard || configuration->option_defined("fparameter-allocation")){
        unsigned int maxFloat = descriptor->numberOfFloatParamRegisters();

        for(auto& parameter : function->parameters){
            auto type = function->getParameterType(parameter.name);
            unsigned int position = function->getParameterPositionByType(parameter.name);

            if(mtac::is_single_float_register(type) && position <= maxFloat){
                overriden_float_registers.insert(ltac::FloatRegister(descriptor->float_param_register(position)));
            }
        }
    }

    return overriden_float_registers;
}

bool callee_save(std::shared_ptr<eddic::Function> definition, ltac::Register reg, Platform platform, std::shared_ptr<Configuration> configuration){
    auto return_type = definition->returnType;
    auto descriptor = getPlatformDescriptor(platform);

    if((return_type == INT || return_type == BOOL || return_type == CHAR) && reg.reg == descriptor->int_return_register1()){
        return false;
    } else if(return_type == STRING && (reg.reg == descriptor->int_return_register1() || reg.reg == descriptor->int_return_register2())){
        return false;
    } else if(return_type->is_pointer() && reg.reg == descriptor->int_return_register1()){
        return false;
    }

    auto parameters = parameter_registers(definition, platform, configuration);

    if(parameters.count(reg)){
        return false;
    }

    return true;
}

bool callee_save(std::shared_ptr<eddic::Function> definition, ltac::FloatRegister reg, Platform platform, std::shared_ptr<Configuration> configuration){
    auto return_type = definition->returnType;
    auto descriptor = getPlatformDescriptor(platform);

    if(return_type == FLOAT && reg.reg == descriptor->float_return_register()){
        return false;
    }

    auto parameters = float_parameter_registers(definition, platform, configuration);

    if(parameters.count(reg)){
        return false;
    }

    return true;
}

void callee_save_registers(mtac::function_p function, mtac::basic_block_p bb, Platform platform, std::shared_ptr<Configuration> configuration){
    //Save registers for all other functions than main
    if(!function->is_main()){
        for(auto& reg : function->use_registers()){
            if(callee_save(function->definition, reg, platform, configuration)){
                ltac::add_instruction(bb, ltac::Operator::PUSH, reg);
            }
        }

        for(auto& float_reg : function->use_float_registers()){
            if(callee_save(function->definition, float_reg, platform, configuration)){
                ltac::add_instruction(bb, ltac::Operator::SUB, ltac::SP, static_cast<int>(FLOAT->size(platform)));
                ltac::add_instruction(bb, ltac::Operator::FMOV, ltac::Address(ltac::SP, 0), float_reg);
            }
        }
    }
}

void callee_restore_registers(mtac::function_p function, mtac::basic_block_p bb, Platform platform, std::shared_ptr<Configuration> configuration){
    //Save registers for all other functions than main
    if(!function->is_main()){
        for(auto& float_reg : boost::adaptors::reverse(function->use_float_registers())){
            if(callee_save(function->definition, float_reg, platform, configuration)){
                ltac::add_instruction(bb, ltac::Operator::FMOV, float_reg, ltac::Address(ltac::SP, 0));
                ltac::add_instruction(bb, ltac::Operator::ADD, ltac::SP, static_cast<int>(FLOAT->size(platform)));
            }
        }

        for(auto& reg : boost::adaptors::reverse(function->use_registers())){
            if(callee_save(function->definition, reg, platform, configuration)){
                ltac::add_instruction(bb, ltac::Operator::POP, reg);
            }
        }
    }
}

template<typename It>
void callee_restore_registers(mtac::function_p function, It& it, Platform platform, std::shared_ptr<Configuration> configuration){
    //Save registers for all other functions than main
    if(!function->is_main()){
        for(auto& reg : function->use_registers()){
            if(callee_save(function->definition, reg, platform, configuration)){
                it.insert(std::make_shared<ltac::Instruction>(ltac::Operator::POP, reg));
            }
        }

        for(auto& float_reg : function->use_float_registers()){
            if(callee_save(function->definition, float_reg, platform, configuration)){
                it.insert(std::make_shared<ltac::Instruction>(ltac::Operator::ADD, ltac::SP, static_cast<int>(FLOAT->size(platform))));
                it.insert(std::make_shared<ltac::Instruction>(ltac::Operator::FMOV, float_reg, ltac::Address(ltac::SP, 0)));
            }
        }
    }
}

template<typename T>
bool contains(const std::set<T>& set, const T& value){
    return set.find(value) != set.end();
}

template<typename T>
bool contains(const std::unordered_set<T>& set, const T& value){
    return set.find(value) != set.end();
}

bool caller_save(mtac::function_p source, std::shared_ptr<eddic::Function> target_definition, ltac::Register reg, Platform platform, std::shared_ptr<Configuration> configuration){
    auto source_parameters = parameter_registers(source->definition, platform, configuration);
    auto target_parameters = parameter_registers(target_definition, platform, configuration);
    auto variable_registers = source->variable_registers();

    //Only saved is used to hold a variable (not bound) or as a parameter in the source function
    if(contains(target_parameters, reg) && (contains(variable_registers, reg) || contains(source_parameters, reg))){
        return true;
    }

    return false;
}

bool caller_save(mtac::function_p source, std::shared_ptr<eddic::Function> target_definition, ltac::FloatRegister reg, Platform platform, std::shared_ptr<Configuration> configuration){
    auto source_parameters = float_parameter_registers(source->definition, platform, configuration);
    auto target_parameters = float_parameter_registers(target_definition, platform, configuration);
    auto variable_registers = source->variable_float_registers();

    //Only saved is used to hold a variable (not bound) or as a parameter in the source function
    if(contains(target_parameters, reg) && (contains(variable_registers, reg) || contains(source_parameters, reg))){
        return true;
    }

    return false;
}

template<typename It>
void caller_save_registers(mtac::function_p function, std::shared_ptr<eddic::Function> target_function, mtac::basic_block_p bb, It it, Platform platform, std::shared_ptr<Configuration> configuration){
    auto pre_it = it.it;

    auto call = boost::get<std::shared_ptr<ltac::Jump>>(*it);

    while(true){
        while(pre_it != bb->l_statements.begin()){
            --pre_it;

            auto statement = *pre_it;

            if(auto* ptr = boost::get<std::shared_ptr<ltac::Instruction>>(&statement)){
                if((*ptr)->op == ltac::Operator::PRE_PARAM){
                    (*ptr)->op = ltac::Operator::NOP;

                    for(auto& float_reg : boost::adaptors::reverse(function->use_float_registers())){
                        if(caller_save(function, target_function, float_reg, platform, configuration)){
                            pre_it = bb->l_statements.insert(pre_it, std::make_shared<ltac::Instruction>(ltac::Operator::FMOV, ltac::Address(ltac::SP, 0), float_reg));
                            pre_it = bb->l_statements.insert(pre_it, std::make_shared<ltac::Instruction>(ltac::Operator::SUB, ltac::SP, static_cast<int>(FLOAT->size(platform))));
                        }
                    }

                    for(auto& reg : boost::adaptors::reverse(function->use_registers())){
                        if(caller_save(function, target_function, reg, platform, configuration)){
                            pre_it = bb->l_statements.insert(pre_it, std::make_shared<ltac::Instruction>(ltac::Operator::PUSH, reg));
                        }
                    }

                    return;
                }
            }
        }

        bb = bb->prev;
        pre_it = bb->l_statements.end();
    }
}

template<typename It, typename Type>
void find(It& it, const Type& value){
    while(true){
        if(auto* ptr = boost::get<Type>(&*it)){
            if(*ptr == value){
                return;
            }
        }

        ++it;
    }
}

template<typename It>
void caller_cleanup(mtac::function_p function, std::shared_ptr<eddic::Function> target_function, mtac::basic_block_p bb, It it, Platform platform, std::shared_ptr<Configuration> configuration){
    auto call = boost::get<std::shared_ptr<ltac::Jump>>(*it);

    caller_save_registers(function, target_function, bb, it, platform, configuration);

    //The iterator has been invalidated by the save, find the call again
    it.restart();
    find(it, call);

    if(it.has_next()){
        ++it;

        bool rewind = true;

        if(auto* ptr = boost::get<std::shared_ptr<ltac::Instruction>>(&*it)){
            if((*ptr)->op == ltac::Operator::ADD){
                if(auto* reg_ptr = boost::get<ltac::Register>(&*(*ptr)->arg1)){
                    if(*reg_ptr == ltac::SP){
                       rewind = false;
                    }
                }
            }
        }

        if(rewind){
            --it;
        }
    }

    for(auto& float_reg : boost::adaptors::reverse(function->use_float_registers())){
        if(caller_save(function, target_function, float_reg, platform, configuration)){
            it.insert_after(std::make_shared<ltac::Instruction>(ltac::Operator::FMOV, float_reg, ltac::Address(ltac::SP, 0)));
            it.insert_after(std::make_shared<ltac::Instruction>(ltac::Operator::ADD, ltac::SP, static_cast<int>(FLOAT->size(platform))));
        }
    }

    for(auto& reg : boost::adaptors::reverse(function->use_registers())){
        if(caller_save(function, target_function, reg, platform, configuration)){
            it.insert_after(std::make_shared<ltac::Instruction>(ltac::Operator::POP, reg));
        }
    }
}

} //End of anonymous

void ltac::generate_prologue_epilogue(mtac::program_p ltac_program, std::shared_ptr<Configuration> configuration){
    bool omit_fp = configuration->option_defined("fomit-frame-pointer");
    auto platform = ltac_program->context->target_platform();

    for(auto& function : ltac_program->functions){
        auto size = function->context->size();

        //1. Generate prologue

        auto bb = function->entry_bb();

        //Enter stack frame
        if(!omit_fp){
            ltac::add_instruction(bb, ltac::Operator::ENTER);
        }

        //Allocate stack space for locals
        ltac::add_instruction(bb, ltac::Operator::SUB, ltac::SP, size);

        auto iter = function->context->begin();
        auto end = function->context->end();

        //Clear stack variables
        for(; iter != end; iter++){
            auto var = iter->second;

            //Only stack variables needs to be cleared
            if(var->position().isStack()){
                auto type = var->type();
                int position = var->position().offset();

                auto int_size = INT->size(platform);

                if(type->is_array() && type->has_elements()){
                    ltac::add_instruction(bb, ltac::Operator::MOV, ltac::Address(ltac::BP, position), static_cast<int>(type->elements()));
                    ltac::add_instruction(bb, ltac::Operator::MEMSET, ltac::Address(ltac::BP, position + int_size),
                            static_cast<int>((type->data_type()->size(platform) / int_size * type->elements())));
                } else if(type->is_custom_type()){
                    ltac::add_instruction(bb, ltac::Operator::MEMSET, ltac::Address(ltac::BP, position), static_cast<int>(type->size(platform) / int_size));
                }
            }
        }

        callee_save_registers(function, bb, platform, configuration);

        //2. Generate epilogue

        bb = function->exit_bb();

        callee_restore_registers(function, bb, platform, configuration);

        ltac::add_instruction(bb, ltac::Operator::ADD, ltac::SP, size);

        //Leave stack frame
        if(!omit_fp){
            ltac::add_instruction(bb, ltac::Operator::LEAVE);
        }

        ltac::add_instruction(bb, ltac::Operator::RET);

        //3. Generate epilogue for each unresolved RET

        for(auto& bb : function){
            auto it = iterate(bb->l_statements);

            while(it.has_next()){
                auto statement = *it;

                if(auto* ptr = boost::get<std::shared_ptr<ltac::Instruction>>(&statement)){
                    if((*ptr)->op == ltac::Operator::PRE_RET){
                        (*ptr)->op = ltac::Operator::RET;

                        //Leave stack frame
                        if(!omit_fp){
                            it.insert(std::make_shared<ltac::Instruction>(ltac::Operator::LEAVE));
                        }

                        it.insert(std::make_shared<ltac::Instruction>(ltac::Operator::ADD, ltac::SP, size));

                        callee_restore_registers(function, it, platform, configuration);
                    }
                }

                ++it;
            }
        }

        //4. Generate caller save/restore code

        for(auto& bb : function){
            auto it = iterate(bb->l_statements);

            while(it.has_next()){
                auto statement = *it;

                if(auto* ptr = boost::get<std::shared_ptr<ltac::Jump>>(&statement)){
                    if((*ptr)->type == ltac::JumpType::CALL){
                        caller_cleanup(function, (*ptr)->target_function, bb, it, platform, configuration);

                        //The iterator is invalidated by the cleanup, necessary to find the call again
                        it.restart();
                        find(it, *ptr);
                    }
                }

                ++it;
            }
        }
    }
}
<|endoftext|>


<commit_before>/* The MIT License (MIT)
 * Copyright (c) <2013> <Nicholas Wright>
 * http://opensource.org/licenses/MIT
 */

/*
 * SHA.cpp
 *
 *  Created on: 23 Dec 2013
 *      Author: Nicholas Wright
 */

#include "../../include/hash/SHA.hpp"
#include <openssl/sha.h>
#include <boost/iostreams/device/file.hpp>
#include <boost/filesystem/fstream.hpp>
#include <iomanip>

using namespace log4cplus;

SHA::SHA() {
	logger = Logger::getInstance(LOG4CPLUS_TEXT("SHA"));
}

std::string SHA::sha256(boost::filesystem::path filepath) {
	if (!boost::filesystem::exists(filepath)) {
		LOG4CPLUS_ERROR(logger, "File " << filepath << " does not exist");
		return "";
	}

	unsigned char digest[SHA256_DIGEST_LENGTH];
	boost::filesystem::ifstream targetFile;

	targetFile.open(filepath, std::ios::in | std::ios::app | std::ios::binary);

	SHA256_CTX sha256;
	SHA256_Init(&sha256);

	std::istream_iterator<unsigned char> eos;
	std::istream_iterator<unsigned char> ite(targetFile);

	int readCount = 0;

	while (ite != eos) {
		SHA256_Update(&sha256, &(*ite), sizeof(*ite));

		ite++;
		readCount++;
	}

	SHA256_Final(digest, &sha256);
	targetFile.close();

	LOG4CPLUS_DEBUG(logger, "Read " << readCount << " bytes from " << filepath);

	std::ostringstream os;
	    os << std::hex << std::setfill('0');  // set the stream to hex with 0 fill

	    for(int i = 0; i < SHA256_DIGEST_LENGTH; i++) {
	    	os << std::setw(2) << (unsigned int)(digest[i]);
	    }

	return os.str();
}

SHA::~SHA() {
	// TODO Auto-generated destructor stub
}

<commit_msg>Fixed white space skip for binary files<commit_after>/* The MIT License (MIT)
 * Copyright (c) <2013> <Nicholas Wright>
 * http://opensource.org/licenses/MIT
 */

/*
 * SHA.cpp
 *
 *  Created on: 23 Dec 2013
 *      Author: Nicholas Wright
 */

#include "../../include/hash/SHA.hpp"
#include <openssl/sha.h>
#include <boost/iostreams/device/file.hpp>
#include <boost/filesystem/fstream.hpp>
#include <iomanip>

using namespace log4cplus;

SHA::SHA() {
	logger = Logger::getInstance(LOG4CPLUS_TEXT("SHA"));
}

std::string SHA::sha256(boost::filesystem::path filepath) {
	if (!boost::filesystem::exists(filepath)) {
		LOG4CPLUS_ERROR(logger, "File " << filepath << " does not exist");
		return "";
	}

	unsigned char digest[SHA256_DIGEST_LENGTH];
	boost::filesystem::ifstream targetFile;

	targetFile.open(filepath, std::ios::in | std::ios::app | std::ios::binary);

	SHA256_CTX sha256;
	SHA256_Init(&sha256);

	std::istreambuf_iterator<char> eos;
	std::istreambuf_iterator<char> ite(targetFile);

	int readCount = 0;

	while (ite != eos) {
		char byte = *ite;
		SHA256_Update(&sha256, &byte, sizeof(*ite));

		ite++;
		readCount++;
	}

	SHA256_Final(digest, &sha256);
	targetFile.close();

	LOG4CPLUS_DEBUG(logger, "Read " << readCount << " bytes from " << filepath);

	std::ostringstream os;
	    os << std::hex << std::setfill('0');  // set the stream to hex with 0 fill

	    for(int i = 0; i < SHA256_DIGEST_LENGTH; i++) {
	    	os << std::setw(2) << (unsigned int)(digest[i]);
	    }

	return os.str();
}

SHA::~SHA() {
	// TODO Auto-generated destructor stub
}

<|endoftext|>


<commit_before>#ifndef RETHREAD_CANCELLATION_TOKEN_H
#define RETHREAD_CANCELLATION_TOKEN_H

#include <rethread/detail/utility.hpp>

#include <atomic>
#include <chrono>
#include <condition_variable>
#include <mutex>
#include <thread>

namespace rethread
{
	class cancellation_handler
	{
	protected:
		virtual ~cancellation_handler() { }

	public:
		/// @brief Should cancel blocking call
		virtual void cancel() = 0;

		/// @brief Should reset cancellation_handler to it's original state
		///        For each cancel() call, there's _exactly_ one reset() call
		virtual void reset() { }
	};

	class cancellation_token;

	namespace this_thread
	{
		template<typename Rep, typename Period>
		inline void sleep_for(const std::chrono::duration<Rep, Period>& duration, const cancellation_token& token);
	}

	class cancellation_token
	{
	public:
		virtual void cancel() = 0;
		virtual void reset() = 0;

		virtual bool is_cancelled() const = 0;

		explicit operator bool() const
		{ return !is_cancelled(); }

	protected:
		virtual ~cancellation_token() { }

		template<typename Rep, typename Period>
		void sleep_for(const std::chrono::duration<Rep, Period>& duration) const
		{ do_sleep_for(std::chrono::duration_cast<std::chrono::nanoseconds>(duration)); }

		virtual void do_sleep_for(const std::chrono::nanoseconds& duration) const = 0;

		/// @pre Handler is not registered
		/// @returns Whether handler was registered. If token was cancelled before registration, this method skips registration and returns false
		virtual bool try_register_cancellation_handler(cancellation_handler& handler) const = 0;

		/// @pre Handler is registered
		/// @returns Whether unregistration succeed
		virtual bool try_unregister_cancellation_handler(cancellation_handler& handler) const = 0;

		/// @pre Handler is registered
		/// @post Handler is not registered
		/// @note Will invoke cancellation_handler::reset() if necessary
		virtual void unregister_cancellation_handler(cancellation_handler& handler) const = 0;

	private:
		friend class cancellation_guard_base;

		template<typename Rep, typename Period>
		friend void this_thread::sleep_for(const std::chrono::duration<Rep, Period>& duration, const cancellation_token& token);
	};

	class dummy_cancellation_token : public cancellation_token
	{
	public:
		void cancel() override { }
		void reset() override  { }

		bool is_cancelled() const override
		{ return false; }

	protected:
		void do_sleep_for(const std::chrono::nanoseconds& duration) const override     { std::this_thread::sleep_for(duration); }

		bool try_register_cancellation_handler(cancellation_handler&) const override   { return true; }
		bool try_unregister_cancellation_handler(cancellation_handler&) const override { return true; }
		void unregister_cancellation_handler(cancellation_handler&) const override     { }
	};

	class cancellation_token_impl : public cancellation_token
	{
		mutable std::mutex              _mutex;
		mutable std::condition_variable _cv;
		std::atomic<bool>               _cancelled{false};
		mutable bool                    _cancelDone{false};
		mutable cancellation_handler*   _cancelHandler{nullptr};

	public:
		cancellation_token_impl() = default;
		cancellation_token_impl(const cancellation_token_impl&) = delete;
		cancellation_token_impl& operator = (const cancellation_token_impl&) = delete;

		void cancel() override
		{
			cancellation_handler* cancelHandler = nullptr;
			{
				std::unique_lock<std::mutex> l(_mutex);
				if (_cancelled)
					return;

				cancelHandler = _cancelHandler;
				_cancelled = true;
			}

			if (cancelHandler)
				cancelHandler->cancel();

			{
				std::unique_lock<std::mutex> l(_mutex);
				_cancelDone = true;
				_cv.notify_all();
			}
		}

		void reset() override
		{
			std::unique_lock<std::mutex> l(_mutex);
			RETHREAD_ASSERT(!_cancelHandler && (_cancelled == _cancelDone), "Cancellation token is in use!");
			_cancelled = false;
			_cancelDone = false;
		}

		bool is_cancelled() const override
		{ return _cancelled.load(std::memory_order_relaxed); }

	protected:
		void do_sleep_for(const std::chrono::nanoseconds& duration) const override
		{
			std::unique_lock<std::mutex> l(_mutex);
			if (_cancelled)
				return;

			_cv.wait_for(l, duration);
		}

		bool try_register_cancellation_handler(cancellation_handler& handler) const override
		{
			std::unique_lock<std::mutex> l(_mutex);
			if (_cancelled)
				return false;

			RETHREAD_ASSERT(!_cancelHandler, "Cancellation handler already registered!");
			_cancelHandler = &handler;
			return true;
		}

		bool try_unregister_cancellation_handler(cancellation_handler&) const override
		{
			std::unique_lock<std::mutex> l(_mutex);
			if (_cancelled)
				return false;

			_cancelHandler = nullptr;
			return true;
		}

		void unregister_cancellation_handler(cancellation_handler&) const override
		{
			std::unique_lock<std::mutex> l(_mutex);
			RETHREAD_ASSERT(_cancelHandler, "No cancellation_handler!");

			cancellation_handler* handler = _cancelHandler;
			_cancelHandler = nullptr;

			if (!_cancelled)
				return;

			while (!_cancelDone)
				_cv.wait(l);

			l.unlock();
			handler->reset();
		}
	};

	class cancellation_token_atomic : public cancellation_token
	{
		std::atomic<bool>                          _cancelled{false};
		mutable std::atomic<cancellation_handler*> _cancelHandler{nullptr};

		mutable std::mutex                         _mutex;
		mutable std::condition_variable            _cv;
		mutable bool                               _cancelDone{false};

	public:
		cancellation_token_atomic() = default;
		cancellation_token_atomic(const cancellation_token_atomic&) = delete;
		cancellation_token_atomic& operator = (const cancellation_token_atomic&) = delete;

		void cancel() override
		{
			cancellation_handler* cancelHandler = nullptr;
			{
				std::unique_lock<std::mutex> l(_mutex);
				if (_cancelled)
					return;

				_cancelled = true;

				cancelHandler = _cancelHandler.exchange(HazardPointer());
				RETHREAD_ASSERT(cancelHandler != HazardPointer(), "_cancelled should protect from double-cancelling");
			}

			if (cancelHandler)
			{
				RETHREAD_ANNOTATE_AFTER(std::addressof(_cancelHandler));
				cancelHandler->cancel();
				RETHREAD_ANNOTATE_BEFORE(cancelHandler);
			}

			{
				std::unique_lock<std::mutex> l(_mutex);
				_cancelDone = true;
				_cv.notify_all();
			}
		}

		void reset() override
		{
			std::unique_lock<std::mutex> l(_mutex);
			RETHREAD_ASSERT((_cancelHandler.load() || _cancelHandler == HazardPointer()) && (_cancelled == _cancelDone), "Cancellation token is in use!");
			_cancelled = false;
			_cancelDone = false;
		}

		bool is_cancelled() const override
		{ return _cancelled.load(std::memory_order_relaxed); }

	protected:
		void do_sleep_for(const std::chrono::nanoseconds& duration) const override
		{
			std::unique_lock<std::mutex> l(_mutex);
			if (is_cancelled())
				return;

			_cv.wait_for(l, duration);
		}

		bool try_register_cancellation_handler(cancellation_handler& handler) const override
		{
			RETHREAD_ANNOTATE_BEFORE(std::addressof(_cancelHandler));
			cancellation_handler* h = _cancelHandler.exchange(&handler, std::memory_order_release);
			if (RETHREAD_UNLIKELY(h != nullptr))
			{
				RETHREAD_ASSERT(h == HazardPointer(), "Cancellation handler already registered!");
				return false;
			}
			return true;
		}

		bool try_unregister_cancellation_handler(cancellation_handler& handler) const override
		{
			cancellation_handler* h = _cancelHandler.exchange(nullptr, std::memory_order_acquire);
			if (RETHREAD_LIKELY(h == &handler))
			{
				RETHREAD_ANNOTATE_AFTER(std::addressof(handler));
				RETHREAD_ANNOTATE_FORGET(std::addressof(handler));
				return true;
			}

			RETHREAD_ASSERT(h == HazardPointer(), "Another token was registered!");
			_cancelHandler.exchange(h); // restore value
			return false;
		}

		void unregister_cancellation_handler(cancellation_handler& handler) const override
		{
			if (try_unregister_cancellation_handler(handler))
				return;

			std::unique_lock<std::mutex> l(_mutex);
			_cancelHandler = nullptr;

			if (!_cancelled)
				return;

			while (!_cancelDone)
				_cv.wait(l);

			RETHREAD_ANNOTATE_AFTER(std::addressof(handler));
			RETHREAD_ANNOTATE_FORGET(std::addressof(handler));
			l.unlock();
			handler.reset();
		}

	private:
		// Dirty trick to optimize register/unregister down to one atomic exchange
		static cancellation_handler* HazardPointer()
		{ return reinterpret_cast<cancellation_handler*>(1); }
	};

	class cancellation_guard_base
	{
	protected:
		bool try_register(const cancellation_token& token, cancellation_handler& handler)
		{ return token.try_register_cancellation_handler(handler); }

		bool try_unregister(const cancellation_token& token, cancellation_handler& handler)
		{ return token.try_unregister_cancellation_handler(handler); }

		void unregister(const cancellation_token& token, cancellation_handler& handler)
		{ token.unregister_cancellation_handler(handler); }
	};

	class cancellation_guard : public cancellation_guard_base
	{
	private:
		const cancellation_token* _token;
		cancellation_handler*     _handler;

	public:
		cancellation_guard(const cancellation_guard&) = delete;
		cancellation_guard& operator = (const cancellation_guard&) = delete;

		cancellation_guard() :
			_token(nullptr), _handler(nullptr)
		{ }

		cancellation_guard(const cancellation_token& token, cancellation_handler& handler) :
			_token(nullptr), _handler(&handler)
		{
			if (try_register(token, handler))
				_token = &token;
		}

		cancellation_guard(cancellation_guard&& other) :
			_token(other._token), _handler(other._handler)
		{ other._token = nullptr; }

		~cancellation_guard()
		{
			if (!_token || RETHREAD_LIKELY(try_unregister(*_token, *_handler)))
				return;
			unregister(*_token, *_handler);
		}

		bool is_cancelled() const
		{ return !_token; }
	};
}

#endif
<commit_msg>Revised annotations - added missing FORGET and removed redundant annotation<commit_after>#ifndef RETHREAD_CANCELLATION_TOKEN_H
#define RETHREAD_CANCELLATION_TOKEN_H

#include <rethread/detail/utility.hpp>

#include <atomic>
#include <chrono>
#include <condition_variable>
#include <mutex>
#include <thread>

namespace rethread
{
	class cancellation_handler
	{
	protected:
		virtual ~cancellation_handler() { }

	public:
		/// @brief Should cancel blocking call
		virtual void cancel() = 0;

		/// @brief Should reset cancellation_handler to it's original state
		///        For each cancel() call, there's _exactly_ one reset() call
		virtual void reset() { }
	};

	class cancellation_token;

	namespace this_thread
	{
		template<typename Rep, typename Period>
		inline void sleep_for(const std::chrono::duration<Rep, Period>& duration, const cancellation_token& token);
	}

	class cancellation_token
	{
	public:
		virtual void cancel() = 0;
		virtual void reset() = 0;

		virtual bool is_cancelled() const = 0;

		explicit operator bool() const
		{ return !is_cancelled(); }

	protected:
		virtual ~cancellation_token() { }

		template<typename Rep, typename Period>
		void sleep_for(const std::chrono::duration<Rep, Period>& duration) const
		{ do_sleep_for(std::chrono::duration_cast<std::chrono::nanoseconds>(duration)); }

		virtual void do_sleep_for(const std::chrono::nanoseconds& duration) const = 0;

		/// @pre Handler is not registered
		/// @returns Whether handler was registered. If token was cancelled before registration, this method skips registration and returns false
		virtual bool try_register_cancellation_handler(cancellation_handler& handler) const = 0;

		/// @pre Handler is registered
		/// @returns Whether unregistration succeed
		virtual bool try_unregister_cancellation_handler(cancellation_handler& handler) const = 0;

		/// @pre Handler is registered
		/// @post Handler is not registered
		/// @note Will invoke cancellation_handler::reset() if necessary
		virtual void unregister_cancellation_handler(cancellation_handler& handler) const = 0;

	private:
		friend class cancellation_guard_base;

		template<typename Rep, typename Period>
		friend void this_thread::sleep_for(const std::chrono::duration<Rep, Period>& duration, const cancellation_token& token);
	};

	class dummy_cancellation_token : public cancellation_token
	{
	public:
		void cancel() override { }
		void reset() override  { }

		bool is_cancelled() const override
		{ return false; }

	protected:
		void do_sleep_for(const std::chrono::nanoseconds& duration) const override     { std::this_thread::sleep_for(duration); }

		bool try_register_cancellation_handler(cancellation_handler&) const override   { return true; }
		bool try_unregister_cancellation_handler(cancellation_handler&) const override { return true; }
		void unregister_cancellation_handler(cancellation_handler&) const override     { }
	};

	class cancellation_token_impl : public cancellation_token
	{
		mutable std::mutex              _mutex;
		mutable std::condition_variable _cv;
		std::atomic<bool>               _cancelled{false};
		mutable bool                    _cancelDone{false};
		mutable cancellation_handler*   _cancelHandler{nullptr};

	public:
		cancellation_token_impl() = default;
		cancellation_token_impl(const cancellation_token_impl&) = delete;
		cancellation_token_impl& operator = (const cancellation_token_impl&) = delete;

		void cancel() override
		{
			cancellation_handler* cancelHandler = nullptr;
			{
				std::unique_lock<std::mutex> l(_mutex);
				if (_cancelled)
					return;

				cancelHandler = _cancelHandler;
				_cancelled = true;
			}

			if (cancelHandler)
				cancelHandler->cancel();

			{
				std::unique_lock<std::mutex> l(_mutex);
				_cancelDone = true;
				_cv.notify_all();
			}
		}

		void reset() override
		{
			std::unique_lock<std::mutex> l(_mutex);
			RETHREAD_ASSERT(!_cancelHandler && (_cancelled == _cancelDone), "Cancellation token is in use!");
			_cancelled = false;
			_cancelDone = false;
		}

		bool is_cancelled() const override
		{ return _cancelled.load(std::memory_order_relaxed); }

	protected:
		void do_sleep_for(const std::chrono::nanoseconds& duration) const override
		{
			std::unique_lock<std::mutex> l(_mutex);
			if (_cancelled)
				return;

			_cv.wait_for(l, duration);
		}

		bool try_register_cancellation_handler(cancellation_handler& handler) const override
		{
			std::unique_lock<std::mutex> l(_mutex);
			if (_cancelled)
				return false;

			RETHREAD_ASSERT(!_cancelHandler, "Cancellation handler already registered!");
			_cancelHandler = &handler;
			return true;
		}

		bool try_unregister_cancellation_handler(cancellation_handler&) const override
		{
			std::unique_lock<std::mutex> l(_mutex);
			if (_cancelled)
				return false;

			_cancelHandler = nullptr;
			return true;
		}

		void unregister_cancellation_handler(cancellation_handler&) const override
		{
			std::unique_lock<std::mutex> l(_mutex);
			RETHREAD_ASSERT(_cancelHandler, "No cancellation_handler!");

			cancellation_handler* handler = _cancelHandler;
			_cancelHandler = nullptr;

			if (!_cancelled)
				return;

			while (!_cancelDone)
				_cv.wait(l);

			l.unlock();
			handler->reset();
		}
	};

	class cancellation_token_atomic : public cancellation_token
	{
		std::atomic<bool>                          _cancelled{false};
		mutable std::atomic<cancellation_handler*> _cancelHandler{nullptr};

		mutable std::mutex                         _mutex;
		mutable std::condition_variable            _cv;
		mutable bool                               _cancelDone{false};

	public:
		cancellation_token_atomic() = default;
		cancellation_token_atomic(const cancellation_token_atomic&) = delete;
		cancellation_token_atomic& operator = (const cancellation_token_atomic&) = delete;

		void cancel() override
		{
			cancellation_handler* cancelHandler = nullptr;
			{
				std::unique_lock<std::mutex> l(_mutex);
				if (_cancelled)
					return;

				_cancelled = true;

				cancelHandler = _cancelHandler.exchange(HazardPointer());
				RETHREAD_ASSERT(cancelHandler != HazardPointer(), "_cancelled should protect from double-cancelling");
			}

			if (cancelHandler)
			{
				RETHREAD_ANNOTATE_AFTER(std::addressof(_cancelHandler));
				RETHREAD_ANNOTATE_FORGET(std::addressof(_cancelHandler));
				cancelHandler->cancel();
				RETHREAD_ANNOTATE_BEFORE(cancelHandler);
			}

			{
				std::unique_lock<std::mutex> l(_mutex);
				_cancelDone = true;
				_cv.notify_all();
			}
		}

		void reset() override
		{
			std::unique_lock<std::mutex> l(_mutex);
			RETHREAD_ASSERT((_cancelHandler.load() || _cancelHandler == HazardPointer()) && (_cancelled == _cancelDone), "Cancellation token is in use!");
			_cancelled = false;
			_cancelDone = false;
		}

		bool is_cancelled() const override
		{ return _cancelled.load(std::memory_order_relaxed); }

	protected:
		void do_sleep_for(const std::chrono::nanoseconds& duration) const override
		{
			std::unique_lock<std::mutex> l(_mutex);
			if (is_cancelled())
				return;

			_cv.wait_for(l, duration);
		}

		bool try_register_cancellation_handler(cancellation_handler& handler) const override
		{
			cancellation_handler* h = _cancelHandler.exchange(&handler, std::memory_order_release);
			RETHREAD_ANNOTATE_BEFORE(std::addressof(_cancelHandler));
			if (RETHREAD_UNLIKELY(h != nullptr))
			{
				RETHREAD_ASSERT(h == HazardPointer(), "Cancellation handler already registered!");
				return false;
			}
			return true;
		}

		bool try_unregister_cancellation_handler(cancellation_handler& handler) const override
		{
			cancellation_handler* h = _cancelHandler.exchange(nullptr, std::memory_order_acquire);
			if (RETHREAD_LIKELY(h == &handler))
				return true;

			RETHREAD_ASSERT(h == HazardPointer(), "Another token was registered!");
			_cancelHandler.exchange(h); // restore value
			return false;
		}

		void unregister_cancellation_handler(cancellation_handler& handler) const override
		{
			if (try_unregister_cancellation_handler(handler))
				return;

			std::unique_lock<std::mutex> l(_mutex);
			_cancelHandler = nullptr;

			if (!_cancelled)
				return;

			while (!_cancelDone)
				_cv.wait(l);

			RETHREAD_ANNOTATE_AFTER(std::addressof(handler));
			RETHREAD_ANNOTATE_FORGET(std::addressof(handler));
			l.unlock();
			handler.reset();
		}

	private:
		// Dirty trick to optimize register/unregister down to one atomic exchange
		static cancellation_handler* HazardPointer()
		{ return reinterpret_cast<cancellation_handler*>(1); }
	};

	class cancellation_guard_base
	{
	protected:
		bool try_register(const cancellation_token& token, cancellation_handler& handler)
		{ return token.try_register_cancellation_handler(handler); }

		bool try_unregister(const cancellation_token& token, cancellation_handler& handler)
		{ return token.try_unregister_cancellation_handler(handler); }

		void unregister(const cancellation_token& token, cancellation_handler& handler)
		{ token.unregister_cancellation_handler(handler); }
	};

	class cancellation_guard : public cancellation_guard_base
	{
	private:
		const cancellation_token* _token;
		cancellation_handler*     _handler;

	public:
		cancellation_guard(const cancellation_guard&) = delete;
		cancellation_guard& operator = (const cancellation_guard&) = delete;

		cancellation_guard() :
			_token(nullptr), _handler(nullptr)
		{ }

		cancellation_guard(const cancellation_token& token, cancellation_handler& handler) :
			_token(nullptr), _handler(&handler)
		{
			if (try_register(token, handler))
				_token = &token;
		}

		cancellation_guard(cancellation_guard&& other) :
			_token(other._token), _handler(other._handler)
		{ other._token = nullptr; }

		~cancellation_guard()
		{
			if (!_token || RETHREAD_LIKELY(try_unregister(*_token, *_handler)))
				return;
			unregister(*_token, *_handler);
		}

		bool is_cancelled() const
		{ return !_token; }
	};
}

#endif
<|endoftext|>


<commit_before>#ifndef UTIL_HPP
#define UTIL_HPP

#include <string>
#include <sstream>
#include <iostream>
#include <vector>
#include <set>
#include <memory>
#include <functional>

#include "utils/suppressWarnings.hpp"

#define UNUSED(expr) (void)(expr)
#define ALL(container) std::begin(container), std::end(container)

using uint = unsigned int;
using int64 = long long;
using uint64 = unsigned long long;

/// Represents a list of types. Used in multiple places
using TypeList = std::set<std::string>;

/// Print something to stdout with a trailing newline
template<typename T>
void println(T thing) {
  std::cout << thing << std::endl;
}

/// Print something to stdout
template<typename T>
void print(T thing) {
  std::cout << thing;
}

/// Print multiple things (with spaces in-between) to stdout
template<typename T, typename... Args>
void print(T thing, Args... args) {
  print(thing);
  print(" ");
  print(args...);
}

/// Print multiple things (with spaces in-between) to stdout with a trailing newline
template<typename T, typename... Args>
void println(T thing, Args... args) {
  if (sizeof...(args) == 1) {
    print(thing);
    print(" ");
    print(args...);
    std::cout << std::endl;
    return;
  }
  print(thing);
  print(" ");
  print(args...);
}

/// Checks if the vector has the item in it
template<typename T>
bool contains(std::vector<T> vec, T item) {
  return std::find(vec.begin(), vec.end(), item) != vec.end();
}

/**
  \brief Split a string into substrings
  \param delim where to break the string
*/
std::vector<std::string> split(const std::string& str, char delim);

/// Allows the use of vectors as map keys
template<typename T>
struct VectorHash {
  std::size_t operator()(const std::vector<T>& vec) const {
    std::size_t seed = vec.size();
    std::hash<T> hash;
    for (const T& i : vec) {
      seed ^= hash(i) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
    }
    return seed;
  }
};

/// Smart pointer utils
template<typename T>
struct PtrUtil {
  /// Shared pointer
  using Link = std::shared_ptr<T>;
  /// Weak pointer
  using WeakLink = std::weak_ptr<T>;

  /**
    \brief Use RTTI to determine if 2 pointers have the same type.
    \tparam U type stored in the shared ptr to compare to

    Compares this PtrUtil's template type with this function's template type.
  */
  template<typename U>
  static inline bool isSameType(const std::shared_ptr<U>& link) {
    return typeid(T) == typeid(*link);
  }

  /**
    \brief Wrapper around std::dynamic_pointer_cast.
    \tparam U stored in the shared ptr to be casted
  */
  template<typename U>
  static inline Link dynPtrCast(const std::shared_ptr<U>& link) {
    return std::dynamic_pointer_cast<T>(link);
  }

  /**
    \brief Wrapper around std::static_pointer_cast.
    \tparam U stored in the shared ptr to be casted
  */
  template<typename U>
  static inline Link staticPtrCast(const std::shared_ptr<U>& link) {
    return std::static_pointer_cast<T>(link);
  }
};

/// Get a pretty address string from a pointer
std::string getAddressStringFrom(const void* ptr);

/// Identity function. Does literally nothing.
struct Identity {
  template<typename T>
  constexpr auto operator()(T&& v) const noexcept -> decltype(std::forward<T>(v)) {
    return std::forward<T>(v);
  }
};

static const auto defaultCollateCombine = [](std::string prev, std::string current) {return prev + ", " + current;};
#define COLLATE_TYPE const typename Container::value_type&

/**
  \brief Collates a bunch of objects from Container into a string
  \param c the Container with objects
  \param objToString lambda to convert the object to a string (by default uses Identity)
  \param combine reduce-style lambda
*/
template<typename Container>
std::string collate(Container c,
  std::function<std::string(COLLATE_TYPE)> objToString = Identity(),
  std::function<std::string(std::string, std::string)> combine = defaultCollateCombine
  ) {
  if (c.size() == 0) return "";
  if (c.size() == 1) return objToString(*c.begin());
  if (c.size() >= 2) {
    std::string str = objToString(*c.begin());
    std::for_each(++c.begin(), c.end(), [&str, &objToString, &combine](COLLATE_TYPE object) {
      str = combine(str, objToString(object));
    });
    return str;
  }
  throw std::logic_error("Size of container must be a positive integer");
}

#undef COLLATE_TYPE

/**
  \brief Convenience function
  \see collate
*/
std::string collateTypeList(TypeList typeList);

#endif
<commit_msg>Remove useless macro<commit_after>#ifndef UTIL_HPP
#define UTIL_HPP

#include <string>
#include <sstream>
#include <iostream>
#include <vector>
#include <set>
#include <memory>
#include <functional>

#include "utils/suppressWarnings.hpp"

#define UNUSED(expr) (void)(expr)
#define ALL(container) std::begin(container), std::end(container)

using uint = unsigned int;
using int64 = long long;
using uint64 = unsigned long long;

/// Represents a list of types. Used in multiple places
using TypeList = std::set<std::string>;

/// Print something to stdout with a trailing newline
template<typename T>
void println(T thing) {
  std::cout << thing << std::endl;
}

/// Print something to stdout
template<typename T>
void print(T thing) {
  std::cout << thing;
}

/// Print multiple things (with spaces in-between) to stdout
template<typename T, typename... Args>
void print(T thing, Args... args) {
  print(thing);
  print(" ");
  print(args...);
}

/// Print multiple things (with spaces in-between) to stdout with a trailing newline
template<typename T, typename... Args>
void println(T thing, Args... args) {
  if (sizeof...(args) == 1) {
    print(thing);
    print(" ");
    print(args...);
    std::cout << std::endl;
    return;
  }
  print(thing);
  print(" ");
  print(args...);
}

/// Checks if the vector has the item in it
template<typename T>
bool contains(std::vector<T> vec, T item) {
  return std::find(vec.begin(), vec.end(), item) != vec.end();
}

/**
  \brief Split a string into substrings
  \param delim where to break the string
*/
std::vector<std::string> split(const std::string& str, char delim);

/// Allows the use of vectors as map keys
template<typename T>
struct VectorHash {
  std::size_t operator()(const std::vector<T>& vec) const {
    std::size_t seed = vec.size();
    std::hash<T> hash;
    for (const T& i : vec) {
      seed ^= hash(i) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
    }
    return seed;
  }
};

/// Smart pointer utils
template<typename T>
struct PtrUtil {
  /// Shared pointer
  using Link = std::shared_ptr<T>;
  /// Weak pointer
  using WeakLink = std::weak_ptr<T>;

  /**
    \brief Use RTTI to determine if 2 pointers have the same type.
    \tparam U type stored in the shared ptr to compare to

    Compares this PtrUtil's template type with this function's template type.
  */
  template<typename U>
  static inline bool isSameType(const std::shared_ptr<U>& link) {
    return typeid(T) == typeid(*link);
  }

  /**
    \brief Wrapper around std::dynamic_pointer_cast.
    \tparam U stored in the shared ptr to be casted
  */
  template<typename U>
  static inline Link dynPtrCast(const std::shared_ptr<U>& link) {
    return std::dynamic_pointer_cast<T>(link);
  }

  /**
    \brief Wrapper around std::static_pointer_cast.
    \tparam U stored in the shared ptr to be casted
  */
  template<typename U>
  static inline Link staticPtrCast(const std::shared_ptr<U>& link) {
    return std::static_pointer_cast<T>(link);
  }
};

/// Get a pretty address string from a pointer
std::string getAddressStringFrom(const void* ptr);

/// Identity function. Does literally nothing.
struct Identity {
  template<typename T>
  constexpr auto operator()(T&& v) const noexcept -> decltype(std::forward<T>(v)) {
    return std::forward<T>(v);
  }
};

static const auto defaultCollateCombine = [](std::string prev, std::string current) {return prev + ", " + current;};

/**
  \brief Collates a bunch of objects from Container into a string
  \tparam Container full type of source container (ex std::vector<int>)
  \param c the Container with objects
  \param objToString lambda to convert the object to a string (by default uses Identity)
  \param combine reduce-style lambda
*/
template<typename Container>
std::string collate(Container c,
  std::function<std::string(const typename Container::value_type&)> objToString = Identity(),
  std::function<std::string(std::string, std::string)> combine = defaultCollateCombine
  ) {
  if (c.size() == 0) return "";
  if (c.size() == 1) return objToString(*c.begin());
  if (c.size() >= 2) {
    std::string str = objToString(*c.begin());
    std::for_each(++c.begin(), c.end(), [&str, &objToString, &combine](const typename Container::value_type& object) {
      str = combine(str, objToString(object));
    });
    return str;
  }
  throw std::logic_error("Size of container must be a positive integer");
}

/**
  \brief Convenience function
  \see collate
*/
std::string collateTypeList(TypeList typeList);

#endif
<|endoftext|>