<commit_before>/*=====================================================================

 QGroundControl Open Source Ground Control Station

 (c) 2009 - 2015 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>

 This file is part of the QGROUNDCONTROL project

 QGROUNDCONTROL is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 QGROUNDCONTROL is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.

 ======================================================================*/

/// @file
///     @author Don Gagne <don@thegagnes.com>

#include "PX4FirmwarePlugin.h"
#include "PX4ParameterMetaData.h"
#include "AutoPilotPlugins/PX4/PX4AutoPilotPlugin.h"    // FIXME: Hack

#include <QDebug>

enum PX4_CUSTOM_MAIN_MODE {
    PX4_CUSTOM_MAIN_MODE_MANUAL = 1,
    PX4_CUSTOM_MAIN_MODE_ALTCTL,
    PX4_CUSTOM_MAIN_MODE_POSCTL,
    PX4_CUSTOM_MAIN_MODE_AUTO,
    PX4_CUSTOM_MAIN_MODE_ACRO,
    PX4_CUSTOM_MAIN_MODE_OFFBOARD,
    PX4_CUSTOM_MAIN_MODE_STABILIZED,
    PX4_CUSTOM_MAIN_MODE_RATTITUDE
};

enum PX4_CUSTOM_SUB_MODE_AUTO {
    PX4_CUSTOM_SUB_MODE_AUTO_READY = 1,
    PX4_CUSTOM_SUB_MODE_AUTO_TAKEOFF,
    PX4_CUSTOM_SUB_MODE_AUTO_LOITER,
    PX4_CUSTOM_SUB_MODE_AUTO_MISSION,
    PX4_CUSTOM_SUB_MODE_AUTO_RTL,
    PX4_CUSTOM_SUB_MODE_AUTO_LAND,
    PX4_CUSTOM_SUB_MODE_AUTO_RTGS
};

union px4_custom_mode {
    struct {
        uint16_t reserved;
        uint8_t main_mode;
        uint8_t sub_mode;
    };
    uint32_t data;
    float data_float;
};

struct Modes2Name {
    uint8_t     main_mode;
    uint8_t     sub_mode;
    const char* name;       ///< Name for flight mode
    bool        canBeSet;   ///< true: Vehicle can be set to this flight mode
};

/// Tranlates from PX4 custom modes to flight mode names

static const struct Modes2Name rgModes2Name[] = {
    { PX4_CUSTOM_MAIN_MODE_MANUAL,      0,                                  "Manual",           true },
    { PX4_CUSTOM_MAIN_MODE_ACRO,        0,                                  "Acro",             true },
    { PX4_CUSTOM_MAIN_MODE_STABILIZED,  0,                                  "Stabilized",       true },
    { PX4_CUSTOM_MAIN_MODE_RATTITUDE,   0,                                  "Rattitude",        true },
    { PX4_CUSTOM_MAIN_MODE_ALTCTL,      0,                                  "Altitude Control", true },
    { PX4_CUSTOM_MAIN_MODE_POSCTL,      0,                                  "Position Control", true },
    { PX4_CUSTOM_MAIN_MODE_OFFBOARD,    0,                                  "Offboard Control", true },
    { PX4_CUSTOM_MAIN_MODE_AUTO,        PX4_CUSTOM_SUB_MODE_AUTO_READY,     "Auto: Ready",       false },
    { PX4_CUSTOM_MAIN_MODE_AUTO,        PX4_CUSTOM_SUB_MODE_AUTO_TAKEOFF,   "Auto: Takeoff",       false },
    { PX4_CUSTOM_MAIN_MODE_AUTO,        PX4_CUSTOM_SUB_MODE_AUTO_LOITER,    "Auto: Pause",           true },
    { PX4_CUSTOM_MAIN_MODE_AUTO,        PX4_CUSTOM_SUB_MODE_AUTO_MISSION,   "Auto: Mission",          true },
    { PX4_CUSTOM_MAIN_MODE_AUTO,        PX4_CUSTOM_SUB_MODE_AUTO_RTL,       "Auto: Return To Land",   true },
    { PX4_CUSTOM_MAIN_MODE_AUTO,        PX4_CUSTOM_SUB_MODE_AUTO_LAND,      "Auto: Landing",          false },
};

QList<VehicleComponent*> PX4FirmwarePlugin::componentsForVehicle(AutoPilotPlugin* vehicle)
{
    Q_UNUSED(vehicle);

    return QList<VehicleComponent*>();
}

QStringList PX4FirmwarePlugin::flightModes(void)
{
    QStringList flightModes;

    // FIXME: fixed-wing/multi-rotor differences?

    for (size_t i=0; i<sizeof(rgModes2Name)/sizeof(rgModes2Name[0]); i++) {
        const struct Modes2Name* pModes2Name = &rgModes2Name[i];

        if (pModes2Name->canBeSet) {
            flightModes += pModes2Name->name;
        }
    }

    return flightModes;
}

QString PX4FirmwarePlugin::flightMode(uint8_t base_mode, uint32_t custom_mode) const
{
    QString flightMode = "Unknown";

    if (base_mode & MAV_MODE_FLAG_CUSTOM_MODE_ENABLED) {
        union px4_custom_mode px4_mode;
        px4_mode.data = custom_mode;

        // FIXME: fixed-wing/multi-rotor differences?

        bool found = false;
        for (size_t i=0; i<sizeof(rgModes2Name)/sizeof(rgModes2Name[0]); i++) {
            const struct Modes2Name* pModes2Name = &rgModes2Name[i];

            if (pModes2Name->main_mode == px4_mode.main_mode && pModes2Name->sub_mode == px4_mode.sub_mode) {
                flightMode = pModes2Name->name;
                found = true;
                break;
            }
        }

        if (!found) {
            qWarning() << "Unknown flight mode" << custom_mode;
        }
    } else {
        qWarning() << "PX4 Flight Stack flight mode without custom mode enabled?";
    }

    return flightMode;
}

bool PX4FirmwarePlugin::setFlightMode(const QString& flightMode, uint8_t* base_mode, uint32_t* custom_mode)
{
    *base_mode = 0;
    *custom_mode = 0;

    bool found = false;
    for (size_t i=0; i<sizeof(rgModes2Name)/sizeof(rgModes2Name[0]); i++) {
        const struct Modes2Name* pModes2Name = &rgModes2Name[i];

        if (flightMode.compare(pModes2Name->name, Qt::CaseInsensitive) == 0) {
            union px4_custom_mode px4_mode;

            px4_mode.data = 0;
            px4_mode.main_mode = pModes2Name->main_mode;
            px4_mode.sub_mode = pModes2Name->sub_mode;

            *base_mode = MAV_MODE_FLAG_CUSTOM_MODE_ENABLED;
            *custom_mode = px4_mode.data;

            found = true;
            break;
        }
    }

    if (!found) {
        qWarning() << "Unknown flight Mode" << flightMode;
    }

    return found;
}

int PX4FirmwarePlugin::manualControlReservedButtonCount(void)
{
    return 0;   // 0 buttons reserved for rc switch simulation
}

bool PX4FirmwarePlugin::isCapable(FirmwareCapabilities capabilities)
{
    qDebug() << (capabilities & (MavCmdPreflightStorageCapability | SetFlightModeCapability | PauseVehicleCapability)) << capabilities;
    return (capabilities & (MavCmdPreflightStorageCapability | SetFlightModeCapability | PauseVehicleCapability)) == capabilities;
}

void PX4FirmwarePlugin::initializeVehicle(Vehicle* vehicle)
{
    Q_UNUSED(vehicle);

    // PX4 Flight Stack doesn't need to do any extra work
}

bool PX4FirmwarePlugin::sendHomePositionToVehicle(void)
{
    // PX4 stack does not want home position sent in the first position.
    // Subsequent sequence numbers must be adjusted.
    return false;
}

void PX4FirmwarePlugin::addMetaDataToFact(QObject* parameterMetaData, Fact* fact, MAV_TYPE vehicleType)
{
    PX4ParameterMetaData* px4MetaData = qobject_cast<PX4ParameterMetaData*>(parameterMetaData);

    if (px4MetaData) {
        px4MetaData->addMetaDataToFact(fact, vehicleType);
    } else {
        qWarning() << "Internal error: pointer passed to PX4FirmwarePlugin::addMetaDataToFact not PX4ParameterMetaData";
    }
}

QList<MAV_CMD> PX4FirmwarePlugin::supportedMissionCommands(void)
{
    QList<MAV_CMD> list;

    list << MAV_CMD_NAV_WAYPOINT
         << MAV_CMD_NAV_LOITER_UNLIM << MAV_CMD_NAV_LOITER_TIME
         << MAV_CMD_NAV_LAND << MAV_CMD_NAV_TAKEOFF
         << MAV_CMD_DO_JUMP
         << MAV_CMD_DO_VTOL_TRANSITION << MAV_CMD_NAV_VTOL_TAKEOFF << MAV_CMD_NAV_VTOL_LAND
         << MAV_CMD_DO_DIGICAM_CONTROL
         << MAV_CMD_DO_SET_CAM_TRIGG_DIST
         << MAV_CMD_DO_SET_SERVO
         << MAV_CMD_DO_CHANGE_SPEED
         << MAV_CMD_NAV_PATHPLANNING;
    return list;
}

void PX4FirmwarePlugin::missionCommandOverrides(QString& commonJsonFilename, QString& fixedWingJsonFilename, QString& multiRotorJsonFilename) const
{
    // No overrides
    commonJsonFilename = QStringLiteral(":/json/PX4/MavCmdInfoCommon.json");
    fixedWingJsonFilename = QStringLiteral(":/json/PX4/MavCmdInfoFixedWing.json");
    multiRotorJsonFilename = QStringLiteral(":/json/PX4/MavCmdInfoMultiRotor.json");
}

QObject* PX4FirmwarePlugin::loadParameterMetaData(const QString& metaDataFile)
{
    PX4ParameterMetaData* metaData = new PX4ParameterMetaData;
    metaData->loadParameterFactMetaDataFile(metaDataFile);
    return metaData;
}

void PX4FirmwarePlugin::pauseVehicle(Vehicle* vehicle)
{
    vehicle->setFlightMode("Auto: Pause");
}
<commit_msg>Print PX4 link loss RTL<commit_after>/*=====================================================================

 QGroundControl Open Source Ground Control Station

 (c) 2009 - 2015 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>

 This file is part of the QGROUNDCONTROL project

 QGROUNDCONTROL is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 QGROUNDCONTROL is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.

 ======================================================================*/

/// @file
///     @author Don Gagne <don@thegagnes.com>

#include "PX4FirmwarePlugin.h"
#include "PX4ParameterMetaData.h"
#include "AutoPilotPlugins/PX4/PX4AutoPilotPlugin.h"    // FIXME: Hack

#include <QDebug>

enum PX4_CUSTOM_MAIN_MODE {
    PX4_CUSTOM_MAIN_MODE_MANUAL = 1,
    PX4_CUSTOM_MAIN_MODE_ALTCTL,
    PX4_CUSTOM_MAIN_MODE_POSCTL,
    PX4_CUSTOM_MAIN_MODE_AUTO,
    PX4_CUSTOM_MAIN_MODE_ACRO,
    PX4_CUSTOM_MAIN_MODE_OFFBOARD,
    PX4_CUSTOM_MAIN_MODE_STABILIZED,
    PX4_CUSTOM_MAIN_MODE_RATTITUDE
};

enum PX4_CUSTOM_SUB_MODE_AUTO {
    PX4_CUSTOM_SUB_MODE_AUTO_READY = 1,
    PX4_CUSTOM_SUB_MODE_AUTO_TAKEOFF,
    PX4_CUSTOM_SUB_MODE_AUTO_LOITER,
    PX4_CUSTOM_SUB_MODE_AUTO_MISSION,
    PX4_CUSTOM_SUB_MODE_AUTO_RTL,
    PX4_CUSTOM_SUB_MODE_AUTO_LAND,
    PX4_CUSTOM_SUB_MODE_AUTO_RTGS
};

union px4_custom_mode {
    struct {
        uint16_t reserved;
        uint8_t main_mode;
        uint8_t sub_mode;
    };
    uint32_t data;
    float data_float;
};

struct Modes2Name {
    uint8_t     main_mode;
    uint8_t     sub_mode;
    const char* name;       ///< Name for flight mode
    bool        canBeSet;   ///< true: Vehicle can be set to this flight mode
};

/// Tranlates from PX4 custom modes to flight mode names

static const struct Modes2Name rgModes2Name[] = {
    { PX4_CUSTOM_MAIN_MODE_MANUAL,      0,                                  "Manual",           true },
    { PX4_CUSTOM_MAIN_MODE_ACRO,        0,                                  "Acro",             true },
    { PX4_CUSTOM_MAIN_MODE_STABILIZED,  0,                                  "Stabilized",       true },
    { PX4_CUSTOM_MAIN_MODE_RATTITUDE,   0,                                  "Rattitude",        true },
    { PX4_CUSTOM_MAIN_MODE_ALTCTL,      0,                                  "Altitude Control", true },
    { PX4_CUSTOM_MAIN_MODE_POSCTL,      0,                                  "Position Control", true },
    { PX4_CUSTOM_MAIN_MODE_OFFBOARD,    0,                                  "Offboard Control", true },
    { PX4_CUSTOM_MAIN_MODE_AUTO,        PX4_CUSTOM_SUB_MODE_AUTO_READY,     "Auto: Ready",       false },
    { PX4_CUSTOM_MAIN_MODE_AUTO,        PX4_CUSTOM_SUB_MODE_AUTO_TAKEOFF,   "Auto: Takeoff",       false },
    { PX4_CUSTOM_MAIN_MODE_AUTO,        PX4_CUSTOM_SUB_MODE_AUTO_LOITER,    "Auto: Pause",           true },
    { PX4_CUSTOM_MAIN_MODE_AUTO,        PX4_CUSTOM_SUB_MODE_AUTO_MISSION,   "Auto: Mission",          true },
    { PX4_CUSTOM_MAIN_MODE_AUTO,        PX4_CUSTOM_SUB_MODE_AUTO_RTL,       "Auto: Return To Land",   true },
    { PX4_CUSTOM_MAIN_MODE_AUTO,        PX4_CUSTOM_SUB_MODE_AUTO_LAND,      "Auto: Landing",          false },
    { PX4_CUSTOM_MAIN_MODE_AUTO,        PX4_CUSTOM_SUB_MODE_AUTO_RTGS,      "Return, Link Loss", false },
};

QList<VehicleComponent*> PX4FirmwarePlugin::componentsForVehicle(AutoPilotPlugin* vehicle)
{
    Q_UNUSED(vehicle);

    return QList<VehicleComponent*>();
}

QStringList PX4FirmwarePlugin::flightModes(void)
{
    QStringList flightModes;

    // FIXME: fixed-wing/multi-rotor differences?

    for (size_t i=0; i<sizeof(rgModes2Name)/sizeof(rgModes2Name[0]); i++) {
        const struct Modes2Name* pModes2Name = &rgModes2Name[i];

        if (pModes2Name->canBeSet) {
            flightModes += pModes2Name->name;
        }
    }

    return flightModes;
}

QString PX4FirmwarePlugin::flightMode(uint8_t base_mode, uint32_t custom_mode) const
{
    QString flightMode = "Unknown";

    if (base_mode & MAV_MODE_FLAG_CUSTOM_MODE_ENABLED) {
        union px4_custom_mode px4_mode;
        px4_mode.data = custom_mode;

        // FIXME: fixed-wing/multi-rotor differences?

        bool found = false;
        for (size_t i=0; i<sizeof(rgModes2Name)/sizeof(rgModes2Name[0]); i++) {
            const struct Modes2Name* pModes2Name = &rgModes2Name[i];

            if (pModes2Name->main_mode == px4_mode.main_mode && pModes2Name->sub_mode == px4_mode.sub_mode) {
                flightMode = pModes2Name->name;
                found = true;
                break;
            }
        }

        if (!found) {
            qWarning() << "Unknown flight mode" << custom_mode;
        }
    } else {
        qWarning() << "PX4 Flight Stack flight mode without custom mode enabled?";
    }

    return flightMode;
}

bool PX4FirmwarePlugin::setFlightMode(const QString& flightMode, uint8_t* base_mode, uint32_t* custom_mode)
{
    *base_mode = 0;
    *custom_mode = 0;

    bool found = false;
    for (size_t i=0; i<sizeof(rgModes2Name)/sizeof(rgModes2Name[0]); i++) {
        const struct Modes2Name* pModes2Name = &rgModes2Name[i];

        if (flightMode.compare(pModes2Name->name, Qt::CaseInsensitive) == 0) {
            union px4_custom_mode px4_mode;

            px4_mode.data = 0;
            px4_mode.main_mode = pModes2Name->main_mode;
            px4_mode.sub_mode = pModes2Name->sub_mode;

            *base_mode = MAV_MODE_FLAG_CUSTOM_MODE_ENABLED;
            *custom_mode = px4_mode.data;

            found = true;
            break;
        }
    }

    if (!found) {
        qWarning() << "Unknown flight Mode" << flightMode;
    }

    return found;
}

int PX4FirmwarePlugin::manualControlReservedButtonCount(void)
{
    return 0;   // 0 buttons reserved for rc switch simulation
}

bool PX4FirmwarePlugin::isCapable(FirmwareCapabilities capabilities)
{
    qDebug() << (capabilities & (MavCmdPreflightStorageCapability | SetFlightModeCapability | PauseVehicleCapability)) << capabilities;
    return (capabilities & (MavCmdPreflightStorageCapability | SetFlightModeCapability | PauseVehicleCapability)) == capabilities;
}

void PX4FirmwarePlugin::initializeVehicle(Vehicle* vehicle)
{
    Q_UNUSED(vehicle);

    // PX4 Flight Stack doesn't need to do any extra work
}

bool PX4FirmwarePlugin::sendHomePositionToVehicle(void)
{
    // PX4 stack does not want home position sent in the first position.
    // Subsequent sequence numbers must be adjusted.
    return false;
}

void PX4FirmwarePlugin::addMetaDataToFact(QObject* parameterMetaData, Fact* fact, MAV_TYPE vehicleType)
{
    PX4ParameterMetaData* px4MetaData = qobject_cast<PX4ParameterMetaData*>(parameterMetaData);

    if (px4MetaData) {
        px4MetaData->addMetaDataToFact(fact, vehicleType);
    } else {
        qWarning() << "Internal error: pointer passed to PX4FirmwarePlugin::addMetaDataToFact not PX4ParameterMetaData";
    }
}

QList<MAV_CMD> PX4FirmwarePlugin::supportedMissionCommands(void)
{
    QList<MAV_CMD> list;

    list << MAV_CMD_NAV_WAYPOINT
         << MAV_CMD_NAV_LOITER_UNLIM << MAV_CMD_NAV_LOITER_TIME
         << MAV_CMD_NAV_LAND << MAV_CMD_NAV_TAKEOFF
         << MAV_CMD_DO_JUMP
         << MAV_CMD_DO_VTOL_TRANSITION << MAV_CMD_NAV_VTOL_TAKEOFF << MAV_CMD_NAV_VTOL_LAND
         << MAV_CMD_DO_DIGICAM_CONTROL
         << MAV_CMD_DO_SET_CAM_TRIGG_DIST
         << MAV_CMD_DO_SET_SERVO
         << MAV_CMD_DO_CHANGE_SPEED
         << MAV_CMD_NAV_PATHPLANNING;
    return list;
}

void PX4FirmwarePlugin::missionCommandOverrides(QString& commonJsonFilename, QString& fixedWingJsonFilename, QString& multiRotorJsonFilename) const
{
    // No overrides
    commonJsonFilename = QStringLiteral(":/json/PX4/MavCmdInfoCommon.json");
    fixedWingJsonFilename = QStringLiteral(":/json/PX4/MavCmdInfoFixedWing.json");
    multiRotorJsonFilename = QStringLiteral(":/json/PX4/MavCmdInfoMultiRotor.json");
}

QObject* PX4FirmwarePlugin::loadParameterMetaData(const QString& metaDataFile)
{
    PX4ParameterMetaData* metaData = new PX4ParameterMetaData;
    metaData->loadParameterFactMetaDataFile(metaDataFile);
    return metaData;
}

void PX4FirmwarePlugin::pauseVehicle(Vehicle* vehicle)
{
    vehicle->setFlightMode("Auto: Pause");
}
<|endoftext|>


<commit_before>/*
 +----------------------------------------------------------------------+
 | Swoole                                                               |
 +----------------------------------------------------------------------+
 | Copyright (c) 2012-2015 The Swoole Group                             |
 +----------------------------------------------------------------------+
 | This source file is subject to version 2.0 of the Apache license,    |
 | that is bundled with this package in the file LICENSE, and is        |
 | available through the world-wide-web at the following url:           |
 | http://www.apache.org/licenses/LICENSE-2.0.html                      |
 | If you did not receive a copy of the Apache2.0 license and are unable|
 | to obtain it through the world-wide-web, please send a note to       |
 | license@swoole.com so we can mail you a copy immediately.            |
 +----------------------------------------------------------------------+
 | Author: Tianfeng Han  <mikan.tenny@gmail.com>                        |
 +----------------------------------------------------------------------+
 */

#include "php_swoole.h"
#ifdef SW_COROUTINE
#include "swoole_coroutine.h"
#endif

using namespace swoole;

enum swoole_timer_type
{
    SW_TIMER_TICK, SW_TIMER_AFTER,
};

typedef struct _swTimer_callback
{
    int type;
    int interval;
    zval* callback;
    zend_fcall_info_cache *fci_cache;
    zval* data;
    zval _callback;
    zend_fcall_info_cache _fci_cache;
    zval _data;
} swTimer_callback;

static int php_swoole_del_timer(swTimer_node *tnode);

void php_swoole_clear_all_timer()
{
    if (!SwooleG.timer.map)
    {
        return;
    }
    uint64_t timer_id;
    //kill user process
    while (1)
    {
        swTimer_node *tnode = (swTimer_node *) swHashMap_each_int(SwooleG.timer.map, &timer_id);
        if (tnode == NULL)
        {
            break;
        }
        if (tnode->type != SW_TIMER_TYPE_PHP)
        {
            continue;
        }
        php_swoole_del_timer(tnode);
        swTimer_del(&SwooleG.timer, tnode);
    }
}

long php_swoole_add_timer(long ms, zval *callback, zval *param, int persistent)
{
    if (ms <= 0)
    {
        swoole_php_fatal_error(E_WARNING, "Timer must be greater than 0");
        return SW_ERR;
    }

    if (SwooleG.serv)
    {
        if (swIsTaskWorker() && SwooleG.serv->task_async == 1)
        {
            goto _create_reactor;
        }
    }
    else
    {
        _create_reactor: php_swoole_check_reactor();
    }

    swTimer_callback *cb = (swTimer_callback *) emalloc(sizeof(swTimer_callback));
    char *func_name = NULL;
    if (!sw_zend_is_callable_ex(callback, NULL, 0, &func_name, NULL, &cb->_fci_cache, NULL))
    {
        swoole_php_fatal_error(E_ERROR, "function '%s' is not callable", func_name);
        return SW_ERR;
    }
    efree(func_name);

    cb->_callback = *callback;
    cb->callback = &cb->_callback;
    cb->fci_cache = &cb->_fci_cache;
    if (param)
    {
        cb->_data = *param;
        cb->data = &cb->_data;
    }
    else
    {
        cb->data = NULL;
    }

    swTimerCallback timer_func;
    if (persistent)
    {
        cb->type = SW_TIMER_TICK;
        timer_func = php_swoole_onInterval;
    }
    else
    {
        cb->type = SW_TIMER_AFTER;
        timer_func = php_swoole_onTimeout;
    }

    Z_TRY_ADDREF_P(cb->callback);
    if (cb->data)
    {
        Z_TRY_ADDREF_P(cb->data);
    }

    swTimer_node *tnode = swTimer_add(&SwooleG.timer, ms, persistent, cb, timer_func);
    if (tnode == NULL)
    {
        swoole_php_fatal_error(E_WARNING, "add timer failed.");
        return SW_ERR;
    }
    else
    {
        tnode->type = SW_TIMER_TYPE_PHP;
        return tnode->id;
    }
}

static int php_swoole_del_timer(swTimer_node *tnode)
{
    swTimer_callback *cb = (swTimer_callback *) tnode->data;
    if (!cb)
    {
        return SW_ERR;
    }
    if (cb->callback)
    {
        zval_ptr_dtor(cb->callback);
    }
    if (cb->data)
    {
        zval_ptr_dtor(cb->data);
    }
    efree(cb);
    return SW_OK;
}

void php_swoole_onTimeout(swTimer *timer, swTimer_node *tnode)
{
    swTimer_callback *cb = (swTimer_callback *) tnode->data;
    zval args[1];
    int argc = 0;

    if (cb->data)
    {
        argc = 1;
        args[0] = *cb->data;
    }

    if (SwooleG.enable_coroutine)
    {
        if (PHPCoroutine::create(cb->fci_cache, argc, args) < 0)
        {
            swoole_php_fatal_error(E_WARNING, "create onTimer coroutine error.");
        }
    }
    else
    {
        zval _retval, *retval = &_retval;
        if (sw_call_user_function_fast_ex(NULL, cb->fci_cache, retval, argc, args) == FAILURE)
        {
            swoole_php_fatal_error(E_WARNING, "onTimeout handler error.");
        }
        zval_ptr_dtor(retval);
    }

    php_swoole_del_timer(tnode);

    if (UNEXPECTED(EG(exception)))
    {
        zend_exception_error(EG(exception), E_ERROR);
    }
}

void php_swoole_onInterval(swTimer *timer, swTimer_node *tnode)
{
    zval *ztimer_id;
    swTimer_callback *cb = (swTimer_callback *) tnode->data;

    SW_MAKE_STD_ZVAL(ztimer_id);
    ZVAL_LONG(ztimer_id, tnode->id);

    zval args[2];
    int argc = 1;
    args[0] = *ztimer_id;
    if (cb->data)
    {
        argc = 2;
        Z_TRY_ADDREF_P(cb->data);
        args[1] = *cb->data;
    }

    if (SwooleG.enable_coroutine)
    {
        if (PHPCoroutine::create(cb->fci_cache, argc, args) < 0)
        {
            swoole_php_fatal_error(E_WARNING, "create onInterval coroutine error.");
            return;
        }
    }
    else
    {
        zval _retval, *retval = &_retval;
        if (sw_call_user_function_fast_ex(NULL, cb->fci_cache, retval, argc, args) == FAILURE)
        {
            swoole_php_fatal_error(E_WARNING, "onInterval handler error.");
        }
        zval_ptr_dtor(retval);
    }

    if (tnode->remove)
    {
        php_swoole_del_timer(tnode);
    }

    if (UNEXPECTED(EG(exception)))
    {
        zend_exception_error(EG(exception), E_ERROR);
    }
}

PHP_FUNCTION(swoole_timer_tick)
{
    zend_long after_ms;
    zval *callback;
    zval *param = NULL;

    if (zend_parse_parameters(ZEND_NUM_ARGS(), "lz|z", &after_ms, &callback, &param) == FAILURE)
    {
        RETURN_FALSE;
    }

    long timer_id = php_swoole_add_timer(after_ms, callback, param, 1);
    if (timer_id < 0)
    {
        RETURN_FALSE;
    }
    else
    {
        RETURN_LONG(timer_id);
    }
}

PHP_FUNCTION(swoole_timer_after)
{
    long after_ms;
    zval *callback;
    zval *param = NULL;

    if (zend_parse_parameters(ZEND_NUM_ARGS(), "lz|z", &after_ms, &callback, &param) == FAILURE)
    {
        RETURN_FALSE;
    }

    long timer_id = php_swoole_add_timer(after_ms, callback, param, 0);
    if (timer_id < 0)
    {
        RETURN_FALSE;
    }
    else
    {
        RETURN_LONG(timer_id);
    }
}

PHP_FUNCTION(swoole_timer_clear)
{
    if (!SwooleG.timer.initialized)
    {
        swoole_php_error(E_WARNING, "no timer");
        RETURN_FALSE;
    }

    long id;
    if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &id) == FAILURE)
    {
        RETURN_FALSE;
    }

    swTimer_node *tnode = swTimer_get(&SwooleG.timer, id);
    if (tnode == NULL)
    {
        swoole_php_error(E_WARNING, "timer#%ld is not found.", id);
        RETURN_FALSE;
    }
    if (tnode->remove)
    {
        RETURN_FALSE;
    }
    //current timer, cannot remove here.
    if (SwooleG.timer._current_id > 0 && tnode->id == SwooleG.timer._current_id)
    {
        tnode->remove = 1;
        RETURN_TRUE;
    }
    //remove timer
    if (php_swoole_del_timer(tnode) < 0)
    {
        RETURN_FALSE;
    }
    if (swTimer_del(&SwooleG.timer, tnode) == SW_FALSE)
    {
        RETURN_FALSE;
    }
    else
    {
        RETURN_TRUE;
    }
}

PHP_FUNCTION(swoole_timer_exists)
{
    if (!SwooleG.timer.set)
    {
        swoole_php_error(E_WARNING, "no timer");
        RETURN_FALSE;
    }

    long id;
    if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &id) == FAILURE)
    {
        RETURN_FALSE;
    }

    swTimer_node *tnode = swTimer_get(&SwooleG.timer, id);
    if (tnode == NULL)
    {
       RETURN_FALSE;
    }
    if (tnode->remove)
    {
        RETURN_FALSE;
    }
    RETURN_TRUE;
}
<commit_msg>fix #2274<commit_after>/*
 +----------------------------------------------------------------------+
 | Swoole                                                               |
 +----------------------------------------------------------------------+
 | Copyright (c) 2012-2015 The Swoole Group                             |
 +----------------------------------------------------------------------+
 | This source file is subject to version 2.0 of the Apache license,    |
 | that is bundled with this package in the file LICENSE, and is        |
 | available through the world-wide-web at the following url:           |
 | http://www.apache.org/licenses/LICENSE-2.0.html                      |
 | If you did not receive a copy of the Apache2.0 license and are unable|
 | to obtain it through the world-wide-web, please send a note to       |
 | license@swoole.com so we can mail you a copy immediately.            |
 +----------------------------------------------------------------------+
 | Author: Tianfeng Han  <mikan.tenny@gmail.com>                        |
 +----------------------------------------------------------------------+
 */

#include "php_swoole.h"
#ifdef SW_COROUTINE
#include "swoole_coroutine.h"
#endif

using namespace swoole;

enum swoole_timer_type
{
    SW_TIMER_TICK, SW_TIMER_AFTER,
};

typedef struct _swTimer_callback
{
    int type;
    int interval;
    zval* callback;
    zend_fcall_info_cache *fci_cache;
    zval* data;
    zval _callback;
    zend_fcall_info_cache _fci_cache;
    zval _data;
} swTimer_callback;

static int php_swoole_del_timer(swTimer_node *tnode);

void php_swoole_clear_all_timer()
{
    if (!SwooleG.timer.map)
    {
        return;
    }
    uint64_t timer_id;
    //kill user process
    while (1)
    {
        swTimer_node *tnode = (swTimer_node *) swHashMap_each_int(SwooleG.timer.map, &timer_id);
        if (tnode == NULL)
        {
            break;
        }
        if (tnode->type != SW_TIMER_TYPE_PHP)
        {
            continue;
        }
        php_swoole_del_timer(tnode);
        swTimer_del(&SwooleG.timer, tnode);
    }
}

long php_swoole_add_timer(long ms, zval *callback, zval *param, int persistent)
{
    if (ms <= 0)
    {
        swoole_php_fatal_error(E_WARNING, "Timer must be greater than 0");
        return SW_ERR;
    }

    if (SwooleG.serv)
    {
        if (swIsTaskWorker() && SwooleG.serv->task_async == 1)
        {
            goto _create_reactor;
        }
        if (swIsUserWorker())
        {
            goto _create_reactor;
        }
    }
    else
    {
        _create_reactor: php_swoole_check_reactor();
    }

    swTimer_callback *cb = (swTimer_callback *) emalloc(sizeof(swTimer_callback));
    char *func_name = NULL;
    if (!sw_zend_is_callable_ex(callback, NULL, 0, &func_name, NULL, &cb->_fci_cache, NULL))
    {
        swoole_php_fatal_error(E_ERROR, "function '%s' is not callable", func_name);
        return SW_ERR;
    }
    efree(func_name);

    cb->_callback = *callback;
    cb->callback = &cb->_callback;
    cb->fci_cache = &cb->_fci_cache;
    if (param)
    {
        cb->_data = *param;
        cb->data = &cb->_data;
    }
    else
    {
        cb->data = NULL;
    }

    swTimerCallback timer_func;
    if (persistent)
    {
        cb->type = SW_TIMER_TICK;
        timer_func = php_swoole_onInterval;
    }
    else
    {
        cb->type = SW_TIMER_AFTER;
        timer_func = php_swoole_onTimeout;
    }

    Z_TRY_ADDREF_P(cb->callback);
    if (cb->data)
    {
        Z_TRY_ADDREF_P(cb->data);
    }

    swTimer_node *tnode = swTimer_add(&SwooleG.timer, ms, persistent, cb, timer_func);
    if (tnode == NULL)
    {
        swoole_php_fatal_error(E_WARNING, "add timer failed.");
        return SW_ERR;
    }
    else
    {
        tnode->type = SW_TIMER_TYPE_PHP;
        return tnode->id;
    }
}

static int php_swoole_del_timer(swTimer_node *tnode)
{
    swTimer_callback *cb = (swTimer_callback *) tnode->data;
    if (!cb)
    {
        return SW_ERR;
    }
    if (cb->callback)
    {
        zval_ptr_dtor(cb->callback);
    }
    if (cb->data)
    {
        zval_ptr_dtor(cb->data);
    }
    efree(cb);
    return SW_OK;
}

void php_swoole_onTimeout(swTimer *timer, swTimer_node *tnode)
{
    swTimer_callback *cb = (swTimer_callback *) tnode->data;
    zval args[1];
    int argc = 0;

    if (cb->data)
    {
        argc = 1;
        args[0] = *cb->data;
    }

    if (SwooleG.enable_coroutine)
    {
        if (PHPCoroutine::create(cb->fci_cache, argc, args) < 0)
        {
            swoole_php_fatal_error(E_WARNING, "create onTimer coroutine error.");
        }
    }
    else
    {
        zval _retval, *retval = &_retval;
        if (sw_call_user_function_fast_ex(NULL, cb->fci_cache, retval, argc, args) == FAILURE)
        {
            swoole_php_fatal_error(E_WARNING, "onTimeout handler error.");
        }
        zval_ptr_dtor(retval);
    }

    php_swoole_del_timer(tnode);

    if (UNEXPECTED(EG(exception)))
    {
        zend_exception_error(EG(exception), E_ERROR);
    }
}

void php_swoole_onInterval(swTimer *timer, swTimer_node *tnode)
{
    zval *ztimer_id;
    swTimer_callback *cb = (swTimer_callback *) tnode->data;

    SW_MAKE_STD_ZVAL(ztimer_id);
    ZVAL_LONG(ztimer_id, tnode->id);

    zval args[2];
    int argc = 1;
    args[0] = *ztimer_id;
    if (cb->data)
    {
        argc = 2;
        Z_TRY_ADDREF_P(cb->data);
        args[1] = *cb->data;
    }

    if (SwooleG.enable_coroutine)
    {
        if (PHPCoroutine::create(cb->fci_cache, argc, args) < 0)
        {
            swoole_php_fatal_error(E_WARNING, "create onInterval coroutine error.");
            return;
        }
    }
    else
    {
        zval _retval, *retval = &_retval;
        if (sw_call_user_function_fast_ex(NULL, cb->fci_cache, retval, argc, args) == FAILURE)
        {
            swoole_php_fatal_error(E_WARNING, "onInterval handler error.");
        }
        zval_ptr_dtor(retval);
    }

    if (tnode->remove)
    {
        php_swoole_del_timer(tnode);
    }

    if (UNEXPECTED(EG(exception)))
    {
        zend_exception_error(EG(exception), E_ERROR);
    }
}

PHP_FUNCTION(swoole_timer_tick)
{
    zend_long after_ms;
    zval *callback;
    zval *param = NULL;

    if (zend_parse_parameters(ZEND_NUM_ARGS(), "lz|z", &after_ms, &callback, &param) == FAILURE)
    {
        RETURN_FALSE;
    }

    long timer_id = php_swoole_add_timer(after_ms, callback, param, 1);
    if (timer_id < 0)
    {
        RETURN_FALSE;
    }
    else
    {
        RETURN_LONG(timer_id);
    }
}

PHP_FUNCTION(swoole_timer_after)
{
    long after_ms;
    zval *callback;
    zval *param = NULL;

    if (zend_parse_parameters(ZEND_NUM_ARGS(), "lz|z", &after_ms, &callback, &param) == FAILURE)
    {
        RETURN_FALSE;
    }

    long timer_id = php_swoole_add_timer(after_ms, callback, param, 0);
    if (timer_id < 0)
    {
        RETURN_FALSE;
    }
    else
    {
        RETURN_LONG(timer_id);
    }
}

PHP_FUNCTION(swoole_timer_clear)
{
    if (!SwooleG.timer.initialized)
    {
        swoole_php_error(E_WARNING, "no timer");
        RETURN_FALSE;
    }

    long id;
    if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &id) == FAILURE)
    {
        RETURN_FALSE;
    }

    swTimer_node *tnode = swTimer_get(&SwooleG.timer, id);
    if (tnode == NULL)
    {
        swoole_php_error(E_WARNING, "timer#%ld is not found.", id);
        RETURN_FALSE;
    }
    if (tnode->remove)
    {
        RETURN_FALSE;
    }
    //current timer, cannot remove here.
    if (SwooleG.timer._current_id > 0 && tnode->id == SwooleG.timer._current_id)
    {
        tnode->remove = 1;
        RETURN_TRUE;
    }
    //remove timer
    if (php_swoole_del_timer(tnode) < 0)
    {
        RETURN_FALSE;
    }
    if (swTimer_del(&SwooleG.timer, tnode) == SW_FALSE)
    {
        RETURN_FALSE;
    }
    else
    {
        RETURN_TRUE;
    }
}

PHP_FUNCTION(swoole_timer_exists)
{
    if (!SwooleG.timer.set)
    {
        swoole_php_error(E_WARNING, "no timer");
        RETURN_FALSE;
    }

    long id;
    if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &id) == FAILURE)
    {
        RETURN_FALSE;
    }

    swTimer_node *tnode = swTimer_get(&SwooleG.timer, id);
    if (tnode == NULL)
    {
       RETURN_FALSE;
    }
    if (tnode->remove)
    {
        RETURN_FALSE;
    }
    RETURN_TRUE;
}
<|endoftext|>


<commit_before>/*
 * Website:
 *      https://github.com/wo3kie/dojo
 *
 * Author:
 *      Lukasz Czerwinski
 */

#ifndef CXX_DOJO_OUTPUT_HPP
#define CXX_DOJO_OUTPUT_HPP

#include <cassert>
#include <array>
#include <iostream>
#include <list>
#include <map>
#include <set>
#include <sstream>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>

template< typename Iterator >
std::ostream & printImpl(
    std::ostream & out,
    char const beginning,
    Iterator begin,
    char const separator,
    Iterator const end,
    char const ending
){
    out << beginning;

    if( begin != end ){
        out << * begin;

        while( ++ begin != end ){
            out << separator << * begin;
        }
    }

    return out << ending;
}

template< typename Iterator >
std::ostream & printVector( std::ostream & out, Iterator begin, Iterator end ){
    return printImpl( out, '[', begin, ',', end, ']' );
}

template< typename T >
std::ostream & operator<<( std::ostream & out, std::vector< T > const & v ){
    return printVector( out, v.begin(), v.end() );
}

template< typename T, std::size_t Size >
std::ostream & operator<<( std::ostream & out, std::array< T, Size > const & a ){
    return printVector( out, a.begin(), a.end() );
}

template< typename Iterator >
std::ostream & printList( std::ostream & out, Iterator begin, Iterator end ){
    return printImpl( out, '(', begin, ',', end, ')' );
}

template< typename T >
std::ostream & operator<<( std::ostream & out, std::list< T > const & v ){
    return printList( out, v.begin(), v.end() );
}

template< typename T1, typename T2 >
std::ostream & printPair( std::ostream & out, std::pair< T1, T2 > const & p ){
    return out << '{' << p.first << ',' << p.second << '}';
}

template< typename T1, typename T2 >
std::ostream & operator<<( std::ostream & out, std::pair< T1, T2 > const & p ){
    return printPair( out, p );
}

template< typename Iterator >
std::ostream & printMap( std::ostream & out, Iterator begin, Iterator end ){
    return printImpl( out, '{', begin, ',', end, '}' );
}

template< typename T1, typename T2 >
std::ostream & operator<<( std::ostream & out, std::map< T1, T2 > const & m ){
    return printMap( out, m.begin(), m.end() );
}

template< typename Iterator >
std::ostream & printSet( std::ostream & out, Iterator begin, Iterator end ){
    return printImpl( out, '{', begin, ',', end, '}' );
}

template< typename T >
std::ostream & operator<<( std::ostream & out, std::set< T > const & s ){
    return printSet( out, s.begin(), s.end() );
}

template< typename T1, typename T2 >
std::ostream & operator<<( std::ostream & out, std::unordered_map< T1, T2 > const & u ){
    return printMap( out, u.begin(), u.end() );
}

template< typename T >
std::ostream & operator<<( std::ostream & out, std::unordered_set< T > const & s ){
    return printSet( out, s.begin(), s.end() );
}

void output_tests()
{
    {
        std::ostringstream oss; oss << std::vector< int >();
        assert( std::string( "[]" ) == oss.str() );
    }
    {
        std::ostringstream oss; oss << std::vector< int >{ 1 };
        assert( std::string( "[1]" ) == oss.str() );
    }
    {
        std::ostringstream oss; oss << std::vector< int >{ 1, 2 };
        assert( std::string( "[1,2]" ) == oss.str() );
    }
    {
        std::ostringstream oss; oss << std::vector< int >{ 1, 2, 3 };
        assert( std::string( "[1,2,3]" ) == oss.str() );
    }

    {
        std::ostringstream oss; oss << std::array< int, 0 >();
        assert( std::string( "[]" ) == oss.str() );
    }
    {
        std::ostringstream oss; oss << std::array< int, 1 >{ 1 };
        assert( std::string( "[1]" ) == oss.str() );
    }
    {
        std::ostringstream oss; oss << std::array< int, 2 >{ 1, 2 };
        assert( std::string( "[1,2]" ) == oss.str() );
    }
    {
        std::ostringstream oss; oss << std::array< int, 3 >{ 1, 2, 3 };
        assert( std::string( "[1,2,3]" ) == oss.str() );
    }

    {
        std::ostringstream oss; oss << std::list< int >();
        assert( std::string( "()" ) == oss.str() );
    }
    {
        std::ostringstream oss; oss << std::list< int >{ 1 };
        assert( std::string( "(1)" ) == oss.str() );
    }
    {
        std::ostringstream oss; oss << std::list< int >{ 1, 2 };
        assert( std::string( "(1,2)" ) == oss.str() );
    }
    {
        std::ostringstream oss; oss << std::list< int >{ 1, 2, 3 };
        assert( std::string( "(1,2,3)" ) == oss.str() );
    }

    {
        std::ostringstream oss; oss << std::make_pair( 1, 2 );
        assert( std::string( "{1,2}" ) == oss.str() );
    }

    {
        std::ostringstream oss; oss << std::map< int, int >();
        assert( std::string( "{}" ) == oss.str() );
    }
    {
        std::ostringstream oss; oss << std::map< int, int >{ { 1 , 2 } };
        assert( std::string( "{{1,2}}" ) == oss.str() );
    }
    {
        std::ostringstream oss; oss << std::map< int, int >{ { 1 , 2 }, { 3, 4 } };
        assert( std::string( "{{1,2},{3,4}}" ) == oss.str() );
    }
    {
        std::ostringstream oss; oss << std::map< int, int >{ { 1 , 2 }, { 3, 4 }, { 5, 6 } };
        assert( std::string( "{{1,2},{3,4},{5,6}}" ) == oss.str() );
    }

    {
        std::ostringstream oss; oss << std::set< int >();
        assert( std::string( "{}" ) == oss.str() );
    }
    {
        std::ostringstream oss; oss << std::set< int >{ 1 };
        assert( std::string( "{1}" ) == oss.str() );
    }
    {
        std::ostringstream oss; oss << std::set< int >{ 1, 2 };
        assert( std::string( "{1,2}" ) == oss.str() );
    }
    {
        std::ostringstream oss; oss << std::set< int >{ 1, 2, 3 };
        assert( std::string( "{1,2,3}" ) == oss.str() );
    }

    {
        std::ostringstream oss; oss << std::unordered_map< int, int >();
        assert( std::string( "{}" ) == oss.str() );
    }
    {
        std::ostringstream oss; oss << std::unordered_map< int, int >{ { 1 , 2 } };
        assert( std::string( "{{1,2}}" ) == oss.str() );
    }

    {
        std::ostringstream oss; oss << std::unordered_set< int >();
        assert( std::string( "{}" ) == oss.str() );
    }
    {
        std::ostringstream oss; oss << std::unordered_set< int >{ 1 };
        assert( std::string( "{1}" ) == oss.str() );
    }
}

#endif

<commit_msg>output<commit_after>/*
 * Website:
 *      https://github.com/wo3kie/dojo
 *
 * Author:
 *      Lukasz Czerwinski
 */

#ifndef CXX_DOJO_OUTPUT_HPP
#define CXX_DOJO_OUTPUT_HPP

#include <cassert>
#include <array>
#include <iostream>
#include <list>
#include <map>
#include <set>
#include <sstream>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>

template< typename Iterator >
std::ostream & printImpl(
    std::ostream & out,
    char const beginning,
    Iterator begin,
    char const * const separator,
    Iterator const end,
    char const ending
){
    out << beginning;

    if( begin != end ){
        out << * begin;

        while( ++ begin != end ){
            out << separator << * begin;
        }
    }

    return out << ending;
}

template< typename Iterator >
std::ostream & printVector( std::ostream & out, Iterator begin, Iterator end ){
    return printImpl( out, '[', begin, ", ", end, ']' );
}

template< typename T >
std::ostream & operator<<( std::ostream & out, std::vector< T > const & v ){
    return printVector( out, v.begin(), v.end() );
}

template< typename T, std::size_t Size >
std::ostream & operator<<( std::ostream & out, std::array< T, Size > const & a ){
    return printVector( out, a.begin(), a.end() );
}

template< typename Iterator >
std::ostream & printList( std::ostream & out, Iterator begin, Iterator end ){
    return printImpl( out, '(', begin, ", ", end, ')' );
}

template< typename T >
std::ostream & operator<<( std::ostream & out, std::list< T > const & v ){
    return printList( out, v.begin(), v.end() );
}

template< typename T1, typename T2 >
std::ostream & printPair( std::ostream & out, std::pair< T1, T2 > const & p ){
    return out << '{' << p.first << ", " << p.second << '}';
}

template< typename T1, typename T2 >
std::ostream & operator<<( std::ostream & out, std::pair< T1, T2 > const & p ){
    return printPair( out, p );
}

template< typename Iterator >
std::ostream & printMap( std::ostream & out, Iterator begin, Iterator end ){
    return printImpl( out, '{', begin, ", ", end, '}' );
}

template< typename T1, typename T2 >
std::ostream & operator<<( std::ostream & out, std::map< T1, T2 > const & m ){
    return printMap( out, m.begin(), m.end() );
}

template< typename Iterator >
std::ostream & printSet( std::ostream & out, Iterator begin, Iterator end ){
    return printImpl( out, '{', begin, ", ", end, '}' );
}

template< typename T >
std::ostream & operator<<( std::ostream & out, std::set< T > const & s ){
    return printSet( out, s.begin(), s.end() );
}

template< typename T1, typename T2 >
std::ostream & operator<<( std::ostream & out, std::unordered_map< T1, T2 > const & u ){
    return printMap( out, u.begin(), u.end() );
}

template< typename T >
std::ostream & operator<<( std::ostream & out, std::unordered_set< T > const & s ){
    return printSet( out, s.begin(), s.end() );
}

void output_tests()
{
    {
        std::ostringstream oss; oss << std::vector< int >();
        assert( std::string( "[]" ) == oss.str() );
    }
    {
        std::ostringstream oss; oss << std::vector< int >{ 1 };
        assert( std::string( "[1]" ) == oss.str() );
    }
    {
        std::ostringstream oss; oss << std::vector< int >{ 1, 2 };
        assert( std::string( "[1,2]" ) == oss.str() );
    }
    {
        std::ostringstream oss; oss << std::vector< int >{ 1, 2, 3 };
        assert( std::string( "[1,2,3]" ) == oss.str() );
    }

    {
        std::ostringstream oss; oss << std::array< int, 0 >();
        assert( std::string( "[]" ) == oss.str() );
    }
    {
        std::ostringstream oss; oss << std::array< int, 1 >{ 1 };
        assert( std::string( "[1]" ) == oss.str() );
    }
    {
        std::ostringstream oss; oss << std::array< int, 2 >{ 1, 2 };
        assert( std::string( "[1,2]" ) == oss.str() );
    }
    {
        std::ostringstream oss; oss << std::array< int, 3 >{ 1, 2, 3 };
        assert( std::string( "[1,2,3]" ) == oss.str() );
    }

    {
        std::ostringstream oss; oss << std::list< int >();
        assert( std::string( "()" ) == oss.str() );
    }
    {
        std::ostringstream oss; oss << std::list< int >{ 1 };
        assert( std::string( "(1)" ) == oss.str() );
    }
    {
        std::ostringstream oss; oss << std::list< int >{ 1, 2 };
        assert( std::string( "(1,2)" ) == oss.str() );
    }
    {
        std::ostringstream oss; oss << std::list< int >{ 1, 2, 3 };
        assert( std::string( "(1,2,3)" ) == oss.str() );
    }

    {
        std::ostringstream oss; oss << std::make_pair( 1, 2 );
        assert( std::string( "{1,2}" ) == oss.str() );
    }

    {
        std::ostringstream oss; oss << std::map< int, int >();
        assert( std::string( "{}" ) == oss.str() );
    }
    {
        std::ostringstream oss; oss << std::map< int, int >{ { 1 , 2 } };
        assert( std::string( "{{1,2}}" ) == oss.str() );
    }
    {
        std::ostringstream oss; oss << std::map< int, int >{ { 1 , 2 }, { 3, 4 } };
        assert( std::string( "{{1,2},{3,4}}" ) == oss.str() );
    }
    {
        std::ostringstream oss; oss << std::map< int, int >{ { 1 , 2 }, { 3, 4 }, { 5, 6 } };
        assert( std::string( "{{1,2},{3,4},{5,6}}" ) == oss.str() );
    }

    {
        std::ostringstream oss; oss << std::set< int >();
        assert( std::string( "{}" ) == oss.str() );
    }
    {
        std::ostringstream oss; oss << std::set< int >{ 1 };
        assert( std::string( "{1}" ) == oss.str() );
    }
    {
        std::ostringstream oss; oss << std::set< int >{ 1, 2 };
        assert( std::string( "{1,2}" ) == oss.str() );
    }
    {
        std::ostringstream oss; oss << std::set< int >{ 1, 2, 3 };
        assert( std::string( "{1,2,3}" ) == oss.str() );
    }

    {
        std::ostringstream oss; oss << std::unordered_map< int, int >();
        assert( std::string( "{}" ) == oss.str() );
    }
    {
        std::ostringstream oss; oss << std::unordered_map< int, int >{ { 1 , 2 } };
        assert( std::string( "{{1,2}}" ) == oss.str() );
    }

    {
        std::ostringstream oss; oss << std::unordered_set< int >();
        assert( std::string( "{}" ) == oss.str() );
    }
    {
        std::ostringstream oss; oss << std::unordered_set< int >{ 1 };
        assert( std::string( "{1}" ) == oss.str() );
    }
}

#endif
<|endoftext|>


<commit_before>// Copyright (c) 2009 Roman Neuhauser
// Distributed under the MIT license (see LICENSE file)
// vim: sw=4 sts=4 et fdm=marker cms=\ //\ %s

#ifndef INIPHILE_INCLUDE_OUTPUT_HPP
#define INIPHILE_INCLUDE_OUTPUT_HPP

#include <boost/foreach.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>

#include "ast.hpp"

namespace iniphile
{

namespace karma = boost::spirit::karma;
namespace ascii = boost::spirit::ascii;
namespace phx = boost::phoenix;

template <class Iter>
struct possibly_quoted_output
: boost::spirit::karma::grammar<
    Iter
  , metagram::string()
  > // {{{
{
    template <class T>
    struct my
    {
        typedef karma::rule<Iter, T> rule;
    };
    possibly_quoted_output() // {{{
    : possibly_quoted_output::base_type(start)
    {
        using ascii::string;
        using ascii::alnum;
        using ascii::char_;
        using karma::repeat;
        using karma::_val;

        start
            %= bareword
             | qstring
        ;
        bareword %= repeat(phx::size(_val))[
            alnum | char_("-.,_$")
        ];
        qstring %= '"' << string << '"';
    } // }}}
    typename my<metagram::string()>::rule start;
    typename my<metagram::qstring()>::rule qstring;
    typename my<metagram::bareword()>::rule bareword;
}; // }}}

template <class Iter>
struct output_grammar
: boost::spirit::karma::grammar<
    Iter
  , metagram::config()
  >
// {{{
{
    template <class T>
    struct my
    {
        typedef karma::rule<Iter, T> rule;
    };

    output_grammar()
    : output_grammar::base_type(start)
    {
        using ascii::string;
        using ascii::alnum;
        using ascii::char_;
        using ascii::blank;
        using karma::eol;
        using karma::repeat;
        using karma::_val;

        start %= *section;
        section
            %=  headerline
            <<  *optionline
        ;
        headerline %= '[' << string << ']' << eol;
        optionline
            %=  optname
            <<  " = "
            <<  optval
            <<  eol
        ;
        optname %= string;

        optval %= possibly_quoted % ' ';

        start.name("start");
        section.name("section");
        headerline.name("headerline");
        optionline.name("optionline");
        optname.name("optname");
        optval.name("optval");
        possibly_quoted.name("possibly_quoted");
    }

    typename my<metagram::config()>::rule start;
    typename my<metagram::section()>::rule section;
    typename my<metagram::sectionname()>::rule headerline;
    typename my<metagram::assignment()>::rule optionline;
    typename my<metagram::optname()>::rule optname;
    typename my<metagram::optval()>::rule optval;
    possibly_quoted_output<Iter> possibly_quoted;
}; // }}}

template<class Iter>
void
generate(Iter & sink, config const & cfg) // {{{
{
    output_grammar<Iter> g;
    karma::generate(
        sink
      , g
      , cfg
    );
} // }}}

template<class Gram, class Type>
bool
parse_(std::string const & input, Gram const & g, Type & v) // {{{
{
    typedef std::string::const_iterator Iter;
    Iter b(input.begin()), e(input.end());
    return qi::parse(b, e, g, v)
        && b == e
    ;
} // }}}

template<class T>
T
parse_(std::string const &, T dflt);

template<>
bool
parse_(std::string const & input, bool dflt) // {{{
{
    using qi::_val;
    using qi::lit;
    using qi::no_case;

    typedef std::string::const_iterator Iter;
    qi::rule<Iter, bool()> yes, no;
    yes = (no_case[lit("true") | "yes"] | "1")[_val = true];
    no  = (no_case[lit("false") | "no"] | "0")[_val = false];
    parse_(input, yes | no, dflt);
    return dflt;
} // }}}

template<>
long
parse_(std::string const & input, long dflt) // {{{
{
    parse_(input, qi::int_, dflt);
    return dflt;
} // }}}

template<>
double
parse_(std::string const & input, double dflt) // {{{
{
    parse_(input, qi::double_, dflt);
    return dflt;
} // }}}

template<class T>
T
get(ast::node const & cfg, valpath const & path, T dflt) // {{{
{
    find_node<valpath::const_iterator> f(
        path.begin()
      , path.end()
    );
    ast::node nd = boost::apply_visitor(f, cfg);
    ast::leaf *l = boost::get<ast::leaf>(&nd);
    if (!l || l->value.empty()) {
        return dflt;
    }
    return parse_(l->value[0], dflt);
} // }}}

template<>
std::string
get(ast::node const & cfg, valpath const & path, std::string dflt) // {{{
{
    find_node<valpath::const_iterator> f(
        path.begin()
      , path.end()
    );
    ast::node nd = boost::apply_visitor(f, cfg);
    ast::leaf *l = boost::get<ast::leaf>(&nd);
    if (!l || l->value.empty()) {
        return dflt;
    }

    typedef std::back_insert_iterator<std::string> Sink;
    possibly_quoted_output<Sink> g;
    return to_string(
        l->value
      , g
      , " "
    );
} // }}}

template<>
std::vector<std::string>
get(ast::node const & cfg, valpath const & path, std::vector<std::string> dflt) // {{{
{
    find_node<valpath::const_iterator> f(
        path.begin()
      , path.end()
    );
    ast::node nd = boost::apply_visitor(f, cfg);
    ast::leaf *l = boost::get<ast::leaf>(&nd);
    if (!l || l->value.empty()) {
        return dflt;
    }
    return l->value;
} // }}}

template<class T>
T
get(ast::node const & cfg, std::string const & path, T dflt) // {{{
{
    return get(cfg, to_valpath(path), dflt);
} // }}}

} // namespace iniphile

#endif
<commit_msg>template<class T> T parse_(string, T) functions require full match<commit_after>// Copyright (c) 2009 Roman Neuhauser
// Distributed under the MIT license (see LICENSE file)
// vim: sw=4 sts=4 et fdm=marker cms=\ //\ %s

#ifndef INIPHILE_INCLUDE_OUTPUT_HPP
#define INIPHILE_INCLUDE_OUTPUT_HPP

#include <boost/foreach.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>

#include "ast.hpp"

namespace iniphile
{

namespace karma = boost::spirit::karma;
namespace ascii = boost::spirit::ascii;
namespace phx = boost::phoenix;

template <class Iter>
struct possibly_quoted_output
: boost::spirit::karma::grammar<
    Iter
  , metagram::string()
  > // {{{
{
    template <class T>
    struct my
    {
        typedef karma::rule<Iter, T> rule;
    };
    possibly_quoted_output() // {{{
    : possibly_quoted_output::base_type(start)
    {
        using ascii::string;
        using ascii::alnum;
        using ascii::char_;
        using karma::repeat;
        using karma::_val;

        start
            %= bareword
             | qstring
        ;
        bareword %= repeat(phx::size(_val))[
            alnum | char_("-.,_$")
        ];
        qstring %= '"' << string << '"';
    } // }}}
    typename my<metagram::string()>::rule start;
    typename my<metagram::qstring()>::rule qstring;
    typename my<metagram::bareword()>::rule bareword;
}; // }}}

template <class Iter>
struct output_grammar
: boost::spirit::karma::grammar<
    Iter
  , metagram::config()
  >
// {{{
{
    template <class T>
    struct my
    {
        typedef karma::rule<Iter, T> rule;
    };

    output_grammar()
    : output_grammar::base_type(start)
    {
        using ascii::string;
        using ascii::alnum;
        using ascii::char_;
        using ascii::blank;
        using karma::eol;
        using karma::repeat;
        using karma::_val;

        start %= *section;
        section
            %=  headerline
            <<  *optionline
        ;
        headerline %= '[' << string << ']' << eol;
        optionline
            %=  optname
            <<  " = "
            <<  optval
            <<  eol
        ;
        optname %= string;

        optval %= possibly_quoted % ' ';

        start.name("start");
        section.name("section");
        headerline.name("headerline");
        optionline.name("optionline");
        optname.name("optname");
        optval.name("optval");
        possibly_quoted.name("possibly_quoted");
    }

    typename my<metagram::config()>::rule start;
    typename my<metagram::section()>::rule section;
    typename my<metagram::sectionname()>::rule headerline;
    typename my<metagram::assignment()>::rule optionline;
    typename my<metagram::optname()>::rule optname;
    typename my<metagram::optval()>::rule optval;
    possibly_quoted_output<Iter> possibly_quoted;
}; // }}}

template<class Iter>
void
generate(Iter & sink, config const & cfg) // {{{
{
    output_grammar<Iter> g;
    karma::generate(
        sink
      , g
      , cfg
    );
} // }}}

template<class Gram, class Type>
bool
parse_(std::string const & input, Gram const & g, Type & v) // {{{
{
    typedef std::string::const_iterator Iter;
    Iter b(input.begin()), e(input.end());
    return qi::parse(b, e, g, v)
        && b == e
    ;
} // }}}

template<class T>
T
parse_(std::string const &, T dflt);

template<>
bool
parse_(std::string const & input, bool dflt) // {{{
{
    using qi::_val;
    using qi::lit;
    using qi::no_case;

    typedef std::string::const_iterator Iter;
    qi::rule<Iter, bool()> yes, no;
    yes = (no_case[lit("true") | "yes"] | "1")[_val = true];
    no  = (no_case[lit("false") | "no"] | "0")[_val = false];
    bool rv;
    return parse_(input, yes | no, rv)
        ? rv
        : dflt
    ;
} // }}}

template<>
long
parse_(std::string const & input, long dflt) // {{{
{
    long rv;
    return parse_(input, qi::int_, rv)
        ? rv
        : dflt
    ;
} // }}}

template<>
double
parse_(std::string const & input, double dflt) // {{{
{
    double rv;
    return parse_(input, qi::double_, rv)
        ? rv
        : dflt
    ;
} // }}}

template<class T>
T
get(ast::node const & cfg, valpath const & path, T dflt) // {{{
{
    find_node<valpath::const_iterator> f(
        path.begin()
      , path.end()
    );
    ast::node nd = boost::apply_visitor(f, cfg);
    ast::leaf *l = boost::get<ast::leaf>(&nd);
    if (!l || l->value.empty()) {
        return dflt;
    }
    return parse_(l->value[0], dflt);
} // }}}

template<>
std::string
get(ast::node const & cfg, valpath const & path, std::string dflt) // {{{
{
    find_node<valpath::const_iterator> f(
        path.begin()
      , path.end()
    );
    ast::node nd = boost::apply_visitor(f, cfg);
    ast::leaf *l = boost::get<ast::leaf>(&nd);
    if (!l || l->value.empty()) {
        return dflt;
    }

    typedef std::back_insert_iterator<std::string> Sink;
    possibly_quoted_output<Sink> g;
    return to_string(
        l->value
      , g
      , " "
    );
} // }}}

template<>
std::vector<std::string>
get(ast::node const & cfg, valpath const & path, std::vector<std::string> dflt) // {{{
{
    find_node<valpath::const_iterator> f(
        path.begin()
      , path.end()
    );
    ast::node nd = boost::apply_visitor(f, cfg);
    ast::leaf *l = boost::get<ast::leaf>(&nd);
    if (!l || l->value.empty()) {
        return dflt;
    }
    return l->value;
} // }}}

template<class T>
T
get(ast::node const & cfg, std::string const & path, T dflt) // {{{
{
    return get(cfg, to_valpath(path), dflt);
} // }}}

} // namespace iniphile

#endif
<|endoftext|>


<commit_before>/*
 * Copyright 1999-2004 The Apache Software Foundation.
 *
 * 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.
 */
#if !defined(XALANDOCUMENTPREFIXRESOLVER_HEADER_GUARD_1357924680)
#define XALANDOCUMENTPREFIXRESOLVER_HEADER_GUARD_1357924680

// Base include file.  Must be first.
#include <xalanc/DOMSupport/DOMSupportDefinitions.hpp>

#include <xalanc/XalanDOM/XalanDOMString.hpp>

#include <xalanc/PlatformSupport/PrefixResolver.hpp>
#include <xalanc/PlatformSupport/DOMStringHelper.hpp>

#include <xalanc/Include/XalanVector.hpp>
#include <xalanc/Include/XalanMap.hpp>
#include <xalanc/Include/STLHelper.hpp>

#include <xalanc/DOMSupport/TreeWalker.hpp>

XALAN_CPP_NAMESPACE_BEGIN

class XalanAttr;
class XalanDocument;

class XALAN_DOMSUPPORT_EXPORT XalanDocumentPrefixResolver : public PrefixResolver
{
public:

	typedef XalanVector<const XalanNode*> 				AttributeVectorType;
	typedef XalanMap<const XalanDOMString*,
					AttributeVectorType>				NamespacesMapType;

	/**
	 * Constructor.
	 *
	 * @param theDocument The XalanDocument instance to use for namespace bindings.
	 * @param theURI The base URI for the instance.  This is rarely needed, but can be provided if the URI for the XalanDocument instance is known.
	 */
	XalanDocumentPrefixResolver(
			const XalanDocument*	theDocument,
			const XalanDOMString&	theURI = XalanDOMString(XalanMemMgrs::getDummyMemMgr()),
            MemoryManagerType&      theManager XALAN_DEFAULT_MEMMGR);

	virtual
	~XalanDocumentPrefixResolver();

	virtual const XalanDOMString*
	getNamespaceForPrefix(const XalanDOMString&		prefix) const;

	virtual const XalanDOMString&
	getURI() const;

	/**
	 * A utility class to walk the XalanDocument instance and look for attribute nodes that declare namespaces.
	 */
	class NamespaceNodesTreeWalker : public TreeWalker
	{
	public:

		NamespaceNodesTreeWalker(NamespacesMapType&		theMap);

		virtual
		~NamespaceNodesTreeWalker();

	protected:

		virtual bool
		startNode(const XalanNode*	node);

		virtual bool
		startNode(XalanNode*	node);

		virtual bool
		endNode(const XalanNode*	node);

		virtual bool
		endNode(XalanNode*	node);

	private:

		NamespacesMapType&	m_map;
	};

protected:

	/**
	 * This function is called when more than one binding exists for a given prefix.
	 * The default behavior uses the first binding, but a deriving class can change
	 * that behavior by overriding.
	 *
	 * @param theVector The vector associated with the namespace prefix.
	 * @return A pointer to a const XalanDOMString containing the desired binding, or NULL.
	 */
	virtual const XalanDOMString*
	duplicateBinding(const AttributeVectorType&		theVector) const;

private:

	NamespacesMapType		m_namespaces;

	const XalanDOMString	m_uri;
};

XALAN_CPP_NAMESPACE_END

#endif	// XALANDOCUMENTPREFIXRESOLVER_HEADER_GUARD_1357924680
<commit_msg>Correct initialization of XalanMap with XalanVector as a data value<commit_after>/*
 * Copyright 1999-2004 The Apache Software Foundation.
 *
 * 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.
 */
#if !defined(XALANDOCUMENTPREFIXRESOLVER_HEADER_GUARD_1357924680)
#define XALANDOCUMENTPREFIXRESOLVER_HEADER_GUARD_1357924680

// Base include file.  Must be first.
#include <xalanc/DOMSupport/DOMSupportDefinitions.hpp>

#include <xalanc/XalanDOM/XalanDOMString.hpp>

#include <xalanc/PlatformSupport/PrefixResolver.hpp>
#include <xalanc/PlatformSupport/DOMStringHelper.hpp>

#include <xalanc/Include/XalanVector.hpp>
#include <xalanc/Include/XalanMap.hpp>
#include <xalanc/Include/STLHelper.hpp>

#include <xalanc/DOMSupport/TreeWalker.hpp>

XALAN_CPP_NAMESPACE_BEGIN

class XalanAttr;
class XalanDocument;

typedef XalanVector<const XalanNode*> 				AttributeVectorTypeDecl;
XALAN_USES_MEMORY_MANAGER(AttributeVectorTypeDecl)

class XALAN_DOMSUPPORT_EXPORT XalanDocumentPrefixResolver : public PrefixResolver
{
public:

	typedef AttributeVectorTypeDecl				        AttributeVectorType;
	typedef XalanMap<const XalanDOMString*,
					AttributeVectorType>				NamespacesMapType;

	/**
	 * Constructor.
	 *
	 * @param theDocument The XalanDocument instance to use for namespace bindings.
	 * @param theURI The base URI for the instance.  This is rarely needed, but can be provided if the URI for the XalanDocument instance is known.
	 */
	XalanDocumentPrefixResolver(
			const XalanDocument*	theDocument,
			const XalanDOMString&	theURI = XalanDOMString(XalanMemMgrs::getDummyMemMgr()),
            MemoryManagerType&      theManager XALAN_DEFAULT_MEMMGR);

	virtual
	~XalanDocumentPrefixResolver();

	virtual const XalanDOMString*
	getNamespaceForPrefix(const XalanDOMString&		prefix) const;

	virtual const XalanDOMString&
	getURI() const;

	/**
	 * A utility class to walk the XalanDocument instance and look for attribute nodes that declare namespaces.
	 */
	class NamespaceNodesTreeWalker : public TreeWalker
	{
	public:

		NamespaceNodesTreeWalker(NamespacesMapType&		theMap);

		virtual
		~NamespaceNodesTreeWalker();

	protected:

		virtual bool
		startNode(const XalanNode*	node);

		virtual bool
		startNode(XalanNode*	node);

		virtual bool
		endNode(const XalanNode*	node);

		virtual bool
		endNode(XalanNode*	node);

	private:

		NamespacesMapType&	m_map;
	};

protected:

	/**
	 * This function is called when more than one binding exists for a given prefix.
	 * The default behavior uses the first binding, but a deriving class can change
	 * that behavior by overriding.
	 *
	 * @param theVector The vector associated with the namespace prefix.
	 * @return A pointer to a const XalanDOMString containing the desired binding, or NULL.
	 */
	virtual const XalanDOMString*
	duplicateBinding(const AttributeVectorType&		theVector) const;

private:

	NamespacesMapType		m_namespaces;

	const XalanDOMString	m_uri;
};

XALAN_CPP_NAMESPACE_END

#endif	// XALANDOCUMENTPREFIXRESOLVER_HEADER_GUARD_1357924680
<|endoftext|>


<commit_before>/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you 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 .
 */
#include "SimpleToolBoxController.hxx"

#include <comphelper/processfactory.hxx>
#include <vcl/toolbox.hxx>
#include <vcl/svapp.hxx>

using namespace ::com::sun::star;

namespace svx { namespace sidebar {

SimpleToolBoxController::SimpleToolBoxController(
    const cssu::Reference<css::frame::XFrame>& rxFrame,
    ToolBox& rToolBox,
    const sal_uInt16 nItemId,
    const rtl::OUString& rsCommand)
    : svt::ToolboxController(comphelper::getComponentContext(comphelper::getProcessServiceFactory()),
        rxFrame, rsCommand),
      mrToolbox(rToolBox),
      mnItemId(nItemId)
{
}

SimpleToolBoxController::~SimpleToolBoxController (void)
{
}

void SAL_CALL SimpleToolBoxController::statusChanged (const css::frame::FeatureStateEvent& rEvent)
    throw (cssu::RuntimeException)
{
    SolarMutexGuard aSolarMutexGuard;

    if (m_bDisposed)
        return;

    mrToolbox.EnableItem(mnItemId, rEvent.IsEnabled);

    sal_uInt16 nItemBits = mrToolbox.GetItemBits(mnItemId);
    nItemBits &= ~TIB_CHECKABLE;
    TriState eState = STATE_NOCHECK;

    sal_Bool bValue;
    if (rEvent.State >>= bValue)
    {
        // Boolean, treat it as checked/unchecked
        mrToolbox.CheckItem(mnItemId, bValue);
        if ( bValue )
            eState = STATE_CHECK;
        nItemBits |= TIB_CHECKABLE;
    }

    mrToolbox.SetItemState(mnItemId, eState);
    mrToolbox.SetItemBits(mnItemId, nItemBits);
}

} } // end of namespace svx::sidebar
<commit_msg>Initialize variable to prevent compiler warning<commit_after>/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you 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 .
 */
#include "SimpleToolBoxController.hxx"

#include <comphelper/processfactory.hxx>
#include <vcl/toolbox.hxx>
#include <vcl/svapp.hxx>

using namespace ::com::sun::star;

namespace svx { namespace sidebar {

SimpleToolBoxController::SimpleToolBoxController(
    const cssu::Reference<css::frame::XFrame>& rxFrame,
    ToolBox& rToolBox,
    const sal_uInt16 nItemId,
    const rtl::OUString& rsCommand)
    : svt::ToolboxController(comphelper::getComponentContext(comphelper::getProcessServiceFactory()),
        rxFrame, rsCommand),
      mrToolbox(rToolBox),
      mnItemId(nItemId)
{
}

SimpleToolBoxController::~SimpleToolBoxController (void)
{
}

void SAL_CALL SimpleToolBoxController::statusChanged (const css::frame::FeatureStateEvent& rEvent)
    throw (cssu::RuntimeException)
{
    SolarMutexGuard aSolarMutexGuard;

    if (m_bDisposed)
        return;

    mrToolbox.EnableItem(mnItemId, rEvent.IsEnabled);

    sal_uInt16 nItemBits = mrToolbox.GetItemBits(mnItemId);
    nItemBits &= ~TIB_CHECKABLE;
    TriState eState = STATE_NOCHECK;

    sal_Bool bValue = sal_False;
    if (rEvent.State >>= bValue)
    {
        // Boolean, treat it as checked/unchecked
        mrToolbox.CheckItem(mnItemId, bValue);
        if ( bValue )
            eState = STATE_CHECK;
        nItemBits |= TIB_CHECKABLE;
    }

    mrToolbox.SetItemState(mnItemId, eState);
    mrToolbox.SetItemBits(mnItemId, nItemBits);
}

} } // end of namespace svx::sidebar
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "webrtc/system_wrappers/interface/condition_variable_wrapper.h"

#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
#include "webrtc/system_wrappers/interface/thread_wrapper.h"
#include "webrtc/system_wrappers/interface/trace.h"

namespace webrtc {

namespace {

const int kLongWaitMs = 100 * 1000; // A long time in testing terms
const int kShortWaitMs = 2 * 1000; // Long enough for process switches to happen

// A Baton is one possible control structure one can build using
// conditional variables.
// A Baton is always held by one and only one active thread - unlike
// a lock, it can never be free.
// One can pass it or grab it - both calls have timeouts.
// Note - a production tool would guard against passing it without
// grabbing it first. This one is for testing, so it doesn't.
class Baton {
 public:
  Baton()
    : giver_sect_(CriticalSectionWrapper::CreateCriticalSection()),
      crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
      cond_var_(ConditionVariableWrapper::CreateConditionVariable()),
      being_passed_(false),
      pass_count_(0) {
  }

  ~Baton() {
    delete giver_sect_;
    delete crit_sect_;
    delete cond_var_;
  }

  // Pass the baton. Returns false if baton is not picked up in |max_msecs|.
  // Only one process can pass at the same time; this property is
  // ensured by the |giver_sect_| lock.
  bool Pass(uint32_t max_msecs) {
    CriticalSectionScoped cs_giver(giver_sect_);
    CriticalSectionScoped cs(crit_sect_);
    SignalBatonAvailable();
    const bool result = TakeBatonIfStillFree(max_msecs);
    if (result) {
      ++pass_count_;
    }
    return result;
  }

  // Grab the baton. Returns false if baton is not passed.
  bool Grab(uint32_t max_msecs) {
    CriticalSectionScoped cs(crit_sect_);
    return WaitUntilBatonOffered(max_msecs);
  }

  int PassCount() {
    // We don't allow polling PassCount() during a Pass()-call since there is
    // no guarantee that |pass_count_| is incremented until the Pass()-call
    // finishes. I.e. the Grab()-call may finish before |pass_count_| has been
    // incremented.
    // Thus, this function waits on giver_sect_.
    CriticalSectionScoped cs(giver_sect_);
    return pass_count_;
  }

 private:
  // Wait/Signal forms a classical semaphore on |being_passed_|.
  // These functions must be called with crit_sect_ held.
  bool WaitUntilBatonOffered(int timeout_ms) {
    while (!being_passed_) {
      if (!cond_var_->SleepCS(*crit_sect_, timeout_ms)) {
        return false;
      }
    }
    being_passed_ = false;
    cond_var_->Wake();
    return true;
  }

  void SignalBatonAvailable() {
    assert(!being_passed_);
    being_passed_ = true;
    cond_var_->Wake();
  }

  // Timeout extension: Wait for a limited time for someone else to
  // take it, and take it if it's not taken.
  // Returns true if resource is taken by someone else, false
  // if it is taken back by the caller.
  // This function must be called with both |giver_sect_| and
  // |crit_sect_| held.
  bool TakeBatonIfStillFree(int timeout_ms) {
    bool not_timeout = true;
    while (being_passed_ && not_timeout) {
      not_timeout = cond_var_->SleepCS(*crit_sect_, timeout_ms);
      // If we're woken up while variable is still held, we may have
      // gotten a wakeup destined for a grabber thread.
      // This situation is not treated specially here.
    }
    if (!being_passed_) {
      return true;
    } else {
      assert(!not_timeout);
      being_passed_ = false;
      return false;
    }
  }

  // Lock that ensures that there is only one thread in the active
  // part of Pass() at a time.
  // |giver_sect_| must always be acquired before |cond_var_|.
  CriticalSectionWrapper* giver_sect_;
  // Lock that protects |being_passed_|.
  CriticalSectionWrapper* crit_sect_;
  ConditionVariableWrapper* cond_var_;
  bool being_passed_;
  // Statistics information: Number of successfull passes.
  int pass_count_;
};

// Function that waits on a Baton, and passes it right back.
// We expect these calls never to time out.
bool WaitingRunFunction(void* obj) {
  Baton* the_baton = static_cast<Baton*> (obj);
  EXPECT_TRUE(the_baton->Grab(kLongWaitMs));
  EXPECT_TRUE(the_baton->Pass(kLongWaitMs));
  return true;
}

class CondVarTest : public ::testing::Test {
 public:
  CondVarTest() {}

  virtual void SetUp() {
    thread_ = ThreadWrapper::CreateThread(&WaitingRunFunction,
                                          &baton_);
    unsigned int id = 42;
    ASSERT_TRUE(thread_->Start(id));
  }

  virtual void TearDown() {
    // We have to wake the thread in order to make it obey the stop order.
    // But we don't know if the thread has completed the run function, so
    // we don't know if it will exit before or after the Pass.
    // Thus, we need to pin it down inside its Run function (between Grab
    // and Pass).
    ASSERT_TRUE(baton_.Pass(kShortWaitMs));
    thread_->SetNotAlive();
    ASSERT_TRUE(baton_.Grab(kShortWaitMs));
    ASSERT_TRUE(thread_->Stop());
    delete thread_;
  }

 protected:
  Baton baton_;

 private:
  ThreadWrapper* thread_;
};

// The SetUp and TearDown functions use condition variables.
// This test verifies those pieces in isolation.
TEST_F(CondVarTest, InitFunctionsWork) {
  // All relevant asserts are in the SetUp and TearDown functions.
}

// This test verifies that one can use the baton multiple times.
TEST_F(CondVarTest, PassBatonMultipleTimes) {
  const int kNumberOfRounds = 2;
  for (int i = 0; i < kNumberOfRounds; ++i) {
    ASSERT_TRUE(baton_.Pass(kShortWaitMs));
    ASSERT_TRUE(baton_.Grab(kShortWaitMs));
  }
  EXPECT_EQ(2 * kNumberOfRounds, baton_.PassCount());
}

}  // anonymous namespace

}  // namespace webrtc
<commit_msg>system_wrappers: Disabled flaky test CondVarTest.PassBatonMultipleTimes<commit_after>/*
 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "webrtc/system_wrappers/interface/condition_variable_wrapper.h"

#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
#include "webrtc/system_wrappers/interface/thread_wrapper.h"
#include "webrtc/system_wrappers/interface/trace.h"

namespace webrtc {

namespace {

const int kLongWaitMs = 100 * 1000; // A long time in testing terms
const int kShortWaitMs = 2 * 1000; // Long enough for process switches to happen

// A Baton is one possible control structure one can build using
// conditional variables.
// A Baton is always held by one and only one active thread - unlike
// a lock, it can never be free.
// One can pass it or grab it - both calls have timeouts.
// Note - a production tool would guard against passing it without
// grabbing it first. This one is for testing, so it doesn't.
class Baton {
 public:
  Baton()
    : giver_sect_(CriticalSectionWrapper::CreateCriticalSection()),
      crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
      cond_var_(ConditionVariableWrapper::CreateConditionVariable()),
      being_passed_(false),
      pass_count_(0) {
  }

  ~Baton() {
    delete giver_sect_;
    delete crit_sect_;
    delete cond_var_;
  }

  // Pass the baton. Returns false if baton is not picked up in |max_msecs|.
  // Only one process can pass at the same time; this property is
  // ensured by the |giver_sect_| lock.
  bool Pass(uint32_t max_msecs) {
    CriticalSectionScoped cs_giver(giver_sect_);
    CriticalSectionScoped cs(crit_sect_);
    SignalBatonAvailable();
    const bool result = TakeBatonIfStillFree(max_msecs);
    if (result) {
      ++pass_count_;
    }
    return result;
  }

  // Grab the baton. Returns false if baton is not passed.
  bool Grab(uint32_t max_msecs) {
    CriticalSectionScoped cs(crit_sect_);
    return WaitUntilBatonOffered(max_msecs);
  }

  int PassCount() {
    // We don't allow polling PassCount() during a Pass()-call since there is
    // no guarantee that |pass_count_| is incremented until the Pass()-call
    // finishes. I.e. the Grab()-call may finish before |pass_count_| has been
    // incremented.
    // Thus, this function waits on giver_sect_.
    CriticalSectionScoped cs(giver_sect_);
    return pass_count_;
  }

 private:
  // Wait/Signal forms a classical semaphore on |being_passed_|.
  // These functions must be called with crit_sect_ held.
  bool WaitUntilBatonOffered(int timeout_ms) {
    while (!being_passed_) {
      if (!cond_var_->SleepCS(*crit_sect_, timeout_ms)) {
        return false;
      }
    }
    being_passed_ = false;
    cond_var_->Wake();
    return true;
  }

  void SignalBatonAvailable() {
    assert(!being_passed_);
    being_passed_ = true;
    cond_var_->Wake();
  }

  // Timeout extension: Wait for a limited time for someone else to
  // take it, and take it if it's not taken.
  // Returns true if resource is taken by someone else, false
  // if it is taken back by the caller.
  // This function must be called with both |giver_sect_| and
  // |crit_sect_| held.
  bool TakeBatonIfStillFree(int timeout_ms) {
    bool not_timeout = true;
    while (being_passed_ && not_timeout) {
      not_timeout = cond_var_->SleepCS(*crit_sect_, timeout_ms);
      // If we're woken up while variable is still held, we may have
      // gotten a wakeup destined for a grabber thread.
      // This situation is not treated specially here.
    }
    if (!being_passed_) {
      return true;
    } else {
      assert(!not_timeout);
      being_passed_ = false;
      return false;
    }
  }

  // Lock that ensures that there is only one thread in the active
  // part of Pass() at a time.
  // |giver_sect_| must always be acquired before |cond_var_|.
  CriticalSectionWrapper* giver_sect_;
  // Lock that protects |being_passed_|.
  CriticalSectionWrapper* crit_sect_;
  ConditionVariableWrapper* cond_var_;
  bool being_passed_;
  // Statistics information: Number of successfull passes.
  int pass_count_;
};

// Function that waits on a Baton, and passes it right back.
// We expect these calls never to time out.
bool WaitingRunFunction(void* obj) {
  Baton* the_baton = static_cast<Baton*> (obj);
  EXPECT_TRUE(the_baton->Grab(kLongWaitMs));
  EXPECT_TRUE(the_baton->Pass(kLongWaitMs));
  return true;
}

class CondVarTest : public ::testing::Test {
 public:
  CondVarTest() {}

  virtual void SetUp() {
    thread_ = ThreadWrapper::CreateThread(&WaitingRunFunction,
                                          &baton_);
    unsigned int id = 42;
    ASSERT_TRUE(thread_->Start(id));
  }

  virtual void TearDown() {
    // We have to wake the thread in order to make it obey the stop order.
    // But we don't know if the thread has completed the run function, so
    // we don't know if it will exit before or after the Pass.
    // Thus, we need to pin it down inside its Run function (between Grab
    // and Pass).
    ASSERT_TRUE(baton_.Pass(kShortWaitMs));
    thread_->SetNotAlive();
    ASSERT_TRUE(baton_.Grab(kShortWaitMs));
    ASSERT_TRUE(thread_->Stop());
    delete thread_;
  }

 protected:
  Baton baton_;

 private:
  ThreadWrapper* thread_;
};

// The SetUp and TearDown functions use condition variables.
// This test verifies those pieces in isolation.
TEST_F(CondVarTest, InitFunctionsWork) {
  // All relevant asserts are in the SetUp and TearDown functions.
}

// This test verifies that one can use the baton multiple times.
TEST_F(CondVarTest, DISABLED_PassBatonMultipleTimes) {
  const int kNumberOfRounds = 2;
  for (int i = 0; i < kNumberOfRounds; ++i) {
    ASSERT_TRUE(baton_.Pass(kShortWaitMs));
    ASSERT_TRUE(baton_.Grab(kShortWaitMs));
  }
  EXPECT_EQ(2 * kNumberOfRounds, baton_.PassCount());
}

}  // anonymous namespace

}  // namespace webrtc
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2017 ScyllaDB
 *
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "table_helper.hh"
#include "cql3/query_processor.hh"
#include "cql3/statements/create_table_statement.hh"
#include "cql3/statements/modification_statement.hh"
#include "database.hh"

future<> table_helper::setup_table() const {
    auto& qp = cql3::get_local_query_processor();
    auto& db = qp.db();

    if (db.has_schema(_keyspace, _name)) {
        return make_ready_future<>();
    }

    auto parsed = cql3::query_processor::parse_statement(_create_cql);

    cql3::statements::raw::cf_statement* parsed_cf_stmt = static_cast<cql3::statements::raw::cf_statement*>(parsed.get());
    parsed_cf_stmt->prepare_keyspace(_keyspace);
    ::shared_ptr<cql3::statements::create_table_statement> statement =
                    static_pointer_cast<cql3::statements::create_table_statement>(
                                    parsed_cf_stmt->prepare(db, qp.get_cql_stats())->statement);
    auto schema = statement->get_cf_meta_data(db);

    // Generate the CF UUID based on its KF names. This is needed to ensure that
    // all Nodes that create it would create it with the same UUID and we don't
    // hit the #420 issue.
    auto uuid = generate_legacy_id(schema->ks_name(), schema->cf_name());

    schema_builder b(schema);
    b.set_uuid(uuid);

    // We don't care it it fails really - this may happen due to concurrent
    // "CREATE TABLE" invocation on different Nodes.
    // The important thing is that it will converge eventually (some traces may
    // be lost in a process but that's ok).
    return service::get_local_migration_manager().announce_new_column_family(b.build(), false).discard_result().handle_exception([this] (auto ep) {});;
}

future<> table_helper::cache_table_info(service::query_state& qs) {
    if (!_prepared_stmt) {
        // if prepared statement has been invalidated - drop cached pointers
        _insert_stmt = nullptr;
    } else if (!_is_fallback_stmt) {
        // we've already prepared the non-fallback statement
        return now();
    }

    return cql3::get_local_query_processor().prepare(_insert_cql, qs.get_client_state(), false)
            .then([this] (shared_ptr<cql_transport::messages::result_message::prepared> msg_ptr) noexcept {
        _prepared_stmt = std::move(msg_ptr->get_prepared());
        shared_ptr<cql3::cql_statement> cql_stmt = _prepared_stmt->statement;
        _insert_stmt = dynamic_pointer_cast<cql3::statements::modification_statement>(cql_stmt);
        _is_fallback_stmt = false;
    }).handle_exception_type([this, &qs] (exceptions::invalid_request_exception& eptr) {
        // the non-fallback statement can't be prepared
        if (!_insert_cql_fallback) {
            return make_exception_future(eptr);
        }
        if (_is_fallback_stmt && _prepared_stmt) {
            // we have already prepared the fallback statement
            return now();
        }
        return cql3::get_local_query_processor().prepare(_insert_cql_fallback.value(), qs.get_client_state(), false)
                .then([this] (shared_ptr<cql_transport::messages::result_message::prepared> msg_ptr) noexcept {
            _prepared_stmt = std::move(msg_ptr->get_prepared());
            shared_ptr<cql3::cql_statement> cql_stmt = _prepared_stmt->statement;
            _insert_stmt = dynamic_pointer_cast<cql3::statements::modification_statement>(cql_stmt);
            _is_fallback_stmt = true;
        });
    }).handle_exception([this] (auto eptr) {
        // One of the possible causes for an error here could be the table that doesn't exist.
        //FIXME: discarded future.
        (void)this->setup_table().discard_result();

        // We throw the bad_column_family exception because the caller
        // expects and accounts this type of errors.
        try {
            std::rethrow_exception(eptr);
        } catch (std::exception& e) {
            throw bad_column_family(_keyspace, _name, e);
        } catch (...) {
            throw bad_column_family(_keyspace, _name);
        }
    });
}

future<> table_helper::insert(service::query_state& qs, noncopyable_function<cql3::query_options ()> opt_maker) {
    return cache_table_info(qs).then([this, &qs, opt_maker = std::move(opt_maker)] () mutable {
        return do_with(opt_maker(), [this, &qs] (auto& opts) {
            opts.prepare(_prepared_stmt->bound_names);
            return _insert_stmt->execute(service::get_storage_proxy().local(), qs, opts);
        });
    }).discard_result();
}

future<> table_helper::setup_keyspace(const sstring& keyspace_name, sstring replication_factor, service::query_state& qs, std::vector<table_helper*> tables) {
    if (this_shard_id() == 0) {
        size_t n = tables.size();
        for (size_t i = 0; i < n; ++i) {
            if (tables[i]->_keyspace != keyspace_name) {
                throw std::invalid_argument("setup_keyspace called with table_helper for different keyspace");
            }
        }
        return seastar::async([&keyspace_name, replication_factor, &qs, tables] {
            auto& db = cql3::get_local_query_processor().db();

            // Create a keyspace
            if (!db.has_keyspace(keyspace_name)) {
                std::map<sstring, sstring> opts;
                opts["replication_factor"] = replication_factor;
                auto ksm = keyspace_metadata::new_keyspace(keyspace_name, "org.apache.cassandra.locator.SimpleStrategy", std::move(opts), true);
                // We use min_timestamp so that default keyspace metadata will loose with any manual adjustments. See issue #2129.
                service::get_local_migration_manager().announce_new_keyspace(ksm, api::min_timestamp, false).get();
            }

            qs.get_client_state().set_keyspace(cql3::get_local_query_processor().db(), keyspace_name);

            // Create tables
            size_t n = tables.size();
            for (size_t i = 0; i < n; ++i) {
                tables[i]->setup_table().get();
            }
        });
    } else {
        return make_ready_future<>();
    }
}
<commit_msg>table_helper: Use local db variable<commit_after>/*
 * Copyright (C) 2017 ScyllaDB
 *
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "table_helper.hh"
#include "cql3/query_processor.hh"
#include "cql3/statements/create_table_statement.hh"
#include "cql3/statements/modification_statement.hh"
#include "database.hh"

future<> table_helper::setup_table() const {
    auto& qp = cql3::get_local_query_processor();
    auto& db = qp.db();

    if (db.has_schema(_keyspace, _name)) {
        return make_ready_future<>();
    }

    auto parsed = cql3::query_processor::parse_statement(_create_cql);

    cql3::statements::raw::cf_statement* parsed_cf_stmt = static_cast<cql3::statements::raw::cf_statement*>(parsed.get());
    parsed_cf_stmt->prepare_keyspace(_keyspace);
    ::shared_ptr<cql3::statements::create_table_statement> statement =
                    static_pointer_cast<cql3::statements::create_table_statement>(
                                    parsed_cf_stmt->prepare(db, qp.get_cql_stats())->statement);
    auto schema = statement->get_cf_meta_data(db);

    // Generate the CF UUID based on its KF names. This is needed to ensure that
    // all Nodes that create it would create it with the same UUID and we don't
    // hit the #420 issue.
    auto uuid = generate_legacy_id(schema->ks_name(), schema->cf_name());

    schema_builder b(schema);
    b.set_uuid(uuid);

    // We don't care it it fails really - this may happen due to concurrent
    // "CREATE TABLE" invocation on different Nodes.
    // The important thing is that it will converge eventually (some traces may
    // be lost in a process but that's ok).
    return service::get_local_migration_manager().announce_new_column_family(b.build(), false).discard_result().handle_exception([this] (auto ep) {});;
}

future<> table_helper::cache_table_info(service::query_state& qs) {
    if (!_prepared_stmt) {
        // if prepared statement has been invalidated - drop cached pointers
        _insert_stmt = nullptr;
    } else if (!_is_fallback_stmt) {
        // we've already prepared the non-fallback statement
        return now();
    }

    return cql3::get_local_query_processor().prepare(_insert_cql, qs.get_client_state(), false)
            .then([this] (shared_ptr<cql_transport::messages::result_message::prepared> msg_ptr) noexcept {
        _prepared_stmt = std::move(msg_ptr->get_prepared());
        shared_ptr<cql3::cql_statement> cql_stmt = _prepared_stmt->statement;
        _insert_stmt = dynamic_pointer_cast<cql3::statements::modification_statement>(cql_stmt);
        _is_fallback_stmt = false;
    }).handle_exception_type([this, &qs] (exceptions::invalid_request_exception& eptr) {
        // the non-fallback statement can't be prepared
        if (!_insert_cql_fallback) {
            return make_exception_future(eptr);
        }
        if (_is_fallback_stmt && _prepared_stmt) {
            // we have already prepared the fallback statement
            return now();
        }
        return cql3::get_local_query_processor().prepare(_insert_cql_fallback.value(), qs.get_client_state(), false)
                .then([this] (shared_ptr<cql_transport::messages::result_message::prepared> msg_ptr) noexcept {
            _prepared_stmt = std::move(msg_ptr->get_prepared());
            shared_ptr<cql3::cql_statement> cql_stmt = _prepared_stmt->statement;
            _insert_stmt = dynamic_pointer_cast<cql3::statements::modification_statement>(cql_stmt);
            _is_fallback_stmt = true;
        });
    }).handle_exception([this] (auto eptr) {
        // One of the possible causes for an error here could be the table that doesn't exist.
        //FIXME: discarded future.
        (void)this->setup_table().discard_result();

        // We throw the bad_column_family exception because the caller
        // expects and accounts this type of errors.
        try {
            std::rethrow_exception(eptr);
        } catch (std::exception& e) {
            throw bad_column_family(_keyspace, _name, e);
        } catch (...) {
            throw bad_column_family(_keyspace, _name);
        }
    });
}

future<> table_helper::insert(service::query_state& qs, noncopyable_function<cql3::query_options ()> opt_maker) {
    return cache_table_info(qs).then([this, &qs, opt_maker = std::move(opt_maker)] () mutable {
        return do_with(opt_maker(), [this, &qs] (auto& opts) {
            opts.prepare(_prepared_stmt->bound_names);
            return _insert_stmt->execute(service::get_storage_proxy().local(), qs, opts);
        });
    }).discard_result();
}

future<> table_helper::setup_keyspace(const sstring& keyspace_name, sstring replication_factor, service::query_state& qs, std::vector<table_helper*> tables) {
    if (this_shard_id() == 0) {
        size_t n = tables.size();
        for (size_t i = 0; i < n; ++i) {
            if (tables[i]->_keyspace != keyspace_name) {
                throw std::invalid_argument("setup_keyspace called with table_helper for different keyspace");
            }
        }
        return seastar::async([&keyspace_name, replication_factor, &qs, tables] {
            auto& db = cql3::get_local_query_processor().db();

            // Create a keyspace
            if (!db.has_keyspace(keyspace_name)) {
                std::map<sstring, sstring> opts;
                opts["replication_factor"] = replication_factor;
                auto ksm = keyspace_metadata::new_keyspace(keyspace_name, "org.apache.cassandra.locator.SimpleStrategy", std::move(opts), true);
                // We use min_timestamp so that default keyspace metadata will loose with any manual adjustments. See issue #2129.
                service::get_local_migration_manager().announce_new_keyspace(ksm, api::min_timestamp, false).get();
            }

            qs.get_client_state().set_keyspace(db, keyspace_name);

            // Create tables
            size_t n = tables.size();
            for (size_t i = 0; i < n; ++i) {
                tables[i]->setup_table().get();
            }
        });
    } else {
        return make_ready_future<>();
    }
}
<|endoftext|>