<commit_before>/*
 * Copyright (c) 2017-2019 dresden elektronik ingenieurtechnik gmbh.
 * All rights reserved.
 *
 * The software in this package is published under the terms of the BSD
 * style license a copy of which has been included with this distribution in
 * the LICENSE.txt file.
 *
 */

#include <QString>
#include <QVariantMap>
#include "de_web_plugin.h"
#include "de_web_plugin_private.h"
#include "json.h"

// server send
#define CMD_STATUS_CHANGE_NOTIFICATION 0x00
#define CMD_ZONE_ENROLL_REQUEST 0x01
// server receive
#define CMD_ZONE_ENROLL_RESPONSE 0x00

// Zone status flags
#define STATUS_ALARM1         0x0001
#define STATUS_ALARM2         0x0002
#define STATUS_TAMPER         0x0004
#define STATUS_BATTERY        0x0008
#define STATUS_SUPERVISION    0x0010
#define STATUS_RESTORE_REP    0x0020
#define STATUS_TROUBLE        0x0040
#define STATUS_AC_MAINS       0x0080
#define STATUS_TEST           0x0100
#define STATUS_BATTERY_DEFECT 0x0200

/*! Handle packets related to the ZCL IAS Zone cluster.
    \param ind the APS level data indication containing the ZCL packet
    \param zclFrame the actual ZCL frame which holds the IAS zone server command
 */
void DeRestPluginPrivate::handleIasZoneClusterIndication(const deCONZ::ApsDataIndication &ind, deCONZ::ZclFrame &zclFrame)
{
    Q_UNUSED(ind);

    QDataStream stream(zclFrame.payload());
    stream.setByteOrder(QDataStream::LittleEndian);

    if (!(zclFrame.frameControl() & deCONZ::ZclFCDirectionServerToClient))
    {
        return;
    }

    if (zclFrame.isProfileWideCommand() && zclFrame.commandId() == deCONZ::ZclReadAttributesResponseId)
    {
        // during setup the IAS Zone type will be read
        // start to proceed discovery here
        if (searchSensorsState == SearchSensorsActive)
        {
            if (!fastProbeTimer->isActive())
            {
                fastProbeTimer->start(5);
            }
        }
    }

    quint16 attrId = 0;
    quint16 zoneStatus = 0; // might be reported or received via CMD_STATUS_CHANGE_NOTIFICATION

    if (zclFrame.isProfileWideCommand() && zclFrame.commandId() == deCONZ::ZclReportAttributesId)
    {
        quint16 a;
        quint8 dataType;

        stream >> a;
        stream >> dataType;

        if (a == IAS_ZONE_CLUSTER_ATTR_ZONE_STATUS_ID && dataType == deCONZ::Zcl16BitBitMap)
        {
            attrId = a; // mark as reported
            stream >> zoneStatus;
        }

        if (stream.status() == QDataStream::ReadPastEnd)
        {
            return; // sanity
        }
    }

    if ((zclFrame.commandId() == CMD_STATUS_CHANGE_NOTIFICATION && zclFrame.isClusterCommand()) || attrId == IAS_ZONE_CLUSTER_ATTR_ZONE_STATUS_ID)
    {

        if (zclFrame.commandId() == CMD_STATUS_CHANGE_NOTIFICATION)
        {
            quint8 extendedStatus;
            quint8 zoneId;
            quint16 delay;
            stream >> zoneStatus;
            stream >> extendedStatus; // reserved, set to 0
            stream >> zoneId;
            stream >> delay;
            DBG_Printf(DBG_ZCL, "IAS Zone Status Change, status: 0x%04X, zoneId: %u, delay: %u\n", zoneStatus, zoneId, delay);
        }

        Sensor *sensor = nullptr;

        for (Sensor &s : sensors)
        {
            if (s.deletedState() != Sensor::StateNormal)
            {
                continue;
            }

            if (!s.fingerPrint().hasInCluster(IAS_ZONE_CLUSTER_ID) && !s.fingerPrint().hasInCluster(IAS_WD_CLUSTER_ID))
            {
                continue;
            }

            if (s.type() != QLatin1String("ZHAAlarm") &&
                s.type() != QLatin1String("ZHACarbonMonoxide") &&
                s.type() != QLatin1String("ZHAFire") &&
                s.type() != QLatin1String("ZHAOpenClose") &&
                s.type() != QLatin1String("ZHAPresence") &&
                s.type() != QLatin1String("ZHAVibration") &&
                s.type() != QLatin1String("ZHAWater"))
            {
                continue;
            }

            if ((ind.srcAddress().hasExt() && s.address().ext() == ind.srcAddress().ext()) ||
                (ind.srcAddress().hasNwk() && s.address().nwk() == ind.srcAddress().nwk()))
            {
                sensor = &s;
                break;
            }
        }

        if (!sensor)
        {
            return;
        }

        const char *attr = nullptr;
        if (sensor->type() == QLatin1String("ZHAAlarm"))
        {
            attr = RStateAlarm;
        }
        else if (sensor->type() == QLatin1String("ZHACarbonMonoxide"))
        {
            attr = RStateCarbonMonoxide;
        }
        else if (sensor->type() == QLatin1String("ZHAFire"))
        {
            attr = RStateFire;
        }
        else if (sensor->type() == QLatin1String("ZHAOpenClose"))
        {
            attr = RStateOpen;
        }
        else if (sensor->type() == QLatin1String("ZHAPresence"))
        {
            attr = RStatePresence;
        }
        else if (sensor->type() == QLatin1String("ZHAVibration"))
        {
            attr = RStateVibration;
        }
        else if (sensor->type() == QLatin1String("ZHAWater"))
        {
            attr = RStateWater;
        }

        ResourceItem *item = nullptr;
        if (attr)
        {
            item = sensor->item(attr);
        }

        if (item)
        {
            sensor->rx();
            sensor->incrementRxCounter();
            bool alarm = (zoneStatus & (STATUS_ALARM1 | STATUS_ALARM2)) ? true : false;
            item->setValue(alarm);
            sensor->updateStateTimestamp();
            sensor->setNeedSaveDatabase(true);
            updateSensorEtag(sensor);
            enqueueEvent(Event(RSensors, item->descriptor().suffix, sensor->id(), item));
            enqueueEvent(Event(RSensors, RStateLastUpdated, sensor->id()));

            ResourceItem *item2 = sensor->item(RStateLowBattery);
            if (item2)
            {
                bool battery = (zoneStatus & STATUS_BATTERY) ? true : false;
                item2->setValue(battery);
                enqueueEvent(Event(RSensors, RStateLowBattery, sensor->id(), item2));
            }

            item2 = sensor->item(RStateTampered);
            if (item2)
            {
                bool tamper = (zoneStatus & STATUS_TAMPER) ? true : false;
                item2->setValue(tamper);
                enqueueEvent(Event(RSensors, RStateTampered, sensor->id(), item2));
            }

            deCONZ::NumericUnion num = {0};
            num.u16 = zoneStatus;
            sensor->setZclValue(NodeValue::UpdateByZclReport, ind.srcEndpoint(), IAS_ZONE_CLUSTER_ID, IAS_ZONE_CLUSTER_ATTR_ZONE_STATUS_ID, num);

            item2 = sensor->item(RConfigReachable);
            if (item2 && !item2->toBool())
            {
                item2->setValue(true);
                enqueueEvent(Event(RSensors, RConfigReachable, sensor->id(), item2));
            }

            if (alarm && item->descriptor().suffix == RStatePresence)
            {   // prepare to automatically set presence to false
                NodeValue &val = sensor->getZclValue(IAS_ZONE_CLUSTER_ID, IAS_ZONE_CLUSTER_ATTR_ZONE_STATUS_ID);

                item2 = sensor->item(RConfigDuration);
                if (val.maxInterval > 0)
                {
                    sensor->durationDue = item->lastSet().addSecs(val.maxInterval);
                }
                else if (item2 && item2->toNumber() > 0)
                {
                    sensor->durationDue = item->lastSet().addSecs(item2->toNumber());
                }
            }
        }

    }
    else if (zclFrame.commandId() == CMD_ZONE_ENROLL_REQUEST && zclFrame.isClusterCommand())
    {
        quint16 zoneType;
        quint16 manufacturer;

        stream >> zoneType;
        stream >> manufacturer;

        DBG_Printf(DBG_INFO_L2, "[IAS] Zone Enroll Request, zone type: 0x%04X, manufacturer: 0x%04X\n", zoneType, manufacturer);

        sendIasZoneEnrollResponse(ind, zclFrame);

        Sensor *sensor = getSensorNodeForAddressAndEndpoint(ind.srcAddress(), ind.srcEndpoint());
        ResourceItem *item = sensor ? sensor->item(RConfigPending) : nullptr;

        if (sensor && item)
        {
            item->setValue(item->toNumber() & ~R_PENDING_ENROLL_RESPONSE);
        }
    }
}

/*! Sends IAS Zone enroll response to IAS Zone server.
    \param ind the APS level data indication containing the ZCL packet
    \param zclFrame the actual ZCL frame which holds the IAS Zone enroll request
 */
void DeRestPluginPrivate::sendIasZoneEnrollResponse(const deCONZ::ApsDataIndication &ind, deCONZ::ZclFrame &zclFrame)
{
    deCONZ::ApsDataRequest req;
    deCONZ::ZclFrame outZclFrame;

    req.setProfileId(ind.profileId());
    req.setClusterId(ind.clusterId());
    req.setDstAddressMode(ind.srcAddressMode());
    req.dstAddress() = ind.srcAddress();
    req.setDstEndpoint(ind.srcEndpoint());
    req.setSrcEndpoint(endpoint());

    outZclFrame.setSequenceNumber(zclFrame.sequenceNumber());
    outZclFrame.setCommandId(CMD_ZONE_ENROLL_RESPONSE);

    outZclFrame.setFrameControl(deCONZ::ZclFCClusterCommand |
                             deCONZ::ZclFCDirectionClientToServer |
                             deCONZ::ZclFCDisableDefaultResponse);

    { // payload
        QDataStream stream(&outZclFrame.payload(), QIODevice::WriteOnly);
        stream.setByteOrder(QDataStream::LittleEndian);

        quint8 code = 0x00; // success
        quint8 zoneId = 100;

        stream << code;
        stream << zoneId;
    }

    { // ZCL frame
        QDataStream stream(&req.asdu(), QIODevice::WriteOnly);
        stream.setByteOrder(QDataStream::LittleEndian);
        outZclFrame.writeToStream(stream);
    }

    if (apsCtrl && apsCtrl->apsdeDataRequest(req) != deCONZ::Success)
    {
        DBG_Printf(DBG_INFO_L2, "[IAS] Zone failed to send enroll reponse\n");
    }
}

/*! Check if a sensor is already enrolled
    \param Sensor - sensor containing the IAS zone cluster
 */
void DeRestPluginPrivate::checkIasEnrollmentStatus(Sensor *sensor)
{
    if (sensor->fingerPrint().hasInCluster(IAS_ZONE_CLUSTER_ID))
    {
        NodeValue val = sensor->getZclValue(IAS_ZONE_CLUSTER_ID, 0x0000);
        deCONZ::NumericUnion iasZoneStatus = val.value;

        ResourceItem *item = nullptr;
        item = sensor->item(RConfigPending);

        if(item && item->toNumber() == 0 && iasZoneStatus.u8 == 0)
        {
            DBG_Printf(DBG_INFO_L2, "[IAS] Sensor NOT enrolled\n");
            item->setValue(item->toNumber() | R_PENDING_WRITE_CIE_ADDRESS | R_PENDING_ENROLL_RESPONSE);
            std::vector<uint16_t> attributes;
            attributes.push_back(0x0000); // IAS zone status
            attributes.push_back(0x0010); // IAS CIE address
            if(readAttributes(sensor, sensor->fingerPrint().endpoint, IAS_ZONE_CLUSTER_ID, attributes))
            {
                queryTime = queryTime.addSecs(1);
            }
        }
        else if(item &&
                (item->toNumber() & R_PENDING_WRITE_CIE_ADDRESS) &&
                (item->toNumber() & R_PENDING_ENROLL_RESPONSE) &&
                iasZoneStatus.u8 == 0)
        {
            DBG_Printf(DBG_INFO_L2, "[IAS] Sensor enrollment pending\n");
        }
        else if(iasZoneStatus.u8 == 1)
        {
            DBG_Printf(DBG_INFO_L2, "[IAS] Sensor enrolled\n");
        }
        else if(item && item->toNumber() == 48 && iasZoneStatus.u8 == 1)        // Sanity check
        {
            DBG_Printf(DBG_INFO_L2, "[IAS] Sensor reporting enrolled. Clearing config pending...\n");
            item->setValue(item->toNumber() & ~R_PENDING_WRITE_CIE_ADDRESS);
            item->setValue(item->toNumber() & ~R_PENDING_ENROLL_RESPONSE);
        }
        else
        {
            DBG_Printf(DBG_INFO_L2, "[IAS] Enrolling...\n");
        }
    }
}

/*! Write IAS CIE address attribute for a node.
    \param Sensor - sensor containing the IAS zone cluster
 */
void DeRestPluginPrivate::writeIasCieAddress(Sensor *sensor)
{
    ResourceItem *item = nullptr;
    item = sensor->item(RConfigPending);

    if (sensor->fingerPrint().hasInCluster(IAS_ZONE_CLUSTER_ID) && item && (item->toNumber() & R_PENDING_WRITE_CIE_ADDRESS))
    {
        // write CIE address needed for some IAS Zone devices
        const quint64 iasCieAddress = apsCtrl->getParameter(deCONZ::ParamMacAddress);
        deCONZ::ZclAttribute attr(0x0010, deCONZ::ZclIeeeAddress, QLatin1String("CIE address"), deCONZ::ZclReadWrite, false);
        attr.setValue(iasCieAddress);

        DBG_Printf(DBG_INFO_L2, "[IAS] Write IAS CIE address for 0x%016llx\n", sensor->address().ext());

        if (writeAttribute(sensor, sensor->fingerPrint().endpoint, IAS_ZONE_CLUSTER_ID, attr, 0))
        {
            // mark done
            item->setValue(item->toNumber() & ~R_PENDING_WRITE_CIE_ADDRESS);
        }
    }
}<commit_msg>Replace IAS pending flags magic number with constants<commit_after>/*
 * Copyright (c) 2017-2019 dresden elektronik ingenieurtechnik gmbh.
 * All rights reserved.
 *
 * The software in this package is published under the terms of the BSD
 * style license a copy of which has been included with this distribution in
 * the LICENSE.txt file.
 *
 */

#include <QString>
#include <QVariantMap>
#include "de_web_plugin.h"
#include "de_web_plugin_private.h"
#include "json.h"

// server send
#define CMD_STATUS_CHANGE_NOTIFICATION 0x00
#define CMD_ZONE_ENROLL_REQUEST 0x01
// server receive
#define CMD_ZONE_ENROLL_RESPONSE 0x00

// Zone status flags
#define STATUS_ALARM1         0x0001
#define STATUS_ALARM2         0x0002
#define STATUS_TAMPER         0x0004
#define STATUS_BATTERY        0x0008
#define STATUS_SUPERVISION    0x0010
#define STATUS_RESTORE_REP    0x0020
#define STATUS_TROUBLE        0x0040
#define STATUS_AC_MAINS       0x0080
#define STATUS_TEST           0x0100
#define STATUS_BATTERY_DEFECT 0x0200

/*! Handle packets related to the ZCL IAS Zone cluster.
    \param ind the APS level data indication containing the ZCL packet
    \param zclFrame the actual ZCL frame which holds the IAS zone server command
 */
void DeRestPluginPrivate::handleIasZoneClusterIndication(const deCONZ::ApsDataIndication &ind, deCONZ::ZclFrame &zclFrame)
{
    Q_UNUSED(ind);

    QDataStream stream(zclFrame.payload());
    stream.setByteOrder(QDataStream::LittleEndian);

    if (!(zclFrame.frameControl() & deCONZ::ZclFCDirectionServerToClient))
    {
        return;
    }

    if (zclFrame.isProfileWideCommand() && zclFrame.commandId() == deCONZ::ZclReadAttributesResponseId)
    {
        // during setup the IAS Zone type will be read
        // start to proceed discovery here
        if (searchSensorsState == SearchSensorsActive)
        {
            if (!fastProbeTimer->isActive())
            {
                fastProbeTimer->start(5);
            }
        }
    }

    quint16 attrId = 0;
    quint16 zoneStatus = 0; // might be reported or received via CMD_STATUS_CHANGE_NOTIFICATION

    if (zclFrame.isProfileWideCommand() && zclFrame.commandId() == deCONZ::ZclReportAttributesId)
    {
        quint16 a;
        quint8 dataType;

        stream >> a;
        stream >> dataType;

        if (a == IAS_ZONE_CLUSTER_ATTR_ZONE_STATUS_ID && dataType == deCONZ::Zcl16BitBitMap)
        {
            attrId = a; // mark as reported
            stream >> zoneStatus;
        }

        if (stream.status() == QDataStream::ReadPastEnd)
        {
            return; // sanity
        }
    }

    if ((zclFrame.commandId() == CMD_STATUS_CHANGE_NOTIFICATION && zclFrame.isClusterCommand()) || attrId == IAS_ZONE_CLUSTER_ATTR_ZONE_STATUS_ID)
    {

        if (zclFrame.commandId() == CMD_STATUS_CHANGE_NOTIFICATION)
        {
            quint8 extendedStatus;
            quint8 zoneId;
            quint16 delay;
            stream >> zoneStatus;
            stream >> extendedStatus; // reserved, set to 0
            stream >> zoneId;
            stream >> delay;
            DBG_Printf(DBG_ZCL, "IAS Zone Status Change, status: 0x%04X, zoneId: %u, delay: %u\n", zoneStatus, zoneId, delay);
        }

        Sensor *sensor = nullptr;

        for (Sensor &s : sensors)
        {
            if (s.deletedState() != Sensor::StateNormal)
            {
                continue;
            }

            if (!s.fingerPrint().hasInCluster(IAS_ZONE_CLUSTER_ID) && !s.fingerPrint().hasInCluster(IAS_WD_CLUSTER_ID))
            {
                continue;
            }

            if (s.type() != QLatin1String("ZHAAlarm") &&
                s.type() != QLatin1String("ZHACarbonMonoxide") &&
                s.type() != QLatin1String("ZHAFire") &&
                s.type() != QLatin1String("ZHAOpenClose") &&
                s.type() != QLatin1String("ZHAPresence") &&
                s.type() != QLatin1String("ZHAVibration") &&
                s.type() != QLatin1String("ZHAWater"))
            {
                continue;
            }

            if ((ind.srcAddress().hasExt() && s.address().ext() == ind.srcAddress().ext()) ||
                (ind.srcAddress().hasNwk() && s.address().nwk() == ind.srcAddress().nwk()))
            {
                sensor = &s;
                break;
            }
        }

        if (!sensor)
        {
            return;
        }

        const char *attr = nullptr;
        if (sensor->type() == QLatin1String("ZHAAlarm"))
        {
            attr = RStateAlarm;
        }
        else if (sensor->type() == QLatin1String("ZHACarbonMonoxide"))
        {
            attr = RStateCarbonMonoxide;
        }
        else if (sensor->type() == QLatin1String("ZHAFire"))
        {
            attr = RStateFire;
        }
        else if (sensor->type() == QLatin1String("ZHAOpenClose"))
        {
            attr = RStateOpen;
        }
        else if (sensor->type() == QLatin1String("ZHAPresence"))
        {
            attr = RStatePresence;
        }
        else if (sensor->type() == QLatin1String("ZHAVibration"))
        {
            attr = RStateVibration;
        }
        else if (sensor->type() == QLatin1String("ZHAWater"))
        {
            attr = RStateWater;
        }

        ResourceItem *item = nullptr;
        if (attr)
        {
            item = sensor->item(attr);
        }

        if (item)
        {
            sensor->rx();
            sensor->incrementRxCounter();
            bool alarm = (zoneStatus & (STATUS_ALARM1 | STATUS_ALARM2)) ? true : false;
            item->setValue(alarm);
            sensor->updateStateTimestamp();
            sensor->setNeedSaveDatabase(true);
            updateSensorEtag(sensor);
            enqueueEvent(Event(RSensors, item->descriptor().suffix, sensor->id(), item));
            enqueueEvent(Event(RSensors, RStateLastUpdated, sensor->id()));

            ResourceItem *item2 = sensor->item(RStateLowBattery);
            if (item2)
            {
                bool battery = (zoneStatus & STATUS_BATTERY) ? true : false;
                item2->setValue(battery);
                enqueueEvent(Event(RSensors, RStateLowBattery, sensor->id(), item2));
            }

            item2 = sensor->item(RStateTampered);
            if (item2)
            {
                bool tamper = (zoneStatus & STATUS_TAMPER) ? true : false;
                item2->setValue(tamper);
                enqueueEvent(Event(RSensors, RStateTampered, sensor->id(), item2));
            }

            deCONZ::NumericUnion num = {0};
            num.u16 = zoneStatus;
            sensor->setZclValue(NodeValue::UpdateByZclReport, ind.srcEndpoint(), IAS_ZONE_CLUSTER_ID, IAS_ZONE_CLUSTER_ATTR_ZONE_STATUS_ID, num);

            item2 = sensor->item(RConfigReachable);
            if (item2 && !item2->toBool())
            {
                item2->setValue(true);
                enqueueEvent(Event(RSensors, RConfigReachable, sensor->id(), item2));
            }

            if (alarm && item->descriptor().suffix == RStatePresence)
            {   // prepare to automatically set presence to false
                NodeValue &val = sensor->getZclValue(IAS_ZONE_CLUSTER_ID, IAS_ZONE_CLUSTER_ATTR_ZONE_STATUS_ID);

                item2 = sensor->item(RConfigDuration);
                if (val.maxInterval > 0)
                {
                    sensor->durationDue = item->lastSet().addSecs(val.maxInterval);
                }
                else if (item2 && item2->toNumber() > 0)
                {
                    sensor->durationDue = item->lastSet().addSecs(item2->toNumber());
                }
            }
        }

    }
    else if (zclFrame.commandId() == CMD_ZONE_ENROLL_REQUEST && zclFrame.isClusterCommand())
    {
        quint16 zoneType;
        quint16 manufacturer;

        stream >> zoneType;
        stream >> manufacturer;

        DBG_Printf(DBG_INFO_L2, "[IAS] Zone Enroll Request, zone type: 0x%04X, manufacturer: 0x%04X\n", zoneType, manufacturer);

        sendIasZoneEnrollResponse(ind, zclFrame);

        Sensor *sensor = getSensorNodeForAddressAndEndpoint(ind.srcAddress(), ind.srcEndpoint());
        ResourceItem *item = sensor ? sensor->item(RConfigPending) : nullptr;

        if (sensor && item)
        {
            item->setValue(item->toNumber() & ~R_PENDING_ENROLL_RESPONSE);
        }
    }
}

/*! Sends IAS Zone enroll response to IAS Zone server.
    \param ind the APS level data indication containing the ZCL packet
    \param zclFrame the actual ZCL frame which holds the IAS Zone enroll request
 */
void DeRestPluginPrivate::sendIasZoneEnrollResponse(const deCONZ::ApsDataIndication &ind, deCONZ::ZclFrame &zclFrame)
{
    deCONZ::ApsDataRequest req;
    deCONZ::ZclFrame outZclFrame;

    req.setProfileId(ind.profileId());
    req.setClusterId(ind.clusterId());
    req.setDstAddressMode(ind.srcAddressMode());
    req.dstAddress() = ind.srcAddress();
    req.setDstEndpoint(ind.srcEndpoint());
    req.setSrcEndpoint(endpoint());

    outZclFrame.setSequenceNumber(zclFrame.sequenceNumber());
    outZclFrame.setCommandId(CMD_ZONE_ENROLL_RESPONSE);

    outZclFrame.setFrameControl(deCONZ::ZclFCClusterCommand |
                             deCONZ::ZclFCDirectionClientToServer |
                             deCONZ::ZclFCDisableDefaultResponse);

    { // payload
        QDataStream stream(&outZclFrame.payload(), QIODevice::WriteOnly);
        stream.setByteOrder(QDataStream::LittleEndian);

        quint8 code = 0x00; // success
        quint8 zoneId = 100;

        stream << code;
        stream << zoneId;
    }

    { // ZCL frame
        QDataStream stream(&req.asdu(), QIODevice::WriteOnly);
        stream.setByteOrder(QDataStream::LittleEndian);
        outZclFrame.writeToStream(stream);
    }

    if (apsCtrl && apsCtrl->apsdeDataRequest(req) != deCONZ::Success)
    {
        DBG_Printf(DBG_INFO_L2, "[IAS] Zone failed to send enroll reponse\n");
    }
}

/*! Check if a sensor is already enrolled
    \param Sensor - sensor containing the IAS zone cluster
 */
void DeRestPluginPrivate::checkIasEnrollmentStatus(Sensor *sensor)
{
    if (sensor->fingerPrint().hasInCluster(IAS_ZONE_CLUSTER_ID))
    {
        NodeValue val = sensor->getZclValue(IAS_ZONE_CLUSTER_ID, 0x0000);
        deCONZ::NumericUnion iasZoneStatus = val.value;

        ResourceItem *item = nullptr;
        item = sensor->item(RConfigPending);

        if (item && item->toNumber() == 0 && iasZoneStatus.u8 == 0)
        {
            DBG_Printf(DBG_INFO_L2, "[IAS] Sensor NOT enrolled\n");
            item->setValue(item->toNumber() | R_PENDING_WRITE_CIE_ADDRESS | R_PENDING_ENROLL_RESPONSE);
            std::vector<uint16_t> attributes;
            attributes.push_back(0x0000); // IAS zone status
            attributes.push_back(0x0010); // IAS CIE address
            if (readAttributes(sensor, sensor->fingerPrint().endpoint, IAS_ZONE_CLUSTER_ID, attributes))
            {
                queryTime = queryTime.addSecs(1);
            }
        }
        else if (item &&
                (item->toNumber() & R_PENDING_WRITE_CIE_ADDRESS) &&
                (item->toNumber() & R_PENDING_ENROLL_RESPONSE) &&
                iasZoneStatus.u8 == 0)
        {
            DBG_Printf(DBG_INFO_L2, "[IAS] Sensor enrollment pending\n");
        }
        else if (iasZoneStatus.u8 == 1)
        {
            DBG_Printf(DBG_INFO_L2, "[IAS] Sensor enrolled\n");
        }
        else if (item && item->toNumber() == (R_PENDING_WRITE_CIE_ADDRESS | R_PENDING_ENROLL_RESPONSE) && iasZoneStatus.u8 == 1)        // Sanity check
        {
            DBG_Printf(DBG_INFO_L2, "[IAS] Sensor reporting enrolled. Clearing config pending...\n");
            item->setValue(item->toNumber() & ~R_PENDING_WRITE_CIE_ADDRESS);
            item->setValue(item->toNumber() & ~R_PENDING_ENROLL_RESPONSE);
        }
        else
        {
            DBG_Printf(DBG_INFO_L2, "[IAS] Enrolling...\n");
        }
    }
}

/*! Write IAS CIE address attribute for a node.
    \param Sensor - sensor containing the IAS zone cluster
 */
void DeRestPluginPrivate::writeIasCieAddress(Sensor *sensor)
{
    ResourceItem *item = nullptr;
    item = sensor->item(RConfigPending);

    if (sensor->fingerPrint().hasInCluster(IAS_ZONE_CLUSTER_ID) && item && (item->toNumber() & R_PENDING_WRITE_CIE_ADDRESS))
    {
        // write CIE address needed for some IAS Zone devices
        const quint64 iasCieAddress = apsCtrl->getParameter(deCONZ::ParamMacAddress);
        deCONZ::ZclAttribute attr(0x0010, deCONZ::ZclIeeeAddress, QLatin1String("CIE address"), deCONZ::ZclReadWrite, false);
        attr.setValue(iasCieAddress);

        DBG_Printf(DBG_INFO_L2, "[IAS] Write IAS CIE address for 0x%016llx\n", sensor->address().ext());

        if (writeAttribute(sensor, sensor->fingerPrint().endpoint, IAS_ZONE_CLUSTER_ID, attr, 0))
        {
            // mark done
            item->setValue(item->toNumber() & ~R_PENDING_WRITE_CIE_ADDRESS);
        }
    }
}
<|endoftext|>


<commit_before>

//===------------------------ exception.cpp -------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include <stdlib.h>
#include <stdio.h>

#include "exception"

#ifndef __has_include
#define __has_include(inc) 0
#endif

#ifdef __APPLE__
  #include <cxxabi.h>

  using namespace __cxxabiv1;
  #define HAVE_DEPENDENT_EH_ABI 1
  #ifndef _LIBCPPABI_VERSION
    using namespace __cxxabiapple;
    // On Darwin, there are two STL shared libraries and a lower level ABI
    // shared libray.  The globals holding the current terminate handler and
    // current unexpected handler are in the ABI library.
    #define __terminate_handler  __cxxabiapple::__cxa_terminate_handler
    #define __unexpected_handler __cxxabiapple::__cxa_unexpected_handler
  #endif  // _LIBCPPABI_VERSION
#elif defined(LIBCXXRT) || __has_include(<cxxabi.h>)
  #include <cxxabi.h>
  using namespace __cxxabiv1;
  #if defined(LIBCXXRT) || defined(_LIBCPPABI_VERSION)
    #define HAVE_DEPENDENT_EH_ABI 1
  #endif
#elif !defined(__GLIBCXX__) // __has_include(<cxxabi.h>)
  static std::terminate_handler  __terminate_handler;
  static std::unexpected_handler __unexpected_handler;
#endif // __has_include(<cxxabi.h>)

_LIBCPP_NORETURN
static void _libcpp_abort(const char* msg)
{
    printf("%s\n", msg);
    abort();
}

namespace std
{

#if !defined(LIBCXXRT) && !defined(_LIBCPPABI_VERSION) && !defined(__GLIBCXX__)

// libcxxrt provides implementations of these functions itself.
unexpected_handler
set_unexpected(unexpected_handler func) _NOEXCEPT
{
    return __sync_lock_test_and_set(&__unexpected_handler, func);
}

unexpected_handler
get_unexpected() _NOEXCEPT
{
    return __sync_fetch_and_add(&__unexpected_handler, (unexpected_handler)0);
}

_LIBCPP_NORETURN
void
unexpected()
{
    (*get_unexpected())();
    // unexpected handler should not return
    terminate();
}

terminate_handler
set_terminate(terminate_handler func) _NOEXCEPT
{
    return __sync_lock_test_and_set(&__terminate_handler, func);
}

terminate_handler
get_terminate() _NOEXCEPT
{
    return __sync_fetch_and_add(&__terminate_handler, (terminate_handler)0);
}

#ifndef EMSCRIPTEN // We provide this in JS
_LIBCPP_NORETURN
void
terminate() _NOEXCEPT
{
#ifndef _LIBCPP_NO_EXCEPTIONS
    try
    {
#endif  // _LIBCPP_NO_EXCEPTIONS
        (*get_terminate())();
        // handler should not return
        _libcpp_abort("terminate_handler unexpectedly returned\n");
#ifndef _LIBCPP_NO_EXCEPTIONS
    }
    catch (...)
    {
        // handler should not throw exception
        _libcpp_abort("terminate_handler unexpectedly threw an exception\n");
    }
#endif  // _LIBCPP_NO_EXCEPTIONS
}
#endif // !EMSCRIPTEN
#endif // !defined(LIBCXXRT) && !defined(_LIBCPPABI_VERSION)

#if !defined(LIBCXXRT) && !defined(__GLIBCXX__) && !defined(EMSCRIPTEN)
bool uncaught_exception() _NOEXCEPT
{
#if defined(__APPLE__) || defined(_LIBCPPABI_VERSION)
    // on Darwin, there is a helper function so __cxa_get_globals is private
    return __cxa_uncaught_exception();
#else  // __APPLE__
#   if defined(_MSC_VER) && ! defined(__clang__)
        _LIBCPP_WARNING("uncaught_exception not yet implemented")
#   else
#       warning uncaught_exception not yet implemented
#   endif
    _libcpp_abort("uncaught_exception not yet implemented\n");
#endif  // __APPLE__
}

#ifndef _LIBCPPABI_VERSION

exception::~exception() _NOEXCEPT
{
}

const char* exception::what() const _NOEXCEPT
{
  return "std::exception";
}

#endif  // _LIBCPPABI_VERSION
#endif //LIBCXXRT
#if !defined(_LIBCPPABI_VERSION) && !defined(__GLIBCXX__)

bad_exception::~bad_exception() _NOEXCEPT
{
}

const char* bad_exception::what() const _NOEXCEPT
{
  return "std::bad_exception";
}

#endif

exception_ptr::~exception_ptr() _NOEXCEPT
{
#if HAVE_DEPENDENT_EH_ABI
    __cxa_decrement_exception_refcount(__ptr_);
#else
#   if defined(_MSC_VER) && ! defined(__clang__)
        _LIBCPP_WARNING("exception_ptr not yet implemented")
#   else
#       warning exception_ptr not yet implemented
#   endif
    _libcpp_abort("exception_ptr not yet implemented\n");
#endif  // __APPLE__
}

exception_ptr::exception_ptr(const exception_ptr& other) _NOEXCEPT
    : __ptr_(other.__ptr_)
{
#if HAVE_DEPENDENT_EH_ABI
    __cxa_increment_exception_refcount(__ptr_);
#else

#   if defined(_MSC_VER) && ! defined(__clang__)
        _LIBCPP_WARNING("exception_ptr not yet implemented")
#   else
#       warning exception_ptr not yet implemented
#   endif
    _libcpp_abort("exception_ptr not yet implemented\n");

#endif  // __APPLE__
}

exception_ptr& exception_ptr::operator=(const exception_ptr& other) _NOEXCEPT
{
#if HAVE_DEPENDENT_EH_ABI
    if (__ptr_ != other.__ptr_)
    {
        __cxa_increment_exception_refcount(other.__ptr_);
        __cxa_decrement_exception_refcount(__ptr_);
        __ptr_ = other.__ptr_;
    }
    return *this;
#else  // __APPLE__

#   if defined(_MSC_VER) && ! defined(__clang__)
        _LIBCPP_WARNING("exception_ptr not yet implemented")
#   else
#       warning exception_ptr not yet implemented
#   endif
    _libcpp_abort("exception_ptr not yet implemented\n");

#endif  // __APPLE__
}

nested_exception::nested_exception() _NOEXCEPT
    : __ptr_(current_exception())
{
}

#if !defined(__GLIBCXX__)

nested_exception::~nested_exception() _NOEXCEPT
{
}

#endif

_LIBCPP_NORETURN
void
nested_exception::rethrow_nested() const
{
    if (__ptr_ == nullptr)
        terminate();
    rethrow_exception(__ptr_);
}

exception_ptr current_exception() _NOEXCEPT
{
#if HAVE_DEPENDENT_EH_ABI
    // be nicer if there was a constructor that took a ptr, then
    // this whole function would be just:
    //    return exception_ptr(__cxa_current_primary_exception());
    exception_ptr ptr;
    ptr.__ptr_ = __cxa_current_primary_exception();
    return ptr;
#else  // __APPLE__
#   if defined(_MSC_VER) && ! defined(__clang__)
        _LIBCPP_WARNING( "exception_ptr not yet implemented" )
#   else
#       warning exception_ptr not yet implemented
#   endif
    _libcpp_abort("exception_ptr not yet implemented\n");
#endif  // __APPLE__
}

_LIBCPP_NORETURN
void rethrow_exception(exception_ptr p)
{
#if HAVE_DEPENDENT_EH_ABI
    __cxa_rethrow_primary_exception(p.__ptr_);
    // if p.__ptr_ is NULL, above returns so we terminate
    terminate();
#else  // __APPLE__
#   if defined(_MSC_VER) && ! defined(__clang__)
        _LIBCPP_WARNING("exception_ptr not yet implemented")
#   else
#       warning exception_ptr not yet implemented
#   endif
    _libcpp_abort("exception_ptr not yet implemented\n");
#endif  // __APPLE__
}
} // std
<commit_msg>Implement std::exception_ptr under libsupc++.<commit_after>

//===------------------------ exception.cpp -------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include <stdlib.h>
#include <stdio.h>

#include "exception"
#include "new"

#ifndef __has_include
#define __has_include(inc) 0
#endif

#ifdef __APPLE__
  #include <cxxabi.h>

  using namespace __cxxabiv1;
  #define HAVE_DEPENDENT_EH_ABI 1
  #ifndef _LIBCPPABI_VERSION
    using namespace __cxxabiapple;
    // On Darwin, there are two STL shared libraries and a lower level ABI
    // shared libray.  The globals holding the current terminate handler and
    // current unexpected handler are in the ABI library.
    #define __terminate_handler  __cxxabiapple::__cxa_terminate_handler
    #define __unexpected_handler __cxxabiapple::__cxa_unexpected_handler
  #endif  // _LIBCPPABI_VERSION
#elif defined(LIBCXXRT) || __has_include(<cxxabi.h>)
  #include <cxxabi.h>
  using namespace __cxxabiv1;
  #if defined(LIBCXXRT) || defined(_LIBCPPABI_VERSION)
    #define HAVE_DEPENDENT_EH_ABI 1
  #endif
#elif !defined(__GLIBCXX__) // __has_include(<cxxabi.h>)
  static std::terminate_handler  __terminate_handler;
  static std::unexpected_handler __unexpected_handler;
#endif // __has_include(<cxxabi.h>)

_LIBCPP_NORETURN
static void _libcpp_abort(const char* msg)
{
    printf("%s\n", msg);
    abort();
}

namespace std
{

#if !defined(LIBCXXRT) && !defined(_LIBCPPABI_VERSION) && !defined(__GLIBCXX__)

// libcxxrt provides implementations of these functions itself.
unexpected_handler
set_unexpected(unexpected_handler func) _NOEXCEPT
{
    return __sync_lock_test_and_set(&__unexpected_handler, func);
}

unexpected_handler
get_unexpected() _NOEXCEPT
{
    return __sync_fetch_and_add(&__unexpected_handler, (unexpected_handler)0);
}

_LIBCPP_NORETURN
void
unexpected()
{
    (*get_unexpected())();
    // unexpected handler should not return
    terminate();
}

terminate_handler
set_terminate(terminate_handler func) _NOEXCEPT
{
    return __sync_lock_test_and_set(&__terminate_handler, func);
}

terminate_handler
get_terminate() _NOEXCEPT
{
    return __sync_fetch_and_add(&__terminate_handler, (terminate_handler)0);
}

#ifndef EMSCRIPTEN // We provide this in JS
_LIBCPP_NORETURN
void
terminate() _NOEXCEPT
{
#ifndef _LIBCPP_NO_EXCEPTIONS
    try
    {
#endif  // _LIBCPP_NO_EXCEPTIONS
        (*get_terminate())();
        // handler should not return
        _libcpp_abort("terminate_handler unexpectedly returned\n");
#ifndef _LIBCPP_NO_EXCEPTIONS
    }
    catch (...)
    {
        // handler should not throw exception
        _libcpp_abort("terminate_handler unexpectedly threw an exception\n");
    }
#endif  // _LIBCPP_NO_EXCEPTIONS
}
#endif // !EMSCRIPTEN
#endif // !defined(LIBCXXRT) && !defined(_LIBCPPABI_VERSION)

#if !defined(LIBCXXRT) && !defined(__GLIBCXX__) && !defined(EMSCRIPTEN)
bool uncaught_exception() _NOEXCEPT
{
#if defined(__APPLE__) || defined(_LIBCPPABI_VERSION)
    // on Darwin, there is a helper function so __cxa_get_globals is private
    return __cxa_uncaught_exception();
#else  // __APPLE__
#   if defined(_MSC_VER) && ! defined(__clang__)
        _LIBCPP_WARNING("uncaught_exception not yet implemented")
#   else
#       warning uncaught_exception not yet implemented
#   endif
    _libcpp_abort("uncaught_exception not yet implemented\n");
#endif  // __APPLE__
}

#ifndef _LIBCPPABI_VERSION

exception::~exception() _NOEXCEPT
{
}

const char* exception::what() const _NOEXCEPT
{
  return "std::exception";
}

#endif  // _LIBCPPABI_VERSION
#endif //LIBCXXRT
#if !defined(_LIBCPPABI_VERSION) && !defined(__GLIBCXX__)

bad_exception::~bad_exception() _NOEXCEPT
{
}

const char* bad_exception::what() const _NOEXCEPT
{
  return "std::bad_exception";
}

#endif

#if defined(__GLIBCXX__)

// libsupc++ does not implement the dependent EH ABI and the functionality
// it uses to implement std::exception_ptr (which it declares as an alias of
// std::__exception_ptr::exception_ptr) is not directly exported to clients. So
// we have little choice but to hijack std::__exception_ptr::exception_ptr's
// (which fortunately has the same layout as our std::exception_ptr) copy
// constructor, assignment operator and destructor (which are part of its
// stable ABI), and its rethrow_exception(std::__exception_ptr::exception_ptr)
// function.

namespace __exception_ptr
{

struct exception_ptr
{
    void* __ptr_;

    exception_ptr(const exception_ptr&) _NOEXCEPT;
    exception_ptr& operator=(const exception_ptr&) _NOEXCEPT;
    ~exception_ptr() _NOEXCEPT;
};

}

_LIBCPP_NORETURN void rethrow_exception(__exception_ptr::exception_ptr);

#endif

exception_ptr::~exception_ptr() _NOEXCEPT
{
#if HAVE_DEPENDENT_EH_ABI
    __cxa_decrement_exception_refcount(__ptr_);
#elif defined(__GLIBCXX__)
    reinterpret_cast<__exception_ptr::exception_ptr*>(this)->~exception_ptr();
#else
#   if defined(_MSC_VER) && ! defined(__clang__)
        _LIBCPP_WARNING("exception_ptr not yet implemented")
#   else
#       warning exception_ptr not yet implemented
#   endif
    _libcpp_abort("exception_ptr not yet implemented\n");
#endif
}

exception_ptr::exception_ptr(const exception_ptr& other) _NOEXCEPT
    : __ptr_(other.__ptr_)
{
#if HAVE_DEPENDENT_EH_ABI
    __cxa_increment_exception_refcount(__ptr_);
#elif defined(__GLIBCXX__)
    new (reinterpret_cast<void*>(this)) __exception_ptr::exception_ptr(
        reinterpret_cast<const __exception_ptr::exception_ptr&>(other));
#else
#   if defined(_MSC_VER) && ! defined(__clang__)
        _LIBCPP_WARNING("exception_ptr not yet implemented")
#   else
#       warning exception_ptr not yet implemented
#   endif
    _libcpp_abort("exception_ptr not yet implemented\n");
#endif
}

exception_ptr& exception_ptr::operator=(const exception_ptr& other) _NOEXCEPT
{
#if HAVE_DEPENDENT_EH_ABI
    if (__ptr_ != other.__ptr_)
    {
        __cxa_increment_exception_refcount(other.__ptr_);
        __cxa_decrement_exception_refcount(__ptr_);
        __ptr_ = other.__ptr_;
    }
    return *this;
#elif defined(__GLIBCXX__)
    *reinterpret_cast<__exception_ptr::exception_ptr*>(this) =
        reinterpret_cast<const __exception_ptr::exception_ptr&>(other);
    return *this;
#else
#   if defined(_MSC_VER) && ! defined(__clang__)
        _LIBCPP_WARNING("exception_ptr not yet implemented")
#   else
#       warning exception_ptr not yet implemented
#   endif
    _libcpp_abort("exception_ptr not yet implemented\n");
#endif
}

nested_exception::nested_exception() _NOEXCEPT
    : __ptr_(current_exception())
{
}

#if !defined(__GLIBCXX__)

nested_exception::~nested_exception() _NOEXCEPT
{
}

#endif

_LIBCPP_NORETURN
void
nested_exception::rethrow_nested() const
{
    if (__ptr_ == nullptr)
        terminate();
    rethrow_exception(__ptr_);
}

#if !defined(__GLIBCXX__)

exception_ptr current_exception() _NOEXCEPT
{
#if HAVE_DEPENDENT_EH_ABI
    // be nicer if there was a constructor that took a ptr, then
    // this whole function would be just:
    //    return exception_ptr(__cxa_current_primary_exception());
    exception_ptr ptr;
    ptr.__ptr_ = __cxa_current_primary_exception();
    return ptr;
#else
#   if defined(_MSC_VER) && ! defined(__clang__)
        _LIBCPP_WARNING( "exception_ptr not yet implemented" )
#   else
#       warning exception_ptr not yet implemented
#   endif
    _libcpp_abort("exception_ptr not yet implemented\n");
#endif
}

#endif  // !__GLIBCXX__

_LIBCPP_NORETURN
void rethrow_exception(exception_ptr p)
{
#if HAVE_DEPENDENT_EH_ABI
    __cxa_rethrow_primary_exception(p.__ptr_);
    // if p.__ptr_ is NULL, above returns so we terminate
    terminate();
#elif defined(__GLIBCXX__)
    rethrow_exception(reinterpret_cast<__exception_ptr::exception_ptr&>(p));
#else
#   if defined(_MSC_VER) && ! defined(__clang__)
        _LIBCPP_WARNING("exception_ptr not yet implemented")
#   else
#       warning exception_ptr not yet implemented
#   endif
    _libcpp_abort("exception_ptr not yet implemented\n");
#endif
}
} // std
<|endoftext|>


<commit_before>#include "../network/network.h"
#include "../classifier/classifier.h"
#include "../trainer/trainer.h"
#include "../reader/reader.h"
#include "../reader/parsed_data.h"
#include <vector>
#include <iostream>
#include <sstream> //For char conversion
#include <string> //For char conversion

double get_average_error(std::vector<double> all_total_errors)
{
    double sum = 0.0;
    for(auto& total_error: all_total_errors)
    {
        sum += total_error;
    }
    double average = sum / all_total_errors.size();
    return average;
}

void classify_epoch(Network& network, TrainingData& training_data, Classifier& classifier)
{
    for(int i=0; i<training_data.data.size(); i++)
    {
        std::vector<double> new_inputs = training_data.data.at(i);
        classifier.set_input_values(new_inputs);
        classifier.classify();

        for(int j=0; j<new_inputs.size(); j++)
        {
            std::cout<< new_inputs.at(j);
            std::cout<< ",";
        }

        std::cout<< " - ";

        for(int k=0; k<network.output_layer.size(); k++)
        {
            std::cout<< network.output_layer.at(k).outgoing_value;
            std::cout<< ",";
        }
        std::cout<< std::endl;
    }
}

void train_epoch(Network& network, TrainingData& training_data, Classifier& classifier, Trainer& trainer)
{
    std::vector<double> all_total_errors;

    for(int i=0; i < training_data.data.size(); i++)
    {
        std::vector<double> new_inputs = training_data.data.at(i);
        classifier.set_input_values(new_inputs);
        classifier.classify();

        std::vector<double> new_targets = training_data.targets.at(i);
        trainer.set_target_values(new_targets);
        trainer.train();

        double total_error = trainer.calculate_total_error(network.output_layer);
        all_total_errors.emplace_back(total_error);
    }

    trainer.epoch += 1;
    network.epoch_average_total_error = get_average_error(all_total_errors);
    if(trainer.epoch % 500 == 0)
    {
        std::cout<< trainer.epoch<<", "<< network.epoch_average_total_error<< std::endl;
    }
}

int main(int argc, char** argv)
{
    std::string file_name;
    if(argc > 0)
    {
        file_name = std::string(argv[1]);
    } else
    {
        std::string file_name = "data/training/scatter_plot";
    }
    Reader reader;
    TrainingData training_data = reader.read_training_data(file_name);
    Network network(training_data.structure);
    Classifier classifier(network);
    Trainer trainer(network, training_data.learning_rate);

    std::cout<< "Epoch"<<", "<< "epoch_average_total_error"<< std::endl;
    train_epoch(network, training_data, classifier, trainer);

    while(network.epoch_average_total_error > training_data.target_total_error)
    {
        train_epoch(network, training_data, classifier, trainer);
    }

    classify_epoch(network, training_data, classifier);
    return 0;
}
<commit_msg>Found some magic numbers, which I frown upon<commit_after>#include "../network/network.h"
#include "../network/neuron/neuron.h"
#include "../classifier/classifier.h"
#include "../trainer/trainer.h"
#include "../reader/reader.h"
#include "../reader/parsed_data.h"
#include <vector>
#include <iostream>
#include <sstream> //For char conversion
#include <string> //For char conversion

double get_average_error(std::vector<double> all_total_errors)
{
    double sum = 0.0;
    for(auto& total_error: all_total_errors)
    {
        sum += total_error;
    }
    double average = sum / all_total_errors.size();
    return average;
}

void classify_epoch(Network& network, TrainingData& training_data, Classifier& classifier)
{
    int training_data_size = training_data.data.size();

    for(int i=0; i<training_data_size; i++)
    {
        std::vector<double> new_inputs = training_data.data.at(i);
        classifier.set_input_values(new_inputs);
        classifier.classify();

        int new_inputs_size = new_inputs.size();
        for(int j=0; j<new_inputs_size; j++)
        {
            std::cout<< new_inputs.at(j);
            std::cout<< ",";
        }

        std::cout<< " - ";

        std::vector<Neuron> updated_outputs = network.output_layer;

        int updated_outputs_size = updated_outputs.size();
        for(int k=0; k<updated_outputs_size; k++)
        {
            std::cout<< updated_outputs.at(k).outgoing_value;
            std::cout<< ",";
        }
        std::cout<< std::endl;
    }
}

void train_epoch(Network& network, TrainingData& training_data, Classifier& classifier, Trainer& trainer)
{
    std::vector<double> all_total_errors;
    int training_data_size = training_data.data.size();

    for(int i=0; i<training_data_size; i++)
    {
        std::vector<double> new_inputs = training_data.data.at(i);
        classifier.set_input_values(new_inputs);
        classifier.classify();

        std::vector<double> new_targets = training_data.targets.at(i);
        trainer.set_target_values(new_targets);
        trainer.train();

        double total_error = trainer.calculate_total_error(network.output_layer);
        all_total_errors.emplace_back(total_error);
    }

    trainer.epoch += 1;
    network.epoch_average_total_error = get_average_error(all_total_errors);
    if(trainer.epoch % 500 == 0)
    {
        std::cout<< trainer.epoch<<", "<< network.epoch_average_total_error<< std::endl;
    }
}

int main(int argc, char** argv)
{
    std::string file_name;
    if(argc > 0)
    {
        file_name = std::string(argv[1]);
    } else
    {
        std::string file_name = "data/training/scatter_plot";
    }
    Reader reader;
    TrainingData training_data = reader.read_training_data(file_name);
    Network network(training_data.structure);
    Classifier classifier(network);
    Trainer trainer(network, training_data.learning_rate);

    std::cout<< "Epoch"<<", "<< "epoch_average_total_error"<< std::endl;
    train_epoch(network, training_data, classifier, trainer);

    while(network.epoch_average_total_error > training_data.target_total_error)
    {
        train_epoch(network, training_data, classifier, trainer);
    }

    classify_epoch(network, training_data, classifier);
    return 0;
}
<|endoftext|>


<commit_before>/*
   //gSystem->AddIncludePath("-I$ALICE_ROOT/PWG1/TPC");
   //.L $ALICE_ROOT/PWG1/TPC/macros/MakeReportTPC.C+
   //
   //MakeReportTPC();

   gSystem->AddIncludePath("-I$ALICE_ROOT/TPC/macros");
   gROOT->LoadMacro("$ALICE_ROOT/TPC/macros/AliXRDPROOFtoolkit.cxx+")
   AliXRDPROOFtoolkit tool;
   TChain * chain = tool.MakeChain("summaryTPCQA.txt","tpcQA",0,200000);
*/

#if !defined(__CINT__) || defined(__MAKECINT__)
#include "TSystem.h"
#include "TFile.h"
#include "TGrid.h"
#include "TF1.h"
#include "TH1.h"
#include "TH2.h"
#include "TProfile.h"
#include "THnSparse.h"
#include "TTreeStream.h"
#include "AliPerformanceTPC.h"
#endif

TObject *pTPCObject=0;
TTreeSRedirector  *pcstream=0;
void Init();
void ReadObjects(const char * path=0);
void MakeReportTPC(Int_t run, const char *path=0 );
void AnalyzeNCL();
void AnalyzeDrift();

void Init(){
  //
  //
  //
  gSystem->Load("libANALYSIS.so");
  gSystem->Load("libANALYSISalice.so");
  gSystem->Load("libTENDER.so");
  gSystem->Load("libCORRFW.so");
  gSystem->Load("libPWG0base.so");
  gSystem->Load("libPWG0dep.so");
  gSystem->Load("libPWG0selectors.so");
  gSystem->Load("libPWG1.so");
  gSystem->Load("libTPCcalib");
  gSystem->Setenv("alien_CLOSE_SE","ALICE::GSI::SE");
  TGrid::Connect("alien://",0,0,"t");
  gSystem->Setenv("alien_CLOSE_SE","ALICE::GSI::SE");
}

void ReadObjects(const char * path){
  //
  //
  //
  TFile *f =0;
  if (path) f=TFile::Open(Form("%s/TPC.PerformanceQAQA.root",path));
  if (!path) f=TFile::Open("TPC.Performance.root");
  if (!f){
    printf("File %s not available\n", path);
    return;
  }
  TList *list = (TList*)f->Get("TPC");
  if (!list){
    printf("QA %s not available\n", path);
    return;
  }
  pTPCObject= (AliPerformanceTPC*)list->FindObject("AliPerformanceTPC");
}

void MakeReportTPC(Int_t run, const char *path ){
  //
  // make a tpcQA report
  //  typical variables exported to the tree
  //
  Init();
  ReadObjects(path);

  pcstream= new TTreeSRedirector("TPC.PerformanceSummary.root");
  (*pcstream)<<"tpcQA"<<"run="<<run;
  AnalyzeNCL();
  AnalyzeDrift();
  (*pcstream)<<"tpcQA"<<"\n";
  delete pcstream;
}

void AnalyzeNCL(){
  //
  // NCL statistic
  //
  // variables:
  static Double_t meanTPCnclF=0;
  static Double_t rmsTPCnclF=0;
  static Double_t slopeATPCnclF=0;
  static Double_t slopeCTPCnclF=0;
  static Double_t meanTPCncl=0;
  static Double_t rmsTPCncl=0;
  static Double_t slopeATPCncl=0;
  static Double_t slopeCTPCncl=0;
  AliPerformanceTPC * pTPC=  (AliPerformanceTPC *)pTPCObject;

  TH1* his1D=0;
  TProfile* hprof=0;
  static TF1 *fpol1 = new TF1("fpol1","pol1");
  //
  // all clusters
  // eta cut - +-1
  // pt cut  - +-0.250 GeV
  pTPC->GetTPCTrackHisto()->GetAxis(5)->SetRangeUser(-1.,1.);
  pTPC->GetTPCTrackHisto()->GetAxis(7)->SetRangeUser(0.25,10);
  his1D = pTPC->GetTPCTrackHisto()->Projection(0);
  meanTPCncl= his1D->GetMean();
  rmsTPCncl= his1D->GetRMS();
  delete his1D;
  hprof = pTPC->GetTPCTrackHisto()->Projection(0,5)->ProfileX();
  hprof->Fit(fpol1,"QNR","QNR",0,0.8);
  slopeATPCncl= fpol1->GetParameter(1);
  hprof->Fit(fpol1,"QNR","QNR",-0.8,0.0);
  slopeCTPCncl= fpol1->GetParameter(1);
  delete hprof;
  //
  // findable clusters
  //
  pTPC->GetTPCTrackHisto()->GetAxis(2)->SetRangeUser(0.4,1.1);
  his1D = pTPC->GetTPCTrackHisto()->Projection(2);
  meanTPCnclF= his1D->GetMean();
  rmsTPCnclF= his1D->GetRMS();
   delete his1D;
  his1D = pTPC->GetTPCTrackHisto()->Projection(2,5)->ProfileX();
  his1D->Fit(fpol1,"QNR","QNR",0,0.8);
  slopeATPCnclF= fpol1->GetParameter(1);
  his1D->Fit(fpol1,"QNR","QNR",-0.8,0.0);
  slopeCTPCnclF= fpol1->GetParameter(1);
  delete his1D;
  printf("Cluster QA report\n");
  printf("meanTPCnclF=\t%f\n",meanTPCnclF);
  printf("rmsTPCnclF=\t%f\n",rmsTPCnclF);
  printf("slopeATPCnclF=\t%f\n",slopeATPCnclF);
  printf("slopeCTPCnclF=\t%f\n",slopeCTPCnclF);
  printf("meanTPCncl=\t%f\n",meanTPCncl);
  printf("rmsTPCncl=\t%f\n",rmsTPCncl);
  printf("slopeATPCncl=\t%f\n",slopeATPCncl);
  printf("slopeCTPCncl=\t%f\n",slopeCTPCncl);
  //
  // dump results to the tree
  //
  (*pcstream)<<"tpcQA"<<
    "meanTPCnclF="<<meanTPCnclF <<
    "rmsTPCnclF="<<rmsTPCnclF <<
    "slopeATPCnclF="<< slopeATPCnclF<<
    "slopeCTPCnclF="<< slopeCTPCnclF<<
    "meanTPCncl="<<meanTPCncl <<
    "rmsTPCncl="<< rmsTPCncl<<
    "slopeATPCncl="<< slopeATPCncl<<
    "slopeCTPCncl="<< slopeCTPCncl;

}

void AnalyzeDrift(){
  //
  // Analyze drift velocity imperfections
  //
  // variables:
  static Double_t offsetdZA=0;
  static Double_t slopedZA=0;
  static Double_t offsetdZC=0;
  static Double_t slopedZC=0;
  AliPerformanceTPC * pTPC=  (AliPerformanceTPC *)pTPCObject;

  TH1* his1D=0;
  TH2* his2D=0;
  static TF1 *fpol1 = new TF1("fpol1","pol1");
  TObjArray arrayFit;
  his2D = pTPC->GetTPCTrackHisto()->Projection(4,5);
  his2D->FitSlicesY(0,0,-1,10,"QNR",&arrayFit);
  delete his2D;
  his1D = (TH1*) arrayFit.At(1);
  his1D->Fit(fpol1,"QNR","QNR",-0.8,-0.1);
  offsetdZC=fpol1->GetParameter(0);
  slopedZC=fpol1->GetParameter(1);
  his1D->Fit(fpol1,"QNR","QNR",0.1,0.8);
  offsetdZA=fpol1->GetParameter(0);
  slopedZA=fpol1->GetParameter(1);
  //
  printf("Drift velocity QA report\n");
  printf("offsetdZA\t%f\n",offsetdZA);
  printf("slopedZA\t%f\n",slopedZA);
  printf("offsetdZC\t%f\n",offsetdZC);
  printf("slopedZC\t%f\n",slopedZC);
  //
  // dump drift QA values
  //
  (*pcstream)<<"tpcQA"<<
    "offsetdZA="<< offsetdZA<<
    "slopedZA="<< slopedZA<<
    "offsetdZC="<< offsetdZC<<
    "slopedZC="<<slopedZC;

}
<commit_msg>Adding chi2 of the fit. (Marian)<commit_after>/*
   //gSystem->AddIncludePath("-I$ALICE_ROOT/PWG1/TPC");
   //.L $ALICE_ROOT/PWG1/TPC/macros/MakeReportTPC.C+
   //
   //MakeReportTPC();

   gSystem->AddIncludePath("-I$ALICE_ROOT/TPC/macros");
   gROOT->LoadMacro("$ALICE_ROOT/TPC/macros/AliXRDPROOFtoolkit.cxx+")
   AliXRDPROOFtoolkit tool;
   TChain * chain = tool.MakeChain("summaryTPCQA.txt","tpcQA",0,200000);

   TTree *tree = chain->CopyTree("1");
*/

#if !defined(__CINT__) || defined(__MAKECINT__)
#include "TSystem.h"
#include "TMath.h"
#include "TVectorD.h"
#include "TFile.h"
#include "TGrid.h"
#include "TF1.h"
#include "TH1.h"
#include "TH2.h"
#include "TProfile.h"
#include "THnSparse.h"
#include "TTreeStream.h"
#include "AliPerformanceTPC.h"
#include "AliPerformanceDEdx.h"
#endif

TObject *pTPCObject=0;
TObject *pTPCObjectGain=0;
TTreeSRedirector  *pcstream=0;
void Init();
void ReadObjects(const char * path=0);
void MakeReportTPC(Int_t run, const char *path=0 );
void AnalyzeNCL();
void AnalyzeDrift();
void AnalyzeGain();

void Init(){
  //
  //
  //
  gSystem->Load("libANALYSIS.so");
  gSystem->Load("libANALYSISalice.so");
  gSystem->Load("libTENDER.so");
  gSystem->Load("libCORRFW.so");
  gSystem->Load("libPWG0base.so");
  gSystem->Load("libPWG0dep.so");
  gSystem->Load("libPWG0selectors.so");
  gSystem->Load("libPWG1.so");
  gSystem->Load("libTPCcalib");
//   gSystem->Setenv("alien_CLOSE_SE","ALICE::GSI::SE");
//   TGrid::Connect("alien://",0,0,"t");
//   gSystem->Setenv("alien_CLOSE_SE","ALICE::GSI::SE");
}

void ReadObjects(const char * path){
  //
  //
  //
  TFile *f =0;
  if (path) f=TFile::Open(Form("%s/TPC.PerformanceQAQA.root",path));
  if (!path) f=TFile::Open("TPC.Performance.root");
  if (!f){
    printf("File %s not available\n", path);
    return;
  }
  TList *list = (TList*)f->Get("TPC");
  if (!list){
    printf("QA %s not available\n", path);
    return;
  }
  pTPCObject= (AliPerformanceTPC*)list->FindObject("AliPerformanceTPC");
  pTPCObjectGain = (AliPerformanceDEdx*)list->FindObject("AliPerformanceDEdxTPCInner");
}

void MakeReportTPC(Int_t run, const char *path ){
  //
  // make a tpcQA report
  //  typical variables exported to the tree
  //
  Init();
  ReadObjects(path);

  pcstream= new TTreeSRedirector("TPC.PerformanceSummary.root");
  (*pcstream)<<"tpcQA"<<"run="<<run;
  AnalyzeNCL();
  AnalyzeDrift();
  AnalyzeGain();
  (*pcstream)<<"tpcQA"<<"\n";
  delete pcstream;
}

void AnalyzeNCL(){
  //
  // NCL statistic
  //
  // variables:
  static Double_t meanTPCnclF=0;
  static Double_t rmsTPCnclF=0;
  static Double_t slopeATPCnclF=0;
  static Double_t slopeCTPCnclF=0;
  static Double_t slopeATPCnclFErr=0;
  static Double_t slopeCTPCnclFErr=0;
  static Double_t meanTPCncl=0;
  static Double_t rmsTPCncl=0;
  static Double_t slopeATPCncl=0;
  static Double_t slopeCTPCncl=0;
  static Double_t slopeATPCnclErr=0;
  static Double_t slopeCTPCnclErr=0;
  AliPerformanceTPC * pTPC=  (AliPerformanceTPC *)pTPCObject;

  TH1* his1D=0;
  TProfile* hprof=0;
  static TF1 *fpol1 = new TF1("fpol1","pol1");
  //
  // all clusters
  // eta cut - +-1
  // pt cut  - +-0.250 GeV
  pTPC->GetTPCTrackHisto()->GetAxis(5)->SetRangeUser(-1.,1.);
  pTPC->GetTPCTrackHisto()->GetAxis(7)->SetRangeUser(0.25,10);
  his1D = pTPC->GetTPCTrackHisto()->Projection(0);
  meanTPCncl= his1D->GetMean();
  rmsTPCncl= his1D->GetRMS();
  delete his1D;
  hprof = pTPC->GetTPCTrackHisto()->Projection(0,5)->ProfileX();
  hprof->Fit(fpol1,"QNR","QNR",0,0.8);
  slopeATPCncl= fpol1->GetParameter(1);
  slopeATPCnclErr= fpol1->GetParError(1);
  hprof->Fit(fpol1,"QNR","QNR",-0.8,0.0);
  slopeCTPCncl= fpol1->GetParameter(1);
  slopeCTPCnclErr= fpol1->GetParameter(1);
  delete hprof;
  //
  // findable clusters
  //
  pTPC->GetTPCTrackHisto()->GetAxis(2)->SetRangeUser(0.4,1.1);
  his1D = pTPC->GetTPCTrackHisto()->Projection(2);
  meanTPCnclF= his1D->GetMean();
  rmsTPCnclF= his1D->GetRMS();
  delete his1D;
  his1D = pTPC->GetTPCTrackHisto()->Projection(2,5)->ProfileX();
  his1D->Fit(fpol1,"QNR","QNR",0,0.8);
  slopeATPCnclF= fpol1->GetParameter(1);
  slopeATPCnclFErr= fpol1->GetParError(1);
  his1D->Fit(fpol1,"QNR","QNR",-0.8,0.0);
  slopeCTPCnclF= fpol1->GetParameter(1);
  slopeCTPCnclFErr= fpol1->GetParameter(1);
  delete his1D;
  printf("Cluster QA report\n");
  printf("meanTPCnclF=\t%f\n",meanTPCnclF);
  printf("rmsTPCnclF=\t%f\n",rmsTPCnclF);
  printf("slopeATPCnclF=\t%f\n",slopeATPCnclF);
  printf("slopeCTPCnclF=\t%f\n",slopeCTPCnclF);
  printf("meanTPCncl=\t%f\n",meanTPCncl);
  printf("rmsTPCncl=\t%f\n",rmsTPCncl);
  printf("slopeATPCncl=\t%f\n",slopeATPCncl);
  printf("slopeCTPCncl=\t%f\n",slopeCTPCncl);
  //
  // dump results to the tree
  //
  (*pcstream)<<"tpcQA"<<
    "meanTPCnclF="<<meanTPCnclF <<
    "rmsTPCnclF="<<rmsTPCnclF <<
    "slopeATPCnclF="<< slopeATPCnclF<<
    "slopeCTPCnclF="<< slopeCTPCnclF<<
    "slopeATPCnclFErr="<< slopeATPCnclFErr<<
    "slopeCTPCnclFErr="<< slopeCTPCnclFErr<<
    "meanTPCncl="<<meanTPCncl <<
    "rmsTPCncl="<< rmsTPCncl<<
    "slopeATPCncl="<< slopeATPCncl<<
    "slopeCTPCncl="<< slopeCTPCncl<<
    "slopeATPCnclErr="<< slopeATPCnclErr<<
    "slopeCTPCnclErr="<< slopeCTPCnclErr;

}

void AnalyzeDrift(){
  //
  // Analyze drift velocity imperfections
  //
  // variables:
  static Double_t offsetdZA=0;
  static Double_t slopedZA=0;
  static Double_t offsetdZC=0;
  static Double_t slopedZC=0;
  static Double_t offsetdZAErr=0;
  static Double_t slopedZAErr=0;
  static Double_t offsetdZCErr=0;
  static Double_t slopedZCErr=0;
  static Double_t offsetdZAchi2=0;
  static Double_t slopedZAchi2=0;
  static Double_t offsetdZchi2=0;
  static Double_t slopedZCchi2=0;
  AliPerformanceTPC * pTPC=  (AliPerformanceTPC *)pTPCObject;

  TH1* his1D=0;
  TH2* his2D=0;
  static TF1 *fpol1 = new TF1("fpol1","pol1");
  TObjArray arrayFit;
  his2D = pTPC->GetTPCTrackHisto()->Projection(4,5);
  his2D->FitSlicesY(0,0,-1,10,"QNR",&arrayFit);
  delete his2D;
  his1D = (TH1*) arrayFit.At(1);
  his1D->Fit(fpol1,"QNRROB=0.8","QNR",-0.8,-0.1);
  offsetdZC=fpol1->GetParameter(0);
  slopedZC=fpol1->GetParameter(1);
  offsetdZCchi2=fpol1->GetChisquare();
  slopedZCchi2=fpol1->GetChisquare();
  //
  his1D->Fit(fpol1,"QNRROB=0.8","QNR",0.1,0.8);
  offsetdZA=fpol1->GetParameter(0);
  slopedZA=fpol1->GetParameter(1);
  offsetdZAErr=fpol1->GetParError(0);
  slopedZAErr=fpol1->GetParError(1);
  offsetdZAchi2=fpol1->GetChisquare();
  slopedZAchi2=fpol1->GetChisquare();
  //
  printf("Drift velocity QA report\n");
  printf("offsetdZA\t%f\n",offsetdZA);
  printf("slopedZA\t%f\n",slopedZA);
  printf("offsetdZC\t%f\n",offsetdZC);
  printf("slopedZC\t%f\n",slopedZC);
  //
  // dump drift QA values
  //
  (*pcstream)<<"tpcQA"<<
    "offsetdZA="<< offsetdZA<<
    "slopedZA="<< slopedZA<<
    "offsetdZC="<< offsetdZC<<
    "slopedZC="<<slopedZC<<
    //
    "offsetdZAErr="<< offsetdZAErr<<
    "slopedZAErr="<< slopedZAErr<<
    "offsetdZCErr="<< offsetdZCErr<<
    "slopedZCErr="<<slopedZCErr<<
    //
    "offsetdZAchi2="<< offsetdZAchi2<<
    "slopedZAchi2="<< slopedZAchi2<<
    "offsetdZCchi2="<< offsetdZCchi2<<
    "slopedZCchi2="<<slopedZCchi2;

}

void AnalyzeGain(){
  //
  // gain statistic
  //
  AliPerformanceDEdx * pTPCgain =  (AliPerformanceDEdx *)pTPCObjectGain;
  static TVectorD MIPvsSector(36);
  static TVectorD sector(36);
  static Float_t MIPmean = 0;
  static Float_t MIPresolution = 0;
  static Float_t attachSlopeC = 0;
  static Float_t attachSlopeA = 0;

  MIPvsSector.Zero();
  //
  // select MIP particles
  //
  pTPCgain->GetDeDxHisto()->GetAxis(7)->SetRangeUser(0.4,0.55);
  pTPCgain->GetDeDxHisto()->GetAxis(0)->SetRangeUser(35,60);
  pTPCgain->GetDeDxHisto()->GetAxis(6)->SetRangeUser(80,160);
  pTPCgain->GetDeDxHisto()->GetAxis(5)->SetRangeUser(-1,1);
  //
  // MIP position and resolution
  //
  TF1 gausFit("gausFit","gaus");
  TH1 * hisProj1D = pTPCgain->GetDeDxHisto()->Projection(0);
  hisProj1D->Fit(&gausFit,"QN","QN");
  delete hisProj1D;
  MIPmean = gausFit.GetParameter(1);
  MIPresolution = 0;
  if (MIPmean!=0) MIPresolution = gausFit.GetParameter(2)/MIPmean;
  //
  // MIP position vs. dip angle (attachment)
  //
  pTPCgain->GetDeDxHisto()->GetAxis(5)->SetRangeUser(-3,0);
  TH2* his2D = pTPCgain->GetDeDxHisto()->Projection(0,5);
  TF1 * fpol = new TF1("fpol","pol1");
  TObjArray arrayFit;
  his2D->FitSlicesY(0,0,-1,10,"QN",&arrayFit);
  delete his2D;
  TH1 * his1D = (TH1*) arrayFit.At(1);
  his1D->Fit(fpol,"QNROB=0.8","QNR",-1,0);
  attachSlopeC = fpol->GetParameter(1);
  //
  pTPCgain->GetDeDxHisto()->GetAxis(5)->SetRangeUser(0,3);
  TH2* his2DA = pTPCgain->GetDeDxHisto()->Projection(0,5);
  TF1 * fpolA = new TF1("fpolA","pol1");
  TObjArray arrayFitA;
  his2DA->FitSlicesY(0,0,-1,10,"QN",&arrayFit);
  delete his2DA;
  TH1 * his1DA = (TH1*) arrayFit.At(1);
  his1DA->Fit(fpolA,"QNROB=0.8","QN",0,1);
  attachSlopeA = fpolA->GetParameter(1);
  //
  // MIP position vs. sector
  //
  pTPCgain->GetDeDxHisto()->GetAxis(5)->SetRangeUser(-3,0); // C side
  for(Int_t i = 0; i < 18; i++) { // loop over sectors; correct mapping to be checked!
    TH1* his1D=0;
    Float_t phiLow = -TMath::Pi() + i*(20./360.)*(2*TMath::Pi());
    Float_t phiUp  = -TMath::Pi() + (i+1)*(20./360.)*(2*TMath::Pi());
    pTPCgain->GetDeDxHisto()->GetAxis(1)->SetRangeUser(phiLow,phiUp);
    his1D = pTPCgain->GetDeDxHisto()->Projection(0);
    TF1 gausFunc("gausFunc","gaus");
    his1D->Fit(&gausFunc, "QN");
    MIPvsSector(i) = gausFunc.GetParameter(1);
    sector(i)=i;
    delete his1D;
  }
  //
  pTPCgain->GetDeDxHisto()->GetAxis(5)->SetRangeUser(0,3); // A side
  for(Int_t i = 0; i < 18; i++) { // loop over sectors; correct mapping to be checked!
    TH1* his1D=0;
    Float_t phiLow = -TMath::Pi() + i*(20./360.)*(2*TMath::Pi());
    Float_t phiUp  = -TMath::Pi() + (i+1)*(20./360.)*(2*TMath::Pi());
    pTPCgain->GetDeDxHisto()->GetAxis(1)->SetRangeUser(phiLow,phiUp);
    his1D = pTPCgain->GetDeDxHisto()->Projection(0);
    TF1 gausFunc("gausFunc","gaus");
    his1D->Fit(&gausFunc, "QN");
    MIPvsSector(i+18) = gausFunc.GetParameter(1);
    sector(i+18)=i+18;
    delete his1D;
  }
  //
  printf("Gain QA report\n");
  printf("MIP mean\t%f\n",MIPmean);
  printf("MIP resolution\t%f\n",MIPresolution);
  printf("MIPslopeA\t%f\n",attachSlopeA);
  printf("MIPslopeC\t%f\n",attachSlopeC);
  //
  (*pcstream)<<"tpcQA"<<
    "MIPattachSlopeC="<<attachSlopeC<<
    "MIPattachSlopeA="<<attachSlopeA<<
    "MIPresolution="<<MIPresolution<<
    "MIPvsSector.="<<&MIPvsSector<<
    "sector.="<<&sector<<
    "MIPmean="<<MIPmean;

}
<|endoftext|>


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

Program:   Medical Imaging & Interaction Toolkit
Language:  C++
Date:      $Date$
Version:   $Revision$

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#include "mitkVolumeDataVtkMapper3D.h"
#include "QmitkAbortEventFilter.h"
#include "QmitkRenderWindow.h"
#include "mitkRenderingManager.h"
#include "QmitkRenderingManager.h"

#include "mitkNodePredicateProperty.h"
#include "mitkDataStorage.h"
#include "mitkProperties.h"

#include "QVTKWidget.h"

#include <qapplication.h>
#include <qeventloop.h>
#include <qguardedptr.h>

QmitkAbortEventFilter*
QmitkAbortEventFilter
::GetInstance()
{
  static QmitkAbortEventFilter instance;
  return &instance;
}

QmitkAbortEventFilter
::QmitkAbortEventFilter()
: m_LODRendererAtButtonPress( NULL )
{
}

QmitkAbortEventFilter
::~QmitkAbortEventFilter()
{
}

bool
QmitkAbortEventFilter
::eventFilter( QObject *object, QEvent *event )
{
  // Extract renderer (if event has been invoked on a RenderWindow)
  bool isLODRenderer = false;
  mitk::BaseRenderer *renderer = NULL;
  QVTKWidget *qVTKWidget = dynamic_cast< QVTKWidget * >( object );
  if (qVTKWidget != NULL )
  {
    renderer = mitk::BaseRenderer::GetInstance( qVTKWidget->GetRenderWindow() );
    if ( renderer && renderer->GetNumberOfVisibleLODEnabledMappers() > 0 )
    {
      isLODRenderer = true;
    }
    else
    {
      // Only LOD enabled renderers are considered
      renderer = NULL;
    }

  }

  if (mitk::RenderingManager::GetInstance()->IsRendering() )
  {
    switch ( event->type() )
    {

    case QEvent::MouseButtonPress:
    {
      // Let only the first (RenderWindow specific) click event affect
      // the LOD process (Qt issues multiple events on mouse click, but the
      // RenderWindow specific one is issued first)
      if ( !m_ButtonPressed )
      {
        m_ButtonPressed = true;

        mitk::RenderingManager::GetInstance()->AbortRendering();

        // For non-LOD RenderWindows, renderer is set to NULL and consequently,
        // the LOD counters for ALL RenderWindows are reset to 0.
        mitk::RenderingManager::GetInstance()->SetNextLOD( 0, renderer );
        mitk::RenderingManager::GetInstance()->LODIncreaseBlockedOn();

        // Store renderer (if LOD-enabled), otherwise renderer will be NULL
        m_LODRendererAtButtonPress = renderer;
      }

      // Store renderer if it is LOD enabled for mouse release
      if ( isLODRenderer )
      {
        m_LODRendererAtButtonPress = renderer;
      }

      QMouseEvent* me = ( QMouseEvent* )( event );
      QMouseEvent* newEvent = new QMouseEvent(
        me->type(), me->pos(), me->globalPos(), me->button(), me->state()
      );
      m_EventQueue.push( ObjectEventPair(QGuardedPtr< QObject >( object ), newEvent) );
      return true;
    }

    case QEvent::MouseButtonDblClick:
    {
      mitk::RenderingManager::GetInstance()->AbortRendering();
      QMouseEvent* me = ( QMouseEvent* )( event );

      QMouseEvent* newEvent = new QMouseEvent(
        me->type(), me->pos(), me->globalPos(), me->button(), me->state()
      );
      m_EventQueue.push( ObjectEventPair(QGuardedPtr< QObject >( object ), newEvent) );
      return true;
    }

    case QEvent::MouseMove:
    {
      if ( m_ButtonPressed )
      {
        if ( isLODRenderer && mitk::RenderingManager::GetInstance()->GetNextLOD( m_LODRendererAtButtonPress ) != 0 )
        {
          mitk::RenderingManager::GetInstance()->SetNextLOD( 0, m_LODRendererAtButtonPress );
          mitk::RenderingManager::GetInstance()->AbortRendering();
        }
      }
      return true;
    }

    case QEvent::MouseButtonRelease:
    {
      if ( m_ButtonPressed )
      {
        m_ButtonPressed = false;

        mitk::RenderingManager::GetInstance()->LODIncreaseBlockedOff();
      }

      QMouseEvent* me = ( QMouseEvent* )( event );
      QMouseEvent* newEvent = new QMouseEvent(
        me->type(), me->pos(), me->globalPos(), me->button(), me->state()
      );
      m_EventQueue.push( ObjectEventPair(QGuardedPtr< QObject >( object ), newEvent) );
      return true;
    }

    case QEvent::Wheel:
    {
      mitk::RenderingManager::GetInstance()->SetNextLOD( 0, renderer );
      mitk::RenderingManager::GetInstance()->AbortRendering();

      QWheelEvent* we = ( QWheelEvent* )( event );
      QWheelEvent* newEvent = new QWheelEvent(
        we->pos(), we->globalPos(), we->delta(), we->state(), we->orientation()
      );
      m_EventQueue.push( ObjectEventPair(QGuardedPtr< QObject >( object ), newEvent) );
      return true;
    }

    case QEvent::Paint:
    {
      QPaintEvent* pe = ( QPaintEvent* )( event );
      QPaintEvent* newEvent = new QPaintEvent( pe->region() );
      m_EventQueue.push( ObjectEventPair(QGuardedPtr< QObject >( object ), newEvent) );
      return true;
    }

    case QEvent::KeyPress:
    {
      mitk::RenderingManager::GetInstance()->AbortRendering();
      QKeyEvent* ke = ( QKeyEvent* )( event );
      QKeyEvent* newEvent = new QKeyEvent(
        ke->type(), ke->key(), ke->ascii(), ke->state(), ke->text(), false, ke->count()
      );
      m_EventQueue.push( ObjectEventPair(QGuardedPtr< QObject >( object ), newEvent) );
      return true;
    }

    case QmitkRenderingRequestEvent::RenderingRequest:
    {
      QmitkRenderingRequestEvent *newEvent = new QmitkRenderingRequestEvent();
      m_EventQueue.push( ObjectEventPair(QGuardedPtr< QObject >( object ), newEvent) );
      return true;
    }

    default:
    {
      return false;
    }
    }
  }
  else
  {
    switch ( event->type() )
    {
      case QEvent::MouseButtonPress:
      {
        // Let only the first (RenderWindow specific) click event affect
        // the LOD process (Qt issues multiple events on mouse click, but the
        // RenderWindow specific one is issued first)
        if ( !m_ButtonPressed )
        {
          m_ButtonPressed = true;
          //mitk::RenderingManager::GetInstance()->SetNextLOD( 0, renderer );
          mitk::RenderingManager::GetInstance()->LODIncreaseBlockedOn();

          m_LODRendererAtButtonPress = renderer;
        }

        // Store renderer if it is LOD enabled for mouse release
        if ( isLODRenderer )
        {
          m_LODRendererAtButtonPress = renderer;
        }

        return false;
      }

      case QEvent::MouseMove:
      {
        // Nothing to do in this case
        return false;
      }

      case QEvent::Wheel:
      {
        mitk::RenderingManager::GetInstance()->RequestUpdateAll(
          mitk::RenderingManager::REQUEST_UPDATE_3DWINDOWS );
        return false;
      }

      case QEvent::MouseButtonRelease:
      {
        if ( m_ButtonPressed )
        {
          m_ButtonPressed = false;
          mitk::RenderingManager::GetInstance()->LODIncreaseBlockedOff();

          if ( m_LODRendererAtButtonPress != NULL )
          {
            mitk::RenderingManager::GetInstance()->RequestUpdate(
              m_LODRendererAtButtonPress->GetRenderWindow() );
          }
          else
          {
            mitk::RenderingManager::GetInstance()->RequestUpdateAll(
              mitk::RenderingManager::REQUEST_UPDATE_3DWINDOWS );
          }
        }
        return false;
      }

      case QEvent::Resize:
      {
        mitk::RenderingManager::GetInstance()->RequestUpdateAll(
          mitk::RenderingManager::REQUEST_UPDATE_3DWINDOWS );
        return false;
      }

      case QEvent::ChildInserted:
      {
        mitk::RenderingManager::GetInstance()->RequestUpdateAll(
          mitk::RenderingManager::REQUEST_UPDATE_3DWINDOWS );
        return false;
      }

      default:
      {
        return false;
      }
    }
  }
}

void
QmitkAbortEventFilter
::ProcessEvents()
{
  qApp->eventLoop()->processEvents( QEventLoop::AllEvents );
}

void
QmitkAbortEventFilter
::IssueQueuedEvents()
{
  while ( !m_EventQueue.empty() )
  {
    ObjectEventPair eventPair = m_EventQueue.front();
    if ( eventPair.first )
    {
      QApplication::postEvent( eventPair.first, eventPair.second );
    }
    m_EventQueue.pop();
  }
}
<commit_msg>ENH (#976): Check for more events in QmitkAbortEventFilter; use typedef for GuardedPtr<commit_after>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Language:  C++
Date:      $Date$
Version:   $Revision$

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#include "mitkVolumeDataVtkMapper3D.h"
#include "QmitkAbortEventFilter.h"
#include "QmitkRenderWindow.h"
#include "mitkRenderingManager.h"
#include "QmitkRenderingManager.h"

#include "mitkNodePredicateProperty.h"
#include "mitkDataStorage.h"
#include "mitkProperties.h"

#include "QVTKWidget.h"

#include <qapplication.h>
#include <qeventloop.h>
#include <qguardedptr.h>

QmitkAbortEventFilter*
QmitkAbortEventFilter
::GetInstance()
{
  static QmitkAbortEventFilter instance;
  return &instance;
}

QmitkAbortEventFilter
::QmitkAbortEventFilter()
: m_LODRendererAtButtonPress( NULL )
{
}

QmitkAbortEventFilter
::~QmitkAbortEventFilter()
{
}

bool
QmitkAbortEventFilter
::eventFilter( QObject *object, QEvent *event )
{
  typedef QGuardedPtr< QObject > GuardedObject;

  // Extract renderer (if event has been invoked on a RenderWindow)
  bool isLODRenderer = false;
  mitk::BaseRenderer *renderer = NULL;
  QVTKWidget *qVTKWidget = dynamic_cast< QVTKWidget * >( object );
  if (qVTKWidget != NULL )
  {
    renderer = mitk::BaseRenderer::GetInstance( qVTKWidget->GetRenderWindow() );
    if ( renderer && renderer->GetNumberOfVisibleLODEnabledMappers() > 0 )
    {
      isLODRenderer = true;
    }
    else
    {
      // Only LOD enabled renderers are considered
      renderer = NULL;
    }

  }

  if (mitk::RenderingManager::GetInstance()->IsRendering() )
  {
    //m_EventQueue.push( ObjectEventPair(GuardedObject( object ), event) );
    //return true;

    switch ( event->type() )
    {

    case QEvent::MouseButtonPress:
    {
      // Let only the first (RenderWindow specific) click event affect
      // the LOD process (Qt issues multiple events on mouse click, but the
      // RenderWindow specific one is issued first)
      if ( !m_ButtonPressed )
      {
        m_ButtonPressed = true;

        mitk::RenderingManager::GetInstance()->AbortRendering();

        // For non-LOD RenderWindows, renderer is set to NULL and consequently,
        // the LOD counters for ALL RenderWindows are reset to 0.
        mitk::RenderingManager::GetInstance()->SetNextLOD( 0, renderer );
        mitk::RenderingManager::GetInstance()->LODIncreaseBlockedOn();

        // Store renderer (if LOD-enabled), otherwise renderer will be NULL
        m_LODRendererAtButtonPress = renderer;
      }

      // Store renderer if it is LOD enabled for mouse release
      if ( isLODRenderer )
      {
        m_LODRendererAtButtonPress = renderer;
      }

      QMouseEvent* me = ( QMouseEvent* )( event );
      QMouseEvent* newEvent = new QMouseEvent(
        me->type(), me->pos(), me->globalPos(), me->button(), me->state()
      );
      m_EventQueue.push( ObjectEventPair(GuardedObject( object ), newEvent) );
      return true;
    }

    case QEvent::MouseButtonDblClick:
    {
      mitk::RenderingManager::GetInstance()->AbortRendering();
      QMouseEvent* me = ( QMouseEvent* )( event );

      QMouseEvent* newEvent = new QMouseEvent(
        me->type(), me->pos(), me->globalPos(), me->button(), me->state()
      );
      m_EventQueue.push( ObjectEventPair(GuardedObject( object ), newEvent) );
      return true;
    }

    case QEvent::MouseMove:
    {
      if ( m_ButtonPressed )
      {
        if ( isLODRenderer && mitk::RenderingManager::GetInstance()->GetNextLOD( m_LODRendererAtButtonPress ) != 0 )
        {
          mitk::RenderingManager::GetInstance()->SetNextLOD( 0, m_LODRendererAtButtonPress );
          mitk::RenderingManager::GetInstance()->AbortRendering();
        }
      }
      return true;
    }

    case QEvent::MouseButtonRelease:
    {
      if ( m_ButtonPressed )
      {
        m_ButtonPressed = false;

        mitk::RenderingManager::GetInstance()->LODIncreaseBlockedOff();
      }

      QMouseEvent* me = ( QMouseEvent* )( event );
      QMouseEvent* newEvent = new QMouseEvent(
        me->type(), me->pos(), me->globalPos(), me->button(), me->state()
      );
      m_EventQueue.push( ObjectEventPair(GuardedObject( object ), newEvent) );
      return true;
    }

    case QEvent::Wheel:
    {
      mitk::RenderingManager::GetInstance()->SetNextLOD( 0, renderer );
      mitk::RenderingManager::GetInstance()->AbortRendering();

      QWheelEvent* we = ( QWheelEvent* )( event );
      QWheelEvent* newEvent = new QWheelEvent(
        we->pos(), we->globalPos(), we->delta(), we->state(), we->orientation()
      );
      m_EventQueue.push( ObjectEventPair(GuardedObject( object ), newEvent) );
      return true;
    }

    case QEvent::Paint:
    {
      QPaintEvent* pe = ( QPaintEvent* )( event );
      QPaintEvent* newEvent = new QPaintEvent( pe->region() );
      m_EventQueue.push( ObjectEventPair(GuardedObject( object ), newEvent) );
      return true;
    }

    case QEvent::KeyPress:
    {
      mitk::RenderingManager::GetInstance()->AbortRendering();
      QKeyEvent* ke = ( QKeyEvent* )( event );
      QKeyEvent* newEvent = new QKeyEvent(
        ke->type(), ke->key(), ke->ascii(), ke->state(), ke->text(), false, ke->count()
      );
      m_EventQueue.push( ObjectEventPair(GuardedObject( object ), newEvent) );
      return true;
    }

    case QmitkRenderingRequestEvent::RenderingRequest:
    {
      //QmitkRenderingRequestEvent *newEvent = new QmitkRenderingRequestEvent();
      //m_EventQueue.push( ObjectEventPair(GuardedObject( object ), newEvent) );
      return true;
    }

    case QEvent::ChildInserted: //change Layout (Big3D, 2D images up, etc.)
    {
      mitk::RenderingManager::GetInstance()->SetNextLOD( 0 );
      mitk::RenderingManager::GetInstance()->AbortRendering();

      QChildEvent* ce = ( QChildEvent* )( event );
      QChildEvent* newEvent = new QChildEvent(
        QEvent::ChildInserted, ce->child() );
      m_EventQueue.push( ObjectEventPair(GuardedObject( object ), newEvent) );
      return true;
    }

    case QEvent::ChildRemoved: //change Layout (Big3D, 2D images up, etc.)
    {
      mitk::RenderingManager::GetInstance()->SetNextLOD( 0 );
      mitk::RenderingManager::GetInstance()->AbortRendering();

      QChildEvent* ce = ( QChildEvent* )( event );
      QChildEvent* newEvent = new QChildEvent(
        QEvent::ChildRemoved, ce->child() );
      m_EventQueue.push( ObjectEventPair(GuardedObject( object ), newEvent) );
      return true;
    }

    case QEvent::Show:
    {
      mitk::RenderingManager::GetInstance()->SetNextLOD( 0 );
      mitk::RenderingManager::GetInstance()->AbortRendering();

      QShowEvent* newEvent = new QShowEvent();
      m_EventQueue.push( ObjectEventPair(GuardedObject( object ), newEvent) );
      return true;
    }

    case QEvent::Hide:
    {
      mitk::RenderingManager::GetInstance()->SetNextLOD( 0 );
      mitk::RenderingManager::GetInstance()->AbortRendering();

      QHideEvent* newEvent = new QHideEvent();
      m_EventQueue.push( ObjectEventPair(GuardedObject( object ), newEvent) );
      return true;
    }

    case QEvent::Close:
    {
      mitk::RenderingManager::GetInstance()->SetNextLOD( 0 );
      mitk::RenderingManager::GetInstance()->AbortRendering();

      QCloseEvent* newEvent = new QCloseEvent();
      m_EventQueue.push( ObjectEventPair(GuardedObject( object ), newEvent) );
      return true;
    }

    case QEvent::ContextMenu:
    {
      mitk::RenderingManager::GetInstance()->SetNextLOD( 0 );
      mitk::RenderingManager::GetInstance()->AbortRendering();

      QContextMenuEvent *cme = ( QContextMenuEvent * )( event );
      QContextMenuEvent *newEvent = new QContextMenuEvent(
        cme->reason(), cme->pos(), cme->globalPos(), cme->state() );
      m_EventQueue.push( ObjectEventPair(GuardedObject( object ), newEvent) );
      return true;
    }

    case QEvent::Timer:
    {
      QTimerEvent* te = ( QTimerEvent* )( event );
      QTimerEvent* newEvent = new QTimerEvent(te->timerId());
      m_EventQueue.push( ObjectEventPair(GuardedObject( object ), newEvent) );
      return true;
    }

    default:
    {
      return true;
    }
    }
  }
  else
  {
    switch ( event->type() )
    {
      case QEvent::MouseButtonPress:
      {
        // Let only the first (RenderWindow specific) click event affect
        // the LOD process (Qt issues multiple events on mouse click, but the
        // RenderWindow specific one is issued first)
        if ( !m_ButtonPressed )
        {
          m_ButtonPressed = true;
          //mitk::RenderingManager::GetInstance()->SetNextLOD( 0, renderer );
          mitk::RenderingManager::GetInstance()->LODIncreaseBlockedOn();

          m_LODRendererAtButtonPress = renderer;
        }

        // Store renderer if it is LOD enabled for mouse release
        if ( isLODRenderer )
        {
          m_LODRendererAtButtonPress = renderer;
        }

        return false;
      }

      case QEvent::MouseMove:
      {
        // Nothing to do in this case
        return false;
      }

      case QEvent::Wheel:
      {
        mitk::RenderingManager::GetInstance()->RequestUpdateAll(
          mitk::RenderingManager::REQUEST_UPDATE_3DWINDOWS );
        return false;
      }

      case QEvent::MouseButtonRelease:
      {
        if ( m_ButtonPressed )
        {
          m_ButtonPressed = false;
          mitk::RenderingManager::GetInstance()->LODIncreaseBlockedOff();

          if ( m_LODRendererAtButtonPress != NULL )
          {
            mitk::RenderingManager::GetInstance()->RequestUpdate(
              m_LODRendererAtButtonPress->GetRenderWindow() );
          }
          else
          {
            mitk::RenderingManager::GetInstance()->RequestUpdateAll(
              mitk::RenderingManager::REQUEST_UPDATE_3DWINDOWS );
          }
        }
        return false;
      }

      case QEvent::Resize:
      {
        mitk::RenderingManager::GetInstance()->RequestUpdateAll(
          mitk::RenderingManager::REQUEST_UPDATE_3DWINDOWS );
        return false;
      }

      case QEvent::ChildInserted:
      {
        mitk::RenderingManager::GetInstance()->RequestUpdateAll(
          mitk::RenderingManager::REQUEST_UPDATE_3DWINDOWS );
        return false;
      }

      default:
      {
        return false;
      }
    }
  }
}

void
QmitkAbortEventFilter
::ProcessEvents()
{
  qApp->eventLoop()->processEvents( QEventLoop::AllEvents );
}

void
QmitkAbortEventFilter
::IssueQueuedEvents()
{
  while ( !m_EventQueue.empty() )
  {
    ObjectEventPair eventPair = m_EventQueue.front();
    if ( eventPair.first )
    {
      QApplication::postEvent( eventPair.first, eventPair.second );
    }
    m_EventQueue.pop();
  }
}
<|endoftext|>


<commit_before>#ifndef RBX_VM_OBJECT_UTILS_HPP
#define RBX_VM_OBJECT_UTILS_HPP

#include "builtin/object.hpp"
#include "exception.hpp"

/**
 *  @file   object_utils.hpp
 *
 *  Defines all the most common operations for dealing with
 *  objects, such as type checking and casting.
 */

// A stupid work around for g++ changing it's behavior on 4.3

#if __clang__ || (__GNUC__ >= 4 && __GNUC_MINOR__ >= 3)
  #define SPECIALIZATION_STORAGE
#else
  #define SPECIALIZATION_STORAGE static inline
#endif

namespace rubinius {

  /**
   *  Ruby type system subtype check.
   *
   *  Given builtin-class +T+, return true if +obj+ is of class +T+
   */
  template <class T>
    static inline bool kind_of(const Object* obj) {
      if(obj->reference_p()) {
        return obj->type_id() == T::type;
      }
      return false;
    }

  /**
   * A specialized version for completeness.
   */
  template <>
    SPECIALIZATION_STORAGE bool kind_of<Object>(const Object* obj) {
      return true;
    }

  /**
   *  Ruby type system class check.
   *
   *  Another version of kind_of that shouldn't be specialized for subtype
   *  compatibility. I.e., only whether object's class is this specific
   *  one.
   */
  template <class T>
    static inline bool instance_of(const Object* obj) {
      if(obj->reference_p()) {
        return obj->type_id() == T::type;
      }
      return false;
    }

  /**
   * A specialized version for completeness.
   */
  template <>
    SPECIALIZATION_STORAGE bool instance_of<Object>(const Object* obj) {
      return obj->reference_p() && (obj->type_id() == ObjectType);
    }

  /*
   *  There is NO reason why as() or try_as() should be getting
   *  NULL arguments. That means something has not been properly
   *  initialised (to cNil if nothing else.)
   */

  /**
   *  Cast Object* into builtin T*.
   *
   *  Given builtin class +T+, return +obj+ cast as type +T*+. If
   *  +obj+ is not of type +T+, throw's a TypeError exception.
   *
   *  @see  builtin/object.cpp has specialised versions.
   */
  template <class T>
    static inline T* as(Object* obj) {
      if(!kind_of<T>(obj)) {
        TypeError::raise(T::type, obj);
      }

      return static_cast<T*>(obj);
    }

  /**
   *  Cast const Object* into builtin const T*.
   *
   *  Given builtin class +T+, return +obj+ cast as type +T*+. If
   *  +obj+ is not of type +T+, throw's a TypeError exception.
   *
   *  @see  builtin/object.cpp has specialised versions.
   */
  template <class T>
    static inline const T* as(const Object* obj) {
      if(!kind_of<T>(obj)) {
        TypeError::raise(T::type, obj);
      }

      return static_cast<const T*>(obj);
    }

  /**
   * A specialized version for completeness.
   */
  template <>
    SPECIALIZATION_STORAGE Object* as<Object>(Object* obj) {
      return obj;
    }

  /**
   * A specialized version for completeness.
   */
  template <>
    SPECIALIZATION_STORAGE const Object* as<Object>(const Object* obj) {
      return obj;
    }

  /**
   *  Cast Object* into builtin T*.
   *
   *  Given builtin class +T+, return +obj+ cast as type +T*+. If
   *  +obj+ is not exactly of type +T+, throw's a TypeError exception.
   *
   *  @see  builtin/object.cpp has specialised versions.
   */
  template <class T>
    static inline T* as_instance(Object* obj) {
      if(!instance_of<T>(obj)) {
        TypeError::raise(T::type, obj);
      }

      return static_cast<T*>(obj);
    }

  /**
   *  Cast const Object* into builtin const T*.
   *
   *  Given builtin class +T+, return +obj+ cast as type +T*+. If
   *  +obj+ is not exactly of type +T+, throw's a TypeError exception.
   *
   *  @see  builtin/object.cpp has specialised versions.
   */
  template <class T>
    static inline const T* as_instance(const Object* obj) {
      if(!instance_of<T>(obj)) {
        TypeError::raise(T::type, obj);
      }

      return static_cast<const T*>(obj);
    }

  /**
   *  Non-raising version of as().
   *
   *  Similar to as<>, but returns NULL if the type is invalid. ONLY
   *  use this when doing a conditional cast.
   *
   *  @see  builtin/object.cpp has specialised versions.
   */
  template <class T>
    static inline T* try_as(Object* obj) {
      if(!kind_of<T>(obj)) {
        return NULL;
      }

      return static_cast<T*>(obj);
    }

  /**
   *  Non-raising version of as(), for const objects.
   *
   *  Similar to as<>, but returns NULL if the type is invalid. ONLY
   *  use this when doing a conditional cast.
   *
   *  @see  builtin/object.cpp has specialised versions.
   */
  template <class T>
    static inline const T* try_as(const Object* obj) {
      if(!kind_of<T>(obj)) {
        return NULL;
      }

      return static_cast<const T*>(obj);
    }

  /**
   *  Non-raising version of as_instance().
   *
   *  Similar to as_instance<>, but returns NULL if the type is invalid. ONLY
   *  use this when doing a conditional cast.
   *
   *  @see  builtin/object.cpp has specialised versions.
   */
  template <class T>
    static inline T* try_as_instance(Object* obj) {
      if(!instance_of<T>(obj)) {
        return NULL;
      }

      return static_cast<T*>(obj);
    }

  /**
   *  Non-raising version of as(), for const objects.
   *
   *  Similar to as<>, but returns NULL if the type is invalid. ONLY
   *  use this when doing a conditional cast.
   *
   *  @see  builtin/object.cpp has specialised versions.
   */
  template <class T>
    static inline const T* try_as_instance(const Object* obj) {
      if(!instance_of<T>(obj)) {
        return NULL;
      }

      return static_cast<const T*>(obj);
    }

  /**
   *  Returns cNil cast to another type of rubinius::Object. Useful in
   *  cases where e.g. a String* would be returned but cNil is returned
   *  as an exceptional value.
   *
   */
  template <class T>
    static inline T* nil() { return static_cast<T*>(cNil); }

  /**
   *  Converts one type into another without a type check. This is
   *  like reinterprete_cast<>(), but we use it so we can easily
   *  find where we're doing explicit force casts.
   */
  template <class T>
    static inline T* force_as(ObjectHeader* obj) {
      return reinterpret_cast<T*>(obj);
    }

  template <class T>
    static inline const T* force_as(const ObjectHeader* obj) {
      return reinterpret_cast<const T*>(obj);
    }

  void type_assert(STATE, Object* obj, object_type type, const char* reason);

#include "gen/kind_of.hpp"

}

#endif
<commit_msg>Fix a __GNUC__ check to work with GCC 5<commit_after>#ifndef RBX_VM_OBJECT_UTILS_HPP
#define RBX_VM_OBJECT_UTILS_HPP

#include "builtin/object.hpp"
#include "exception.hpp"

/**
 *  @file   object_utils.hpp
 *
 *  Defines all the most common operations for dealing with
 *  objects, such as type checking and casting.
 */

// A stupid work around for g++ changing it's behavior on 4.3

#if __clang__ || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)
  #define SPECIALIZATION_STORAGE
#else
  #define SPECIALIZATION_STORAGE static inline
#endif

namespace rubinius {

  /**
   *  Ruby type system subtype check.
   *
   *  Given builtin-class +T+, return true if +obj+ is of class +T+
   */
  template <class T>
    static inline bool kind_of(const Object* obj) {
      if(obj->reference_p()) {
        return obj->type_id() == T::type;
      }
      return false;
    }

  /**
   * A specialized version for completeness.
   */
  template <>
    SPECIALIZATION_STORAGE bool kind_of<Object>(const Object* obj) {
      return true;
    }

  /**
   *  Ruby type system class check.
   *
   *  Another version of kind_of that shouldn't be specialized for subtype
   *  compatibility. I.e., only whether object's class is this specific
   *  one.
   */
  template <class T>
    static inline bool instance_of(const Object* obj) {
      if(obj->reference_p()) {
        return obj->type_id() == T::type;
      }
      return false;
    }

  /**
   * A specialized version for completeness.
   */
  template <>
    SPECIALIZATION_STORAGE bool instance_of<Object>(const Object* obj) {
      return obj->reference_p() && (obj->type_id() == ObjectType);
    }

  /*
   *  There is NO reason why as() or try_as() should be getting
   *  NULL arguments. That means something has not been properly
   *  initialised (to cNil if nothing else.)
   */

  /**
   *  Cast Object* into builtin T*.
   *
   *  Given builtin class +T+, return +obj+ cast as type +T*+. If
   *  +obj+ is not of type +T+, throw's a TypeError exception.
   *
   *  @see  builtin/object.cpp has specialised versions.
   */
  template <class T>
    static inline T* as(Object* obj) {
      if(!kind_of<T>(obj)) {
        TypeError::raise(T::type, obj);
      }

      return static_cast<T*>(obj);
    }

  /**
   *  Cast const Object* into builtin const T*.
   *
   *  Given builtin class +T+, return +obj+ cast as type +T*+. If
   *  +obj+ is not of type +T+, throw's a TypeError exception.
   *
   *  @see  builtin/object.cpp has specialised versions.
   */
  template <class T>
    static inline const T* as(const Object* obj) {
      if(!kind_of<T>(obj)) {
        TypeError::raise(T::type, obj);
      }

      return static_cast<const T*>(obj);
    }

  /**
   * A specialized version for completeness.
   */
  template <>
    SPECIALIZATION_STORAGE Object* as<Object>(Object* obj) {
      return obj;
    }

  /**
   * A specialized version for completeness.
   */
  template <>
    SPECIALIZATION_STORAGE const Object* as<Object>(const Object* obj) {
      return obj;
    }

  /**
   *  Cast Object* into builtin T*.
   *
   *  Given builtin class +T+, return +obj+ cast as type +T*+. If
   *  +obj+ is not exactly of type +T+, throw's a TypeError exception.
   *
   *  @see  builtin/object.cpp has specialised versions.
   */
  template <class T>
    static inline T* as_instance(Object* obj) {
      if(!instance_of<T>(obj)) {
        TypeError::raise(T::type, obj);
      }

      return static_cast<T*>(obj);
    }

  /**
   *  Cast const Object* into builtin const T*.
   *
   *  Given builtin class +T+, return +obj+ cast as type +T*+. If
   *  +obj+ is not exactly of type +T+, throw's a TypeError exception.
   *
   *  @see  builtin/object.cpp has specialised versions.
   */
  template <class T>
    static inline const T* as_instance(const Object* obj) {
      if(!instance_of<T>(obj)) {
        TypeError::raise(T::type, obj);
      }

      return static_cast<const T*>(obj);
    }

  /**
   *  Non-raising version of as().
   *
   *  Similar to as<>, but returns NULL if the type is invalid. ONLY
   *  use this when doing a conditional cast.
   *
   *  @see  builtin/object.cpp has specialised versions.
   */
  template <class T>
    static inline T* try_as(Object* obj) {
      if(!kind_of<T>(obj)) {
        return NULL;
      }

      return static_cast<T*>(obj);
    }

  /**
   *  Non-raising version of as(), for const objects.
   *
   *  Similar to as<>, but returns NULL if the type is invalid. ONLY
   *  use this when doing a conditional cast.
   *
   *  @see  builtin/object.cpp has specialised versions.
   */
  template <class T>
    static inline const T* try_as(const Object* obj) {
      if(!kind_of<T>(obj)) {
        return NULL;
      }

      return static_cast<const T*>(obj);
    }

  /**
   *  Non-raising version of as_instance().
   *
   *  Similar to as_instance<>, but returns NULL if the type is invalid. ONLY
   *  use this when doing a conditional cast.
   *
   *  @see  builtin/object.cpp has specialised versions.
   */
  template <class T>
    static inline T* try_as_instance(Object* obj) {
      if(!instance_of<T>(obj)) {
        return NULL;
      }

      return static_cast<T*>(obj);
    }

  /**
   *  Non-raising version of as(), for const objects.
   *
   *  Similar to as<>, but returns NULL if the type is invalid. ONLY
   *  use this when doing a conditional cast.
   *
   *  @see  builtin/object.cpp has specialised versions.
   */
  template <class T>
    static inline const T* try_as_instance(const Object* obj) {
      if(!instance_of<T>(obj)) {
        return NULL;
      }

      return static_cast<const T*>(obj);
    }

  /**
   *  Returns cNil cast to another type of rubinius::Object. Useful in
   *  cases where e.g. a String* would be returned but cNil is returned
   *  as an exceptional value.
   *
   */
  template <class T>
    static inline T* nil() { return static_cast<T*>(cNil); }

  /**
   *  Converts one type into another without a type check. This is
   *  like reinterprete_cast<>(), but we use it so we can easily
   *  find where we're doing explicit force casts.
   */
  template <class T>
    static inline T* force_as(ObjectHeader* obj) {
      return reinterpret_cast<T*>(obj);
    }

  template <class T>
    static inline const T* force_as(const ObjectHeader* obj) {
      return reinterpret_cast<const T*>(obj);
    }

  void type_assert(STATE, Object* obj, object_type type, const char* reason);

#include "gen/kind_of.hpp"

}

#endif
<|endoftext|>