<commit_before>/*
 * Copyright 2014 The Imaging Source Europe GmbH
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "v4l2_utils.h"

#include "v4l2_property_mapping.h"
#include "utils.h"
#include "logging.h"

#if HAVE_UDEV
#include <libudev.h>
#endif

#include <glob.h>

#include <vector>
#include <algorithm>

using namespace tcam;

uint32_t tcam::convert_v4l2_flags (uint32_t v4l2_flags)
{
    uint32_t internal_flags = 0;

    if (is_bit_set(v4l2_flags, V4L2_CTRL_FLAG_DISABLED))
    {
        internal_flags = set_bit(internal_flags, TCAM_PROPERTY_FLAG_DISABLED);
    }
    if (is_bit_set(v4l2_flags, V4L2_CTRL_FLAG_GRABBED))
    {
        internal_flags = set_bit(internal_flags, TCAM_PROPERTY_FLAG_GRABBED);
    }
    if (is_bit_set(v4l2_flags, V4L2_CTRL_FLAG_READ_ONLY))
    {
        internal_flags = set_bit(internal_flags, TCAM_PROPERTY_FLAG_READ_ONLY);
    }
    if (is_bit_set(v4l2_flags, V4L2_CTRL_FLAG_UPDATE))
    {}
    if (is_bit_set(v4l2_flags, V4L2_CTRL_FLAG_INACTIVE))
    {
        internal_flags = set_bit(internal_flags, TCAM_PROPERTY_FLAG_INACTIVE);
    }
    if (is_bit_set(v4l2_flags, V4L2_CTRL_FLAG_SLIDER))
    {}
    if (is_bit_set(v4l2_flags, V4L2_CTRL_FLAG_WRITE_ONLY))
    {
        internal_flags = set_bit(internal_flags, TCAM_PROPERTY_FLAG_WRITE_ONLY);
    }
    if (is_bit_set(v4l2_flags, V4L2_CTRL_FLAG_VOLATILE))
    {}
    // if (is_bit_set(v4l2_flags, V4L2_CTRL_FLAG_HAS_PAYLOAD))
    // {}

    return internal_flags;
}

static TCAM_PROPERTY_ID find_mapping (int v4l2_id)
{
    auto f = [v4l2_id] (int p)
        {
            if (v4l2_id == p)
                return true;
            return false;
        };

    for (const auto& m : v4l2_mappings)
    {
        auto match = std::find_if(m.v4l2_id.begin(), m.v4l2_id.end(), f);

        if (match != m.v4l2_id.end())
            return m.id;
    }
    return TCAM_PROPERTY_INVALID;
}

std::shared_ptr<Property> tcam::create_property (int fd,
                                                 struct v4l2_queryctrl* queryctrl,
                                                 struct v4l2_ext_control* ctrl,
                                                 std::shared_ptr<PropertyImpl> impl)
{

    // assure we have the typ
    Property::VALUE_TYPE type;

    switch (queryctrl->type)
    {
        case V4L2_CTRL_TYPE_BOOLEAN:
        {
            type = Property::BOOLEAN;
            break;
        }
        case V4L2_CTRL_TYPE_INTEGER:
        {
            type = Property::INTEGER;
            break;
        }
        case V4L2_CTRL_TYPE_STRING:
        {
            type = Property::STRING;
            break;
        }
        case V4L2_CTRL_TYPE_INTEGER_MENU:
        {
            type = Property::ENUM;
            break;
        }
        case V4L2_CTRL_TYPE_BUTTON:
        {
            type = Property::BUTTON;
            break;
        }
        default:
        {
            type = Property::UNDEFINED;
            break;
        }
    }

    auto prop_id = find_mapping (ctrl->id);

    auto ctrl_m = get_control_reference(prop_id);

    TCAM_PROPERTY_TYPE type_to_use;
    tcam_device_property cp = {};

    if (ctrl_m.id == TCAM_PROPERTY_INVALID)
    {
        tcam_log(TCAM_LOG_WARNING, "Unable to find std property. Passing raw property identifier through. '%s'(%x)", (char*)queryctrl->name, queryctrl->id);
        // pass through and do not associate with anything existing
        type_to_use = value_type_to_ctrl_type(type);
        memcpy(cp.name, (char*)queryctrl->name, sizeof(cp.name));
        cp.type = value_type_to_ctrl_type(type);
        // generate id so that identfication of passed through properties is guaranteed
        cp.id = generate_unique_property_id();
    }
    else
    {
        type_to_use = ctrl_m.type_to_use;
        cp = create_empty_property(ctrl_m.id);
    }

    uint32_t flags = convert_v4l2_flags(queryctrl->flags);

    switch (type_to_use)
    {
        case TCAM_PROPERTY_TYPE_BOOLEAN:
        {
            if (queryctrl->default_value == 0)
            {
                cp.value.b.default_value = false;
            }
            else if (queryctrl->default_value > 0)
            {
                cp.value.b.default_value = true;
            }
            else
            {
                tcam_log(TCAM_LOG_ERROR,
                        "Boolean '%s' has impossible default value: %d Setting to false",
                        cp.name,
                        queryctrl->default_value);
                cp.value.b.default_value = false;
            }

            if (ctrl->value == 0)
            {
                cp.value.b.value = false;
            }
            else if (ctrl->value > 0)
            {
                cp.value.b.value = true;
            }
            else
            {
                tcam_log(TCAM_LOG_ERROR,
                        "Boolean '%s' has impossible value: %d Setting to false",
                        cp.name,
                        ctrl->value);
                cp.value.b.value = false;
            }
            cp.flags = flags;

            return std::make_shared<Property>(PropertyBoolean(impl, cp, type));
        }
        case TCAM_PROPERTY_TYPE_INTEGER:
        {
            cp.value.i.min = queryctrl->minimum;
            cp.value.i.max = queryctrl->maximum;
            cp.value.i.step = queryctrl->step;

            if (cp.value.i.min > cp.value.i.max)
            {
                tcam_log(TCAM_LOG_ERROR,
                         "Range boundaries for property '%s' are faulty. Ignoring property as a precaution.",
                         cp.name);
                return nullptr;
            }

            if (cp.value.i.step == 0)
            {
                tcam_log(TCAM_LOG_WARNING,
                         "Detected stepsize 0 for property %s. Setting to 1.",
                         cp.name);

                cp.value.i.step = 1;
            }

            cp.value.i.default_value = queryctrl->default_value;
            cp.value.i.value = ctrl->value;
            cp.flags = flags;

            return std::make_shared<Property>(PropertyInteger(impl, cp, type));
        }
        // case TCAM_CTRL_TYPE_DOUBLE:
        // {
        // Does not exist in v4l2
        // }
        case TCAM_PROPERTY_TYPE_STRING:
        {
            memcpy(cp.value.s.value,(char*)queryctrl->name, sizeof(cp.value.s.value));
            memcpy(cp.value.s.default_value, (char*)queryctrl->name, sizeof(cp.value.s.default_value));
            cp.flags = flags;

            return std::make_shared<Property>(PropertyString(impl, cp, type));
        }
        case TCAM_PROPERTY_TYPE_ENUMERATION:
        {
            cp.value.i.min = queryctrl->minimum;
            cp.value.i.max = queryctrl->maximum;
            cp.value.i.step = 0;
            cp.value.i.default_value = queryctrl->default_value;
            cp.value.i.value = ctrl->value;
            cp.flags = flags;

            struct v4l2_querymenu qmenu = {};

            qmenu.id = queryctrl->id;

            std::map<std::string, int> m;

            for (int i = 0; i <= queryctrl->maximum; i++)
            {
                qmenu.index = i;
                if (tcam_xioctl(fd, VIDIOC_QUERYMENU, &qmenu))
                    continue;

                std::string map_string((char*) qmenu.name);
                m.emplace(map_string, i);
            }

            return std::make_shared<Property>(PropertyEnumeration(impl, cp, m, type));
        }
        case TCAM_PROPERTY_TYPE_BUTTON:
        {
            cp.flags = flags;

            return std::make_shared<Property>(PropertyButton(impl, cp, type));
        }
        default:
        {
            std::string s = "Unknown V4L2 Control type: ";
            s.append((char*)queryctrl->name);
            tcam_log(TCAM_LOG_ERROR, s.c_str());
            break;
        }
    }
    return nullptr;
}

std::vector<DeviceInfo> tcam::get_v4l2_device_list ()
{
    std::vector<DeviceInfo> device_list;

    struct udev* udev = udev_new();
    if (!udev)
    {
        return device_list;
    }

    /* Create a list of the devices in the 'video4linux' subsystem. */
    struct udev_enumerate* enumerate = udev_enumerate_new(udev);
    udev_enumerate_add_match_subsystem(enumerate, "video4linux");
    udev_enumerate_scan_devices(enumerate);
    struct udev_list_entry* devices = udev_enumerate_get_list_entry(enumerate);
    struct udev_list_entry* dev_list_entry;

    udev_list_entry_foreach(dev_list_entry, devices)
    {
        const char* path;
        char needed_path[100];

        /* Get the filename of the /sys entry for the device
           and create a udev_device object (dev) representing it */
        path = udev_list_entry_get_name(dev_list_entry);
        struct udev_device* dev = udev_device_new_from_syspath(udev, path);

        /* The device pointed to by dev contains information about
           the hidraw device. In order to get information about the
           USB device, get the parent device with the
           subsystem/devtype pair of "usb"/"usb_device". This will
           be several levels up the tree, but the function will find
           it.*/

        /* we need to copy the devnode (/dev/videoX) before the path
           is changed to the path of the usb device behind it (/sys/class/....) */
        strcpy(needed_path, udev_device_get_devnode(dev));

        struct udev_device* parent_device = udev_device_get_parent_with_subsystem_devtype(dev, "usb", "usb_device");

        /* skip this device if we can't get the usb parent */
        if (!parent_device)
        {
            continue;
        }

        /* From here, we can call get_sysattr_value() for each file
           in the device's /sys entry. The strings passed into these
           functions (idProduct, idVendor, serial, etc.) correspond
           directly to the files in the directory which represents
           the USB device. Note that USB strings are Unicode, UCS2
           encoded, but the strings returned from
           udev_device_get_sysattr_value() are UTF-8 encoded. */

        static const char* TCAM_VENDOR_ID_STRING = "199e";

        if (strcmp(udev_device_get_sysattr_value(parent_device, "idVendor"), TCAM_VENDOR_ID_STRING) == 0)
        {
            tcam_device_info info = {};
            info.type = TCAM_DEVICE_TYPE_V4L2;
            strncpy(info.identifier, needed_path, sizeof(info.identifier));

            if (udev_device_get_sysattr_value(parent_device, "idProduct") != NULL)
            {
                strncpy(info.additional_identifier, udev_device_get_sysattr_value(parent_device, "idProduct"), sizeof(info.additional_identifier));
            }

            if (udev_device_get_sysattr_value(parent_device, "product") != NULL)
                strncpy(info.name, udev_device_get_sysattr_value(parent_device, "product"), sizeof(info.name));
            else
                memcpy(info.name, "\0", sizeof(info.name));

            if (udev_device_get_sysattr_value(parent_device, "serial") != NULL)
            {
                std::string tmp = udev_device_get_sysattr_value(parent_device, "serial");
                tmp.erase(remove_if(tmp.begin(), tmp.end(), isspace), tmp.end());
                strncpy(info.serial_number, tmp.c_str(), sizeof(info.serial_number));
            }
            else
            {
                memcpy(info.serial_number, "\0", sizeof(info.serial_number));
            }
            device_list.push_back(DeviceInfo(info));
        }

        udev_device_unref(dev);
    }

    /* Free the enumerator object */
    udev_enumerate_unref(enumerate);

    udev_unref(udev);

    return device_list;
}
<commit_msg>Add missing switch case<commit_after>/*
 * Copyright 2014 The Imaging Source Europe GmbH
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "v4l2_utils.h"

#include "v4l2_property_mapping.h"
#include "utils.h"
#include "logging.h"

#if HAVE_UDEV
#include <libudev.h>
#endif

#include <glob.h>

#include <vector>
#include <algorithm>

using namespace tcam;

uint32_t tcam::convert_v4l2_flags (uint32_t v4l2_flags)
{
    uint32_t internal_flags = 0;

    if (is_bit_set(v4l2_flags, V4L2_CTRL_FLAG_DISABLED))
    {
        internal_flags = set_bit(internal_flags, TCAM_PROPERTY_FLAG_DISABLED);
    }
    if (is_bit_set(v4l2_flags, V4L2_CTRL_FLAG_GRABBED))
    {
        internal_flags = set_bit(internal_flags, TCAM_PROPERTY_FLAG_GRABBED);
    }
    if (is_bit_set(v4l2_flags, V4L2_CTRL_FLAG_READ_ONLY))
    {
        internal_flags = set_bit(internal_flags, TCAM_PROPERTY_FLAG_READ_ONLY);
    }
    if (is_bit_set(v4l2_flags, V4L2_CTRL_FLAG_UPDATE))
    {}
    if (is_bit_set(v4l2_flags, V4L2_CTRL_FLAG_INACTIVE))
    {
        internal_flags = set_bit(internal_flags, TCAM_PROPERTY_FLAG_INACTIVE);
    }
    if (is_bit_set(v4l2_flags, V4L2_CTRL_FLAG_SLIDER))
    {}
    if (is_bit_set(v4l2_flags, V4L2_CTRL_FLAG_WRITE_ONLY))
    {
        internal_flags = set_bit(internal_flags, TCAM_PROPERTY_FLAG_WRITE_ONLY);
    }
    if (is_bit_set(v4l2_flags, V4L2_CTRL_FLAG_VOLATILE))
    {}
    // if (is_bit_set(v4l2_flags, V4L2_CTRL_FLAG_HAS_PAYLOAD))
    // {}

    return internal_flags;
}

static TCAM_PROPERTY_ID find_mapping (int v4l2_id)
{
    auto f = [v4l2_id] (int p)
        {
            if (v4l2_id == p)
                return true;
            return false;
        };

    for (const auto& m : v4l2_mappings)
    {
        auto match = std::find_if(m.v4l2_id.begin(), m.v4l2_id.end(), f);

        if (match != m.v4l2_id.end())
            return m.id;
    }
    return TCAM_PROPERTY_INVALID;
}

std::shared_ptr<Property> tcam::create_property (int fd,
                                                 struct v4l2_queryctrl* queryctrl,
                                                 struct v4l2_ext_control* ctrl,
                                                 std::shared_ptr<PropertyImpl> impl)
{

    // assure we have the typ
    Property::VALUE_TYPE type;

    switch (queryctrl->type)
    {
        case V4L2_CTRL_TYPE_BOOLEAN:
        {
            type = Property::BOOLEAN;
            break;
        }
        case V4L2_CTRL_TYPE_INTEGER:
        {
            type = Property::INTEGER;
            break;
        }
        case V4L2_CTRL_TYPE_STRING:
        {
            type = Property::STRING;
            break;
        }
        case V4L2_CTRL_TYPE_INTEGER_MENU:
        case V4L2_CTRL_TYPE_MENU:
        {
            type = Property::ENUM;
            break;
        }
        case V4L2_CTRL_TYPE_BUTTON:
        {
            type = Property::BUTTON;
            break;
        }
        default:
        {
            type = Property::UNDEFINED;
            break;
        }
    }

    auto prop_id = find_mapping (ctrl->id);

    auto ctrl_m = get_control_reference(prop_id);

    TCAM_PROPERTY_TYPE type_to_use;
    tcam_device_property cp = {};

    if (ctrl_m.id == TCAM_PROPERTY_INVALID)
    {
        tcam_log(TCAM_LOG_WARNING, "Unable to find std property. Passing raw property identifier through. '%s'(%x)", (char*)queryctrl->name, queryctrl->id);
        // pass through and do not associate with anything existing
        type_to_use = value_type_to_ctrl_type(type);
        memcpy(cp.name, (char*)queryctrl->name, sizeof(cp.name));
        cp.type = value_type_to_ctrl_type(type);
        // generate id so that identfication of passed through properties is guaranteed
        cp.id = generate_unique_property_id();
    }
    else
    {
        type_to_use = ctrl_m.type_to_use;
        cp = create_empty_property(ctrl_m.id);
    }

    uint32_t flags = convert_v4l2_flags(queryctrl->flags);

    switch (type_to_use)
    {
        case TCAM_PROPERTY_TYPE_BOOLEAN:
        {
            if (queryctrl->default_value == 0)
            {
                cp.value.b.default_value = false;
            }
            else if (queryctrl->default_value > 0)
            {
                cp.value.b.default_value = true;
            }
            else
            {
                tcam_log(TCAM_LOG_ERROR,
                        "Boolean '%s' has impossible default value: %d Setting to false",
                        cp.name,
                        queryctrl->default_value);
                cp.value.b.default_value = false;
            }

            if (ctrl->value == 0)
            {
                cp.value.b.value = false;
            }
            else if (ctrl->value > 0)
            {
                cp.value.b.value = true;
            }
            else
            {
                tcam_log(TCAM_LOG_ERROR,
                        "Boolean '%s' has impossible value: %d Setting to false",
                        cp.name,
                        ctrl->value);
                cp.value.b.value = false;
            }
            cp.flags = flags;

            return std::make_shared<Property>(PropertyBoolean(impl, cp, type));
        }
        case TCAM_PROPERTY_TYPE_INTEGER:
        {
            cp.value.i.min = queryctrl->minimum;
            cp.value.i.max = queryctrl->maximum;
            cp.value.i.step = queryctrl->step;

            if (cp.value.i.min > cp.value.i.max)
            {
                tcam_log(TCAM_LOG_ERROR,
                         "Range boundaries for property '%s' are faulty. Ignoring property as a precaution.",
                         cp.name);
                return nullptr;
            }

            if (cp.value.i.step == 0)
            {
                tcam_log(TCAM_LOG_WARNING,
                         "Detected stepsize 0 for property %s. Setting to 1.",
                         cp.name);

                cp.value.i.step = 1;
            }

            cp.value.i.default_value = queryctrl->default_value;
            cp.value.i.value = ctrl->value;
            cp.flags = flags;

            return std::make_shared<Property>(PropertyInteger(impl, cp, type));
        }
        // case TCAM_CTRL_TYPE_DOUBLE:
        // {
        // Does not exist in v4l2
        // }
        case TCAM_PROPERTY_TYPE_STRING:
        {
            memcpy(cp.value.s.value,(char*)queryctrl->name, sizeof(cp.value.s.value));
            memcpy(cp.value.s.default_value, (char*)queryctrl->name, sizeof(cp.value.s.default_value));
            cp.flags = flags;

            return std::make_shared<Property>(PropertyString(impl, cp, type));
        }
        case TCAM_PROPERTY_TYPE_ENUMERATION:
        {
            cp.value.i.min = queryctrl->minimum;
            cp.value.i.max = queryctrl->maximum;
            cp.value.i.step = 0;
            cp.value.i.default_value = queryctrl->default_value;
            cp.value.i.value = ctrl->value;
            cp.flags = flags;

            struct v4l2_querymenu qmenu = {};

            qmenu.id = queryctrl->id;

            std::map<std::string, int> m;

            for (int i = 0; i <= queryctrl->maximum; i++)
            {
                qmenu.index = i;
                if (tcam_xioctl(fd, VIDIOC_QUERYMENU, &qmenu))
                    continue;

                std::string map_string((char*) qmenu.name);
                m.emplace(map_string, i);
            }

            return std::make_shared<Property>(PropertyEnumeration(impl, cp, m, type));
        }
        case TCAM_PROPERTY_TYPE_BUTTON:
        {
            cp.flags = flags;

            return std::make_shared<Property>(PropertyButton(impl, cp, type));
        }
        default:
        {
            std::string s = "Unknown V4L2 Control type: ";
            s.append((char*)queryctrl->name);
            tcam_log(TCAM_LOG_ERROR, s.c_str());
            break;
        }
    }
    return nullptr;
}

std::vector<DeviceInfo> tcam::get_v4l2_device_list ()
{
    std::vector<DeviceInfo> device_list;

    struct udev* udev = udev_new();
    if (!udev)
    {
        return device_list;
    }

    /* Create a list of the devices in the 'video4linux' subsystem. */
    struct udev_enumerate* enumerate = udev_enumerate_new(udev);
    udev_enumerate_add_match_subsystem(enumerate, "video4linux");
    udev_enumerate_scan_devices(enumerate);
    struct udev_list_entry* devices = udev_enumerate_get_list_entry(enumerate);
    struct udev_list_entry* dev_list_entry;

    udev_list_entry_foreach(dev_list_entry, devices)
    {
        const char* path;
        char needed_path[100];

        /* Get the filename of the /sys entry for the device
           and create a udev_device object (dev) representing it */
        path = udev_list_entry_get_name(dev_list_entry);
        struct udev_device* dev = udev_device_new_from_syspath(udev, path);

        /* The device pointed to by dev contains information about
           the hidraw device. In order to get information about the
           USB device, get the parent device with the
           subsystem/devtype pair of "usb"/"usb_device". This will
           be several levels up the tree, but the function will find
           it.*/

        /* we need to copy the devnode (/dev/videoX) before the path
           is changed to the path of the usb device behind it (/sys/class/....) */
        strcpy(needed_path, udev_device_get_devnode(dev));

        struct udev_device* parent_device = udev_device_get_parent_with_subsystem_devtype(dev, "usb", "usb_device");

        /* skip this device if we can't get the usb parent */
        if (!parent_device)
        {
            continue;
        }

        /* From here, we can call get_sysattr_value() for each file
           in the device's /sys entry. The strings passed into these
           functions (idProduct, idVendor, serial, etc.) correspond
           directly to the files in the directory which represents
           the USB device. Note that USB strings are Unicode, UCS2
           encoded, but the strings returned from
           udev_device_get_sysattr_value() are UTF-8 encoded. */

        static const char* TCAM_VENDOR_ID_STRING = "199e";

        if (strcmp(udev_device_get_sysattr_value(parent_device, "idVendor"), TCAM_VENDOR_ID_STRING) == 0)
        {
            tcam_device_info info = {};
            info.type = TCAM_DEVICE_TYPE_V4L2;
            strncpy(info.identifier, needed_path, sizeof(info.identifier));

            if (udev_device_get_sysattr_value(parent_device, "idProduct") != NULL)
            {
                strncpy(info.additional_identifier, udev_device_get_sysattr_value(parent_device, "idProduct"), sizeof(info.additional_identifier));
            }

            if (udev_device_get_sysattr_value(parent_device, "product") != NULL)
                strncpy(info.name, udev_device_get_sysattr_value(parent_device, "product"), sizeof(info.name));
            else
                memcpy(info.name, "\0", sizeof(info.name));

            if (udev_device_get_sysattr_value(parent_device, "serial") != NULL)
            {
                std::string tmp = udev_device_get_sysattr_value(parent_device, "serial");
                tmp.erase(remove_if(tmp.begin(), tmp.end(), isspace), tmp.end());
                strncpy(info.serial_number, tmp.c_str(), sizeof(info.serial_number));
            }
            else
            {
                memcpy(info.serial_number, "\0", sizeof(info.serial_number));
            }
            device_list.push_back(DeviceInfo(info));
        }

        udev_device_unref(dev);
    }

    /* Free the enumerator object */
    udev_enumerate_unref(enumerate);

    udev_unref(udev);

    return device_list;
}
<|endoftext|>


<commit_before>/*
 * Copyright 2015 Milian Wolff <mail@milianw.de>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Library General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#include "model.h"

#include <QDebug>

#include <sstream>

using namespace std;

namespace {
QString generateSummary(const AccumulatedTraceData& data)
{
    stringstream stream;
    const double totalTimeS = 0.001 * data.totalTime;
    stream << "<qt>"
           << "total runtime: " << fixed << totalTimeS << "s.
"
           << "bytes allocated in total (ignoring deallocations): " << formatBytes(data.totalAllocated)
             << " (" << formatBytes(data.totalAllocated / totalTimeS) << "/s)
"
           << "calls to allocation functions: " << data.totalAllocations
             << " (" << size_t(data.totalAllocations / totalTimeS) << "/s)
"
           << "peak heap memory consumption: " << formatBytes(data.peak) << "
"
           << "total memory leaked: " << formatBytes(data.leaked) << "
";
    stream << "</qt>";
    return QString::fromStdString(stream.str());
}

int parentRow(const QModelIndex& child)
{
    return child.isValid() ? static_cast<int>(child.internalId()) : -1;
}

}

Model::Model(QObject* parent)
{

}

Model::~Model()
{
}

QVariant Model::headerData(int section, Qt::Orientation orientation, int role) const
{
    if (orientation != Qt::Horizontal || role != Qt::DisplayRole || section < 0 || section >= NUM_COLUMNS) {
        return QVariant();
    }
    switch (static_cast<Columns>(section)) {
        case FileColumn:
            return tr("File");
        case FunctionColumn:
            return tr("Function");
        case ModuleColumn:
            return tr("Module");
        case AllocationsColumn:
            return tr("Allocations");
        case PeakColumn:
            return tr("Peak");
        case LeakedColumn:
            return tr("Leaked");
        case AllocatedColumn:
            return tr("Allocated");
        case NUM_COLUMNS:
            break;
    }
    return QVariant();
}

QVariant Model::data(const QModelIndex& index, int role) const
{
    if (index.row() < 0 || index.row() > m_data.mergedAllocations.size()
        || index.column() < 0 || index.column() > NUM_COLUMNS)
    {
        return QVariant();
    }
    const auto parent = index.parent();
    if (parent.isValid()) {
        // child level
        if (parent.parent().isValid()) {
            return QVariant();
        }
        const auto& allocation = m_data.mergedAllocations[parent.row()];
        const auto& trace = allocation.traces[index.row()];

        if (role == Qt::DisplayRole) {
            return allocationData(trace, m_data.findTrace(trace.traceIndex).ipIndex, static_cast<Columns>(index.column()));
        } else if (role == Qt::ToolTipRole) {
            stringstream stream;
            m_data.printBacktrace(trace.traceIndex, stream);
            return QString::fromStdString(stream.str());
        }
        return QVariant();
    }

    // top-level
    const auto& allocation = m_data.mergedAllocations[index.row()];
    if (role == Qt::DisplayRole) {
        return allocationData(allocation, allocation.ipIndex, static_cast<Columns>(index.column()));
    }
    return QVariant();
}

QModelIndex Model::index(int row, int column, const QModelIndex& parent) const
{
    if (row < 0 || column  < 0 || column >= NUM_COLUMNS || row >= rowCount(parent)) {
        return QModelIndex();
    }
    return createIndex(row, column, static_cast<quintptr>(parent.row()));
}

QModelIndex Model::parent(const QModelIndex& child) const
{
    const auto parent = parentRow(child);
    if (parent == -1) {
        return QModelIndex();
    } else {
        return createIndex(parent, 0, -1);
    }
}

int Model::rowCount(const QModelIndex& parent) const
{
    if (parent.isValid()) {
        if (parent.column() != 0 || parent.row() < 0 || parent.row() >= m_data.mergedAllocations.size()
            || parentRow(parent) != -1)
        {
            return 0;
        } else {
            return m_data.mergedAllocations[parent.row()].traces.size();
        }
    }
    return m_data.mergedAllocations.size();
}

int Model::columnCount(const QModelIndex& /*parent*/) const
{
    return NUM_COLUMNS;
}

void Model::loadFile(const QString& file)
{
    beginResetModel();
    m_data.read(file.toStdString());
    endResetModel();
    emit dataReady(generateSummary(m_data));
}

QVariant Model::allocationData(const AllocationData& allocation, const IpIndex& ipIndex, Columns column) const
{
    switch (column) {
    case AllocationsColumn:
        return static_cast<quint64>(allocation.allocations);
    case PeakColumn:
        return static_cast<quint64>(allocation.peak);
    case LeakedColumn:
        return static_cast<quint64>(allocation.leaked);
    case AllocatedColumn:
        return static_cast<quint64>(allocation.allocated);
    case FileColumn:
    case ModuleColumn:
    case FunctionColumn: {
        const auto& ip = m_data.findIp(ipIndex);
        if (column == FunctionColumn) {
            if (ip.functionIndex) {
                return QString::fromStdString(m_data.prettyFunction(m_data.stringify(ip.functionIndex)));
            } else {
                return QLatin1String("0x") + QString::number(ip.instructionPointer, 16);
            }
        } else if (column == ModuleColumn) {
            return QString::fromStdString(m_data.stringify(ip.moduleIndex));
        } else if (ip.fileIndex) {
            auto file = QString::fromStdString(m_data.stringify(ip.fileIndex));
            return file + QLatin1Char(':') + QString::number(ip.line);
        } else {
            return QString();
        }
        break;
    }
    case NUM_COLUMNS:
        break;
    }
    return QVariant();
}<commit_msg>Deduplicate shown functions by skipping first, merged, level.<commit_after>/*
 * Copyright 2015 Milian Wolff <mail@milianw.de>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Library General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#include "model.h"

#include <QDebug>

#include <sstream>

using namespace std;

namespace {
QString generateSummary(const AccumulatedTraceData& data)
{
    stringstream stream;
    const double totalTimeS = 0.001 * data.totalTime;
    stream << "<qt>"
           << "total runtime: " << fixed << totalTimeS << "s.
"
           << "bytes allocated in total (ignoring deallocations): " << formatBytes(data.totalAllocated)
             << " (" << formatBytes(data.totalAllocated / totalTimeS) << "/s)
"
           << "calls to allocation functions: " << data.totalAllocations
             << " (" << size_t(data.totalAllocations / totalTimeS) << "/s)
"
           << "peak heap memory consumption: " << formatBytes(data.peak) << "
"
           << "total memory leaked: " << formatBytes(data.leaked) << "
";
    stream << "</qt>";
    return QString::fromStdString(stream.str());
}

int parentRow(const QModelIndex& child)
{
    return child.isValid() ? static_cast<int>(child.internalId()) : -1;
}

}

Model::Model(QObject* parent)
{

}

Model::~Model()
{
}

QVariant Model::headerData(int section, Qt::Orientation orientation, int role) const
{
    if (orientation != Qt::Horizontal || role != Qt::DisplayRole || section < 0 || section >= NUM_COLUMNS) {
        return QVariant();
    }
    switch (static_cast<Columns>(section)) {
        case FileColumn:
            return tr("File");
        case FunctionColumn:
            return tr("Function");
        case ModuleColumn:
            return tr("Module");
        case AllocationsColumn:
            return tr("Allocations");
        case PeakColumn:
            return tr("Peak");
        case LeakedColumn:
            return tr("Leaked");
        case AllocatedColumn:
            return tr("Allocated");
        case NUM_COLUMNS:
            break;
    }
    return QVariant();
}

QVariant Model::data(const QModelIndex& index, int role) const
{
    if (index.row() < 0 || index.row() > m_data.mergedAllocations.size()
        || index.column() < 0 || index.column() > NUM_COLUMNS)
    {
        return QVariant();
    }
    const auto parent = index.parent();
    if (parent.isValid()) {
        // child level
        if (parent.parent().isValid()) {
            return QVariant();
        }
        const auto& allocation = m_data.mergedAllocations[parent.row()];
        const auto& trace = allocation.traces[index.row()];

        if (role == Qt::DisplayRole) {
            auto node = m_data.findTrace(trace.traceIndex);
            // skip first level, it is duplicated on the top-level
            node = m_data.findTrace(node.parentIndex);
            return allocationData(trace, node.ipIndex, static_cast<Columns>(index.column()));
        } else if (role == Qt::ToolTipRole) {
            stringstream stream;
            m_data.printBacktrace(trace.traceIndex, stream);
            return QString::fromStdString(stream.str());
        }
        return QVariant();
    }

    // top-level
    const auto& allocation = m_data.mergedAllocations[index.row()];
    if (role == Qt::DisplayRole) {
        return allocationData(allocation, allocation.ipIndex, static_cast<Columns>(index.column()));
    }
    return QVariant();
}

QModelIndex Model::index(int row, int column, const QModelIndex& parent) const
{
    if (row < 0 || column  < 0 || column >= NUM_COLUMNS || row >= rowCount(parent)) {
        return QModelIndex();
    }
    return createIndex(row, column, static_cast<quintptr>(parent.row()));
}

QModelIndex Model::parent(const QModelIndex& child) const
{
    const auto parent = parentRow(child);
    if (parent == -1) {
        return QModelIndex();
    } else {
        return createIndex(parent, 0, -1);
    }
}

int Model::rowCount(const QModelIndex& parent) const
{
    if (parent.isValid()) {
        if (parent.column() != 0 || parent.row() < 0 || parent.row() >= m_data.mergedAllocations.size()
            || parentRow(parent) != -1)
        {
            return 0;
        } else {
            return m_data.mergedAllocations[parent.row()].traces.size();
        }
    }
    return m_data.mergedAllocations.size();
}

int Model::columnCount(const QModelIndex& /*parent*/) const
{
    return NUM_COLUMNS;
}

void Model::loadFile(const QString& file)
{
    beginResetModel();
    m_data.read(file.toStdString());
    endResetModel();
    emit dataReady(generateSummary(m_data));
}

QVariant Model::allocationData(const AllocationData& allocation, const IpIndex& ipIndex, Columns column) const
{
    switch (column) {
    case AllocationsColumn:
        return static_cast<quint64>(allocation.allocations);
    case PeakColumn:
        return static_cast<quint64>(allocation.peak);
    case LeakedColumn:
        return static_cast<quint64>(allocation.leaked);
    case AllocatedColumn:
        return static_cast<quint64>(allocation.allocated);
    case FileColumn:
    case ModuleColumn:
    case FunctionColumn: {
        const auto& ip = m_data.findIp(ipIndex);
        if (column == FunctionColumn) {
            if (ip.functionIndex) {
                return QString::fromStdString(m_data.prettyFunction(m_data.stringify(ip.functionIndex)));
            } else {
                return QLatin1String("0x") + QString::number(ip.instructionPointer, 16);
            }
        } else if (column == ModuleColumn) {
            return QString::fromStdString(m_data.stringify(ip.moduleIndex));
        } else if (ip.fileIndex) {
            auto file = QString::fromStdString(m_data.stringify(ip.fileIndex));
            return file + QLatin1Char(':') + QString::number(ip.line);
        } else {
            return QString();
        }
        break;
    }
    case NUM_COLUMNS:
        break;
    }
    return QVariant();
}<|endoftext|>


<commit_before>#include "stdafx.h"
#include "SmartViewPane.h"
#include "String.h"
#include "SmartView/SmartView.h"

static wstring CLASS = L"SmartViewPane";

SmartViewPane* SmartViewPane::Create(UINT uidLabel)
{
	auto pane = new SmartViewPane();
	if (pane)
	{
		pane->SetLabel(uidLabel, true);
	}

	return pane;
}

SmartViewPane::SmartViewPane()
{
	m_TextPane.m_bMultiline = true;
	m_TextPane.SetLabel(NULL, true);
	m_bHasData = false;
	m_bDoDropDown = true;
	m_bReadOnly = true;
}

bool SmartViewPane::IsType(__ViewTypes vType)
{
	return CTRL_SMARTVIEWPANE == vType || DropDownPane::IsType(vType);
}

ULONG SmartViewPane::GetFlags()
{
	return DropDownPane::GetFlags() | vpCollapsible;
}

void SmartViewPane::Initialize(int iControl, _In_ CWnd* pParent, _In_ HDC hdc)
{
	for (auto smartViewParserType : SmartViewParserTypeArray)
	{
		InsertDropString(smartViewParserType.lpszName, smartViewParserType.ulValue);
	}

	CreateControl(iControl, pParent, hdc);

	DropDownPane::Initialize(0, pParent, hdc);

	// Passing a control # of 1 gives us a built in margin
	m_TextPane.Initialize(1, pParent, hdc);

	m_bInitialized = true;
}

int SmartViewPane::GetFixedHeight()
{
	if (!m_bDoDropDown && !m_bHasData) return 0;

	auto iHeight = 0;

	if (0 != m_iControl) iHeight += m_iSmallHeightMargin; // Top margin

	// Our expand/collapse button
	iHeight += m_iButtonHeight;
	// Control label will be next to this

	if (m_bDoDropDown && !m_bCollapsed)
	{
		iHeight += m_iEditHeight; // Height of the dropdown
		iHeight += m_TextPane.GetFixedHeight();
	}

	return iHeight;
}

int SmartViewPane::GetLines()
{
	auto iStructType = GetDropDownSelectionValue();
	if (!m_bCollapsed && (m_bHasData || iStructType))
	{
		return m_TextPane.GetLines();
	}

	return 0;
}

void SmartViewPane::SetWindowPos(int x, int y, int width, int height)
{
	auto hRes = S_OK;
	if (!m_bDoDropDown && !m_bHasData)
	{
		EC_B(m_CollapseButton.ShowWindow(SW_HIDE));
		EC_B(m_Label.ShowWindow(SW_HIDE));
		EC_B(m_DropDown.ShowWindow(SW_HIDE));
		m_TextPane.ShowWindow(SW_HIDE);
	}
	else
	{
		EC_B(m_CollapseButton.ShowWindow(SW_SHOW));
		EC_B(m_Label.ShowWindow(SW_SHOW));
	}

	if (0 != m_iControl)
	{
		y += m_iSmallHeightMargin;
		height -= m_iSmallHeightMargin;
	}

	ViewPane::SetWindowPos(x, y, width, height);

	y += m_iLabelHeight + m_iSmallHeightMargin;
	height -= m_iButtonHeight + m_iSmallHeightMargin;

	if (m_bCollapsed)
	{
		EC_B(m_DropDown.ShowWindow(SW_HIDE));
		m_TextPane.ShowWindow(SW_HIDE);
	}
	else
	{
		if (m_bDoDropDown)
		{
			EC_B(m_DropDown.ShowWindow(SW_SHOW));
			EC_B(m_DropDown.SetWindowPos(NULL, x, y, width, m_iEditHeight, SWP_NOZORDER));

			y += m_iEditHeight;
			height -= m_iEditHeight;
		}

		m_TextPane.ShowWindow(SW_SHOW);
		m_TextPane.SetWindowPos(x, y, width, height);
	}
}

void SmartViewPane::SetMargins(
	int iMargin,
	int iSideMargin,
	int iLabelHeight, // Height of the label
	int iSmallHeightMargin,
	int iLargeHeightMargin,
	int iButtonHeight, // Height of buttons below the control
	int iEditHeight) // height of an edit control
{
	m_TextPane.SetMargins(iMargin, iSideMargin, iLabelHeight, iSmallHeightMargin, iLargeHeightMargin, iButtonHeight, iEditHeight);
	ViewPane::SetMargins(iMargin, iSideMargin, iLabelHeight, iSmallHeightMargin, iLargeHeightMargin, iButtonHeight, iEditHeight);
}

void SmartViewPane::SetStringW(wstring szMsg)
{
	if (!szMsg.empty())
	{
		m_bHasData = true;
	}
	else
	{
		m_bHasData = false;
	}

	m_TextPane.SetStringW(szMsg);
}

void SmartViewPane::DisableDropDown()
{
	m_bDoDropDown = false;
}

void SmartViewPane::SetParser(__ParsingTypeEnum iParser)
{
	for (size_t iDropNum = 0; iDropNum < SmartViewParserTypeArray.size(); iDropNum++)
	{
		if (iParser == static_cast<__ParsingTypeEnum>(SmartViewParserTypeArray[iDropNum].ulValue))
		{
			SetSelection(iDropNum);
			break;
		}
	}
}

void SmartViewPane::Parse(SBinary myBin)
{
	auto iStructType = static_cast<__ParsingTypeEnum>(GetDropDownSelectionValue());
	auto szSmartView = InterpretBinaryAsString(myBin, iStructType, nullptr);

	m_bHasData = !szSmartView.empty();
	SetStringW(szSmartView);
}
<commit_msg>Error opening SV pane<commit_after>#include "stdafx.h"
#include "SmartViewPane.h"
#include "String.h"
#include "SmartView/SmartView.h"

static wstring CLASS = L"SmartViewPane";

SmartViewPane* SmartViewPane::Create(UINT uidLabel)
{
	auto pane = new SmartViewPane();
	if (pane)
	{
		pane->SetLabel(uidLabel, true);
	}

	return pane;
}

SmartViewPane::SmartViewPane()
{
	m_TextPane.m_bMultiline = true;
	m_TextPane.SetLabel(NULL, true);
	m_bHasData = false;
	m_bDoDropDown = true;
	m_bReadOnly = true;
}

bool SmartViewPane::IsType(__ViewTypes vType)
{
	return CTRL_SMARTVIEWPANE == vType || DropDownPane::IsType(vType);
}

ULONG SmartViewPane::GetFlags()
{
	return DropDownPane::GetFlags() | vpCollapsible;
}

void SmartViewPane::Initialize(int /*iControl*/, _In_ CWnd* pParent, _In_ HDC hdc)
{
	for (auto smartViewParserType : SmartViewParserTypeArray)
	{
		InsertDropString(smartViewParserType.lpszName, smartViewParserType.ulValue);
	}

	DropDownPane::Initialize(0, pParent, hdc);
	m_TextPane.Initialize(1, pParent, hdc);

	m_bInitialized = true;
}

int SmartViewPane::GetFixedHeight()
{
	if (!m_bDoDropDown && !m_bHasData) return 0;

	auto iHeight = 0;

	if (0 != m_iControl) iHeight += m_iSmallHeightMargin; // Top margin

	// Our expand/collapse button
	iHeight += m_iButtonHeight;
	// Control label will be next to this

	if (m_bDoDropDown && !m_bCollapsed)
	{
		iHeight += m_iEditHeight; // Height of the dropdown
		iHeight += m_TextPane.GetFixedHeight();
	}

	return iHeight;
}

int SmartViewPane::GetLines()
{
	auto iStructType = GetDropDownSelectionValue();
	if (!m_bCollapsed && (m_bHasData || iStructType))
	{
		return m_TextPane.GetLines();
	}

	return 0;
}

void SmartViewPane::SetWindowPos(int x, int y, int width, int height)
{
	auto hRes = S_OK;
	if (!m_bDoDropDown && !m_bHasData)
	{
		EC_B(m_CollapseButton.ShowWindow(SW_HIDE));
		EC_B(m_Label.ShowWindow(SW_HIDE));
		EC_B(m_DropDown.ShowWindow(SW_HIDE));
		m_TextPane.ShowWindow(SW_HIDE);
	}
	else
	{
		EC_B(m_CollapseButton.ShowWindow(SW_SHOW));
		EC_B(m_Label.ShowWindow(SW_SHOW));
	}

	if (0 != m_iControl)
	{
		y += m_iSmallHeightMargin;
		height -= m_iSmallHeightMargin;
	}

	ViewPane::SetWindowPos(x, y, width, height);

	y += m_iLabelHeight + m_iSmallHeightMargin;
	height -= m_iButtonHeight + m_iSmallHeightMargin;

	if (m_bCollapsed)
	{
		EC_B(m_DropDown.ShowWindow(SW_HIDE));
		m_TextPane.ShowWindow(SW_HIDE);
	}
	else
	{
		if (m_bDoDropDown)
		{
			EC_B(m_DropDown.ShowWindow(SW_SHOW));
			EC_B(m_DropDown.SetWindowPos(NULL, x, y, width, m_iEditHeight, SWP_NOZORDER));

			y += m_iEditHeight;
			height -= m_iEditHeight;
		}

		m_TextPane.ShowWindow(SW_SHOW);
		m_TextPane.SetWindowPos(x, y, width, height);
	}
}

void SmartViewPane::SetMargins(
	int iMargin,
	int iSideMargin,
	int iLabelHeight, // Height of the label
	int iSmallHeightMargin,
	int iLargeHeightMargin,
	int iButtonHeight, // Height of buttons below the control
	int iEditHeight) // height of an edit control
{
	m_TextPane.SetMargins(iMargin, iSideMargin, iLabelHeight, iSmallHeightMargin, iLargeHeightMargin, iButtonHeight, iEditHeight);
	ViewPane::SetMargins(iMargin, iSideMargin, iLabelHeight, iSmallHeightMargin, iLargeHeightMargin, iButtonHeight, iEditHeight);
}

void SmartViewPane::SetStringW(wstring szMsg)
{
	if (!szMsg.empty())
	{
		m_bHasData = true;
	}
	else
	{
		m_bHasData = false;
	}

	m_TextPane.SetStringW(szMsg);
}

void SmartViewPane::DisableDropDown()
{
	m_bDoDropDown = false;
}

void SmartViewPane::SetParser(__ParsingTypeEnum iParser)
{
	for (size_t iDropNum = 0; iDropNum < SmartViewParserTypeArray.size(); iDropNum++)
	{
		if (iParser == static_cast<__ParsingTypeEnum>(SmartViewParserTypeArray[iDropNum].ulValue))
		{
			SetSelection(iDropNum);
			break;
		}
	}
}

void SmartViewPane::Parse(SBinary myBin)
{
	auto iStructType = static_cast<__ParsingTypeEnum>(GetDropDownSelectionValue());
	auto szSmartView = InterpretBinaryAsString(myBin, iStructType, nullptr);

	m_bHasData = !szSmartView.empty();
	SetStringW(szSmartView);
}
<|endoftext|>


<commit_before>/*! \file ospDVR.cpp A GLUT-based viewer for Wavefront OBJ files */

// viewer widget
#include "../../apps/util/glut3D/glut3D.h"
// ospray, for rendering
#include "ospray/ospray.h"

namespace ospray {
  using std::cout;
  using std::endl;

  const char *renderType = "dvr_ispc";

  /*! \page volview_notes_on_volume_interface Internal Notes on Volume Interface

    Right now i'm using a trivially simple interface to ospray's
    volume code by simply passing filename and dimensions right into
    the ospray volume object, which then does its own parsing *inside*
    ospray. this is, however, not as it should eventually be - to be
    fixed! */

  void error(const std::string &vol)
  {
    cout << "ospray::ospDVR fatal error : " << vol << endl;
    cout << endl;
    cout << "Proper usage: " << endl;
    cout << "  ./ospDVR <sizex> <sizey> <sizez> volFile.raw" << std::endl;
    cout << endl;
    exit(1);
  }

  using ospray::glut3D::Glut3DWidget;

  //! volume viewer widget.
  /*! \internal Note that all handling of camera is almost exactly
    similar to the code in msgView; might make sense to move that into
    a common class! */
  struct VolumeViewer : public Glut3DWidget {
    /*! construct volume from file name and dimensions \see volview_notes_on_volume_interface */
    VolumeViewer(const vec3i dims, const std::string &fileName, int resampleSize=0)
      : Glut3DWidget(Glut3DWidget::FRAMEBUFFER_NONE),
        fb(NULL), renderer(NULL), volume(NULL),
        dims(dims), fileName(fileName), resampleSize(resampleSize)
    {
      camera = ospNewCamera("perspective");
      Assert2(camera,"could not create camera");
      ospSet3f(camera,"pos",-1,1,-1);
      ospSet3f(camera,"dir",+1,-1,+1);
      ospCommit(camera);
      ospCommit(camera);

      volume = ospNewVolume("naive32-uint8");
      Assert(volume && "null volume handle");
      ospSet3i(volume,"dimensions",dims.x,dims.y,dims.z);
      // ospSet3i(volume,"resample_dimensions",resampleSize,resampleSize,resampleSize);
      ospSetString(volume,"filename",fileName.c_str());
      ospCommit(volume);

      renderer = ospNewRenderer(renderType);
      Assert2(renderer,"could not create renderer");
      ospSetParam(renderer,"volume",volume);
      ospSetParam(renderer,"camera",camera);
      ospCommit(renderer);

    };
    virtual void reshape(const ospray::vec2i &newSize)
    {
      Glut3DWidget::reshape(newSize);
      if (fb) ospFreeFrameBuffer(fb);
      fb = ospNewFrameBuffer(newSize,OSP_RGBA_I8);
      ospSetf(camera,"aspect",viewPort.aspect);
      ospCommit(camera);
    }

    virtual void display()
    {
      if (!fb || !renderer) return;

      if (viewPort.modified) {
        Assert2(camera,"ospray camera is null");

        // PRINT(viewPort);

        ospSetVec3f(camera,"pos",viewPort.from);
        ospSetVec3f(camera,"dir",viewPort.at-viewPort.from);
        ospSetVec3f(camera,"up",viewPort.up);
        ospSetf(camera,"aspect",viewPort.aspect);
        ospCommit(camera);
        viewPort.modified = false;
      }

      fps.startRender();
      ospRenderFrame(fb,renderer);
      fps.doneRender();

      ucharFB = (unsigned int *)ospMapFrameBuffer(fb);
      frameBufferMode = Glut3DWidget::FRAMEBUFFER_UCHAR;
      Glut3DWidget::display();

      ospUnmapFrameBuffer(ucharFB,fb);

      char title[1000];

       sprintf(title,"Test04: GlutWidget+ospray API rest (%f fps)",
               fps.getFPS());
       setTitle(title);
      forceRedraw();
    }

    std::string    fileName; /*! volume file name \see volview_notes_on_volume_interface */
    vec3i          dims;     /*! volume dimensions \see volview_notes_on_volume_interface */
    OSPVolume      volume;
    OSPFrameBuffer fb;
    OSPRenderer    renderer;
    OSPCamera      camera;
    int            resampleSize;
    ospray::glut3D::FPSCounter fps;
  };

  void ospDVRMain(int &ac, const char **&av)
  {
    ospLoadModule("dvr");

    if (ac < 5)
      error("no input scene specified (or done so in wrong format)");

    vec3i volDims;
    std::string volFileName;
    int resample = 0;

    for (int i=1;i<ac;i++) {
      std::string arg = av[i];
      if (arg[0] != '-') {
        volDims.x = atoi(av[i+0]);
        volDims.y = atoi(av[i+1]);
        volDims.z = atoi(av[i+2]);
        volFileName = av[i+3];
        i += 3;
      } else if (arg == "--resample") {
        // resample volume to this size
        resample = atoi(av[++i]);
      } else if (arg == "--ispc") {
        // resample volume to this size
        renderType = "dvr_ispc";
      } else if (arg == "--scalar") {
        // resample volume to this size
        renderType = "dvr_scalar";
      } else
        throw std::runtime_error("unknown parameter "+arg);
    }
    // const vec3i volDims(atoi(av[1]),
    //                     atoi(av[2]),
    //                     atoi(av[3]));
    // const std::string volFileName = av[4];

    // -------------------------------------------------------
    // create viewer window
    // -------------------------------------------------------
    VolumeViewer window(volDims,volFileName,resample);
    window.create("ospDVR: OSPRay miniature DVR volume viewer");
    printf("Viewer created. Press 'Q' to quit.\n");
    window.setWorldBounds(box3f(vec3f(0.f),vec3f(1.f)));
    // window.setWorldBounds(box3f(vec3f(0.f),vec3f(resample?vec3i(resample):volDims)));
    ospray::glut3D::runGLUT();
  }
}

int main(int ac, const char **av)
{
  ospInit(&ac,av);
  ospray::glut3D::initGLUT(&ac,av);
  ospray::ospDVRMain(ac,av);
}
<commit_msg>setting stepsize automatically based on volume dims<commit_after>/*! \file ospDVR.cpp A GLUT-based viewer for Wavefront OBJ files */

// viewer widget
#include "../../apps/util/glut3D/glut3D.h"
// ospray, for rendering
#include "ospray/ospray.h"

namespace ospray {
  using std::cout;
  using std::endl;

  const char *renderType = "dvr_ispc";

  /*! \page volview_notes_on_volume_interface Internal Notes on Volume Interface

    Right now i'm using a trivially simple interface to ospray's
    volume code by simply passing filename and dimensions right into
    the ospray volume object, which then does its own parsing *inside*
    ospray. this is, however, not as it should eventually be - to be
    fixed! */

  void error(const std::string &vol)
  {
    cout << "ospray::ospDVR fatal error : " << vol << endl;
    cout << endl;
    cout << "Proper usage: " << endl;
    cout << "  ./ospDVR <sizex> <sizey> <sizez> volFile.raw" << std::endl;
    cout << endl;
    exit(1);
  }

  using ospray::glut3D::Glut3DWidget;

  //! volume viewer widget.
  /*! \internal Note that all handling of camera is almost exactly
    similar to the code in msgView; might make sense to move that into
    a common class! */
  struct VolumeViewer : public Glut3DWidget {
    /*! construct volume from file name and dimensions \see volview_notes_on_volume_interface */
    VolumeViewer(const vec3i dims, const std::string &fileName, int resampleSize=0)
      : Glut3DWidget(Glut3DWidget::FRAMEBUFFER_NONE),
        fb(NULL), renderer(NULL), volume(NULL),
        dims(dims), fileName(fileName), resampleSize(resampleSize)
    {
      camera = ospNewCamera("perspective");
      Assert2(camera,"could not create camera");
      ospSet3f(camera,"pos",-1,1,-1);
      ospSet3f(camera,"dir",+1,-1,+1);
      ospCommit(camera);
      ospCommit(camera);

      volume = ospNewVolume("naive32-uint8");
      Assert(volume && "null volume handle");
      ospSet3i(volume,"dimensions",dims.x,dims.y,dims.z);
      // ospSet3i(volume,"resample_dimensions",resampleSize,resampleSize,resampleSize);
      ospSetString(volume,"filename",fileName.c_str());
      ospCommit(volume);

      renderer = ospNewRenderer(renderType);
      ospSet1f(renderer,"dt",0.5f/std::max(dims.x,std::max(dims.y,dims.z)));

      Assert2(renderer,"could not create renderer");
      ospSetParam(renderer,"volume",volume);
      ospSetParam(renderer,"camera",camera);
      ospCommit(renderer);

    };
    virtual void reshape(const ospray::vec2i &newSize)
    {
      Glut3DWidget::reshape(newSize);
      if (fb) ospFreeFrameBuffer(fb);
      fb = ospNewFrameBuffer(newSize,OSP_RGBA_I8);
      ospSetf(camera,"aspect",viewPort.aspect);
      ospCommit(camera);
    }

    virtual void display()
    {
      if (!fb || !renderer) return;

      if (viewPort.modified) {
        Assert2(camera,"ospray camera is null");

        // PRINT(viewPort);

        ospSetVec3f(camera,"pos",viewPort.from);
        ospSetVec3f(camera,"dir",viewPort.at-viewPort.from);
        ospSetVec3f(camera,"up",viewPort.up);
        ospSetf(camera,"aspect",viewPort.aspect);
        ospCommit(camera);
        viewPort.modified = false;
      }

      fps.startRender();
      ospRenderFrame(fb,renderer);
      fps.doneRender();

      ucharFB = (unsigned int *)ospMapFrameBuffer(fb);
      frameBufferMode = Glut3DWidget::FRAMEBUFFER_UCHAR;
      Glut3DWidget::display();

      ospUnmapFrameBuffer(ucharFB,fb);

      char title[1000];

       sprintf(title,"Test04: GlutWidget+ospray API rest (%f fps)",
               fps.getFPS());
       setTitle(title);
      forceRedraw();
    }

    std::string    fileName; /*! volume file name \see volview_notes_on_volume_interface */
    vec3i          dims;     /*! volume dimensions \see volview_notes_on_volume_interface */
    OSPVolume      volume;
    OSPFrameBuffer fb;
    OSPRenderer    renderer;
    OSPCamera      camera;
    int            resampleSize;
    ospray::glut3D::FPSCounter fps;
  };

  void ospDVRMain(int &ac, const char **&av)
  {
    ospLoadModule("dvr");

    if (ac < 5)
      error("no input scene specified (or done so in wrong format)");

    vec3i volDims;
    std::string volFileName;
    int resample = 0;

    for (int i=1;i<ac;i++) {
      std::string arg = av[i];
      if (arg[0] != '-') {
        volDims.x = atoi(av[i+0]);
        volDims.y = atoi(av[i+1]);
        volDims.z = atoi(av[i+2]);
        volFileName = av[i+3];
        i += 3;
      } else if (arg == "--resample") {
        // resample volume to this size
        resample = atoi(av[++i]);
      } else if (arg == "--ispc") {
        // resample volume to this size
        renderType = "dvr_ispc";
      } else if (arg == "--scalar") {
        // resample volume to this size
        renderType = "dvr_scalar";
      } else
        throw std::runtime_error("unknown parameter "+arg);
    }
    // const vec3i volDims(atoi(av[1]),
    //                     atoi(av[2]),
    //                     atoi(av[3]));
    // const std::string volFileName = av[4];

    // -------------------------------------------------------
    // create viewer window
    // -------------------------------------------------------
    VolumeViewer window(volDims,volFileName,resample);
    window.create("ospDVR: OSPRay miniature DVR volume viewer");
    printf("Viewer created. Press 'Q' to quit.\n");
    window.setWorldBounds(box3f(vec3f(0.f),vec3f(1.f)));
    // window.setWorldBounds(box3f(vec3f(0.f),vec3f(resample?vec3i(resample):volDims)));
    ospray::glut3D::runGLUT();
  }
}

int main(int ac, const char **av)
{
  ospInit(&ac,av);
  ospray::glut3D::initGLUT(&ac,av);
  ospray::ospDVRMain(ac,av);
}
<|endoftext|>


<commit_before>/*
 * LinuxFileMonitor.cpp
 *
 * Copyright (C) 2009-11 by RStudio, Inc.
 *
 * This program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include <core/system/FileMonitor.hpp>

#include <core/Log.hpp>
#include <core/Error.hpp>
#include <core/FileInfo.hpp>

#include <core/system/FileScanner.hpp>
#include <core/system/System.hpp>

#include "FileMonitorImpl.hpp"

namespace core {
namespace system {
namespace file_monitor {

namespace {

} // anonymous namespace

namespace detail {

// register a new file monitor
Handle registerMonitor(const core::FilePath& filePath,
                       bool recursive,
                       const Callbacks& callbacks)
{
   return Handle();
}

// unregister a file monitor
void unregisterMonitor(Handle handle)
{

}

void run(const boost::function<void()>& checkForInput)
{

}

void stop()
{

}

} // namespace detail
} // namespace file_monitor
} // namespace system
} // namespace core

<commit_msg>add todos<commit_after>/*
 * LinuxFileMonitor.cpp
 *
 * Copyright (C) 2009-11 by RStudio, Inc.
 *
 * This program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include <core/system/FileMonitor.hpp>

#include <core/Log.hpp>
#include <core/Error.hpp>
#include <core/FileInfo.hpp>

#include <core/system/FileScanner.hpp>
#include <core/system/System.hpp>

#include "FileMonitorImpl.hpp"

// TODO: investigate parallel package (multicore) interactions with file monitor

// TODO: should we be using lstat64?

namespace core {
namespace system {
namespace file_monitor {

namespace {

} // anonymous namespace

namespace detail {

// register a new file monitor
Handle registerMonitor(const core::FilePath& filePath,
                       bool recursive,
                       const Callbacks& callbacks)
{
   return Handle();
}

// unregister a file monitor
void unregisterMonitor(Handle handle)
{

}

void run(const boost::function<void()>& checkForInput)
{

}

void stop()
{

}

} // namespace detail
} // namespace file_monitor
} // namespace system
} // namespace core

<|endoftext|>


<commit_before>// Copyright (C) 2018 The Bitcoin Unlimited developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "xversionmessage.h"
#include "hashwrapper.h"
#include "random.h"
#include "streams.h"
#include "util.h"

bool xversion_deterministic_hashing = false;

XMapSaltedHasher::XMapSaltedHasher()
    : k0(xversion_deterministic_hashing ? 0x1122334455667788UL : GetRand(std::numeric_limits<uint64_t>::max())),
      k1(xversion_deterministic_hashing ? 0x99aabbccddeeff00UL : GetRand(std::numeric_limits<uint64_t>::max()))
{
}

uint64_t XMapSaltedHasher::operator()(const uint64_t key) const
{
    CSipHasher hasher(k0, k1);
    return hasher.Write(key).Finalize();
}

uint64_t CXVersionMessage::as_u64c(const uint64_t k) const
{
    if (xmap.count(k) == 0)
        return 0;
    LOCK(cacheProtector);
    if (cache_u64c.count(k) == 0)
    {
        const std::vector<uint8_t> &vec = xmap.at(k);
        uint64_t v = 0;
        try
        {
            CDataStream s(vec, SER_NETWORK, PROTOCOL_VERSION);
            s >> COMPACTSIZE(v);
        }
        catch (...)
        {
            LOG(NET, "Error reading extended configuration key %016llx as u64c. Assuming zero.\n", k);
            v = 0;
        }
        cache_u64c[k] = v;
    }
    return cache_u64c.at(k);
}

void CXVersionMessage::set_u64c(const uint64_t key, const uint64_t val)
{
    CDataStream s(SER_NETWORK, PROTOCOL_VERSION);
    s << COMPACTSIZE(val);

    std::vector<uint8_t> vec;
    vec.insert(vec.begin(), s.begin(), s.end());
    xmap[key] = vec;
    LOCK(cacheProtector);
    cache_u64c[key] = val;
}
<commit_msg>move lock before count to solve potential segfault issue where map can be read and written to at the same time<commit_after>// Copyright (C) 2018 The Bitcoin Unlimited developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "xversionmessage.h"
#include "hashwrapper.h"
#include "random.h"
#include "streams.h"
#include "util.h"

bool xversion_deterministic_hashing = false;

XMapSaltedHasher::XMapSaltedHasher()
    : k0(xversion_deterministic_hashing ? 0x1122334455667788UL : GetRand(std::numeric_limits<uint64_t>::max())),
      k1(xversion_deterministic_hashing ? 0x99aabbccddeeff00UL : GetRand(std::numeric_limits<uint64_t>::max()))
{
}

uint64_t XMapSaltedHasher::operator()(const uint64_t key) const
{
    CSipHasher hasher(k0, k1);
    return hasher.Write(key).Finalize();
}

uint64_t CXVersionMessage::as_u64c(const uint64_t k) const
{
    LOCK(cacheProtector);
    if (xmap.count(k) == 0)
        return 0;
    if (cache_u64c.count(k) == 0)
    {
        const std::vector<uint8_t> &vec = xmap.at(k);
        uint64_t v = 0;
        try
        {
            CDataStream s(vec, SER_NETWORK, PROTOCOL_VERSION);
            s >> COMPACTSIZE(v);
        }
        catch (...)
        {
            LOG(NET, "Error reading extended configuration key %016llx as u64c. Assuming zero.\n", k);
            v = 0;
        }
        cache_u64c[k] = v;
    }
    return cache_u64c.at(k);
}

void CXVersionMessage::set_u64c(const uint64_t key, const uint64_t val)
{
    CDataStream s(SER_NETWORK, PROTOCOL_VERSION);
    s << COMPACTSIZE(val);

    std::vector<uint8_t> vec;
    vec.insert(vec.begin(), s.begin(), s.end());
    xmap[key] = vec;
    LOCK(cacheProtector);
    cache_u64c[key] = val;
}
<|endoftext|>


<commit_before>#ifndef __PROCESS_PROCESS_HPP__
#define __PROCESS_PROCESS_HPP__

#include <stdint.h>
#include <pthread.h>

#include <map>
#include <queue>

#include <process/address.hpp>
#include <process/clock.hpp>
#include <process/event.hpp>
#include <process/filter.hpp>
#include <process/http.hpp>
#include <process/message.hpp>
#include <process/mime.hpp>
#include <process/pid.hpp>

#include <stout/duration.hpp>
#include <stout/lambda.hpp>
#include <stout/option.hpp>
#include <stout/thread.hpp>

namespace process {

class ProcessBase : public EventVisitor
{
public:
  explicit ProcessBase(const std::string& id = "");

  virtual ~ProcessBase();

  UPID self() const { return pid; }

protected:
  // Invoked when an event is serviced.
  virtual void serve(const Event& event)
  {
    event.visit(this);
  }

  // Callbacks used to visit (i.e., handle) a specific event.
  virtual void visit(const MessageEvent& event);
  virtual void visit(const DispatchEvent& event);
  virtual void visit(const HttpEvent& event);
  virtual void visit(const ExitedEvent& event);
  virtual void visit(const TerminateEvent& event);

  // Invoked when a process gets spawned.
  virtual void initialize() {}

  // Invoked when a process is terminated (unless visit is overriden).
  virtual void finalize() {}

  // Invoked when a linked process has exited (see link).
  virtual void exited(const UPID& pid) {}

  // Invoked when a linked process can no longer be monitored (see link).
  virtual void lost(const UPID& pid) {}

  // Puts a message at front of queue.
  void inject(
      const UPID& from,
      const std::string& name,
      const char* data = NULL,
      size_t length = 0);

  // Sends a message with data to PID.
  void send(
      const UPID& to,
      const std::string& name,
      const char* data = NULL,
      size_t length = 0);

  // Links with the specified PID. Linking with a process from within
  // the same "operating system process" is gauranteed to give you
  // perfect monitoring of that process. However, linking with a
  // process on another machine might result in receiving lost
  // callbacks due to the nature of a distributed environment.
  UPID link(const UPID& pid);

  // The default visit implementation for message events invokes
  // installed message handlers, or delegates the message to another
  // process (a delegate can be installed below but a message handler
  // always takes precedence over delegating). A message handler is
  // any function which takes two arguments, the "from" pid and the
  // message body.
  typedef lambda::function<void(const UPID&, const std::string&)>
  MessageHandler;

  // Setup a handler for a message.
  void install(
      const std::string& name,
      const MessageHandler& handler)
  {
    handlers.message[name] = handler;
  }

  template <typename T>
  void install(
      const std::string& name,
      void (T::*method)(const UPID&, const std::string&))
  {
    // Note that we use dynamic_cast here so a process can use
    // multiple inheritance if it sees so fit (e.g., to implement
    // multiple callback interfaces).
    MessageHandler handler =
      lambda::bind(method, dynamic_cast<T*>(this), lambda::_1, lambda::_2);
    install(name, handler);
  }

  // Delegate incoming message's with the specified name to pid.
  void delegate(const std::string& name, const UPID& pid)
  {
    delegates[name] = pid;
  }

  // The default visit implementation for HTTP events invokes
  // installed HTTP handlers. A HTTP handler is any function which
  // takes an http::Request object and returns an http::Response.
  typedef lambda::function<Future<http::Response>(const http::Request&)>
  HttpRequestHandler;

  // Setup a handler for an HTTP request.
  void route(
      const std::string& name,
      const Option<std::string>& help,
      const HttpRequestHandler& handler);

  template <typename T>
  void route(
      const std::string& name,
      const Option<std::string>& help,
      Future<http::Response> (T::*method)(const http::Request&))
  {
    // Note that we use dynamic_cast here so a process can use
    // multiple inheritance if it sees so fit (e.g., to implement
    // multiple callback interfaces).
    HttpRequestHandler handler =
      lambda::bind(method, dynamic_cast<T*>(this), lambda::_1);
    route(name, help, handler);
  }

  // Provide the static asset(s) at the specified _absolute_ path for
  // the specified name. For example, assuming the process named
  // "server" invoked 'provide("name", "path")' then an HTTP request
  // for '/server/name' would return the asset found at 'path'. If the
  // specified path is a directory then an HTTP request for
  // '/server/name/file' would return the asset found at
  // '/path/file'. The 'Content-Type' header of the HTTP response will
  // be set to the specified type given the file extension (you can
  // manipulate this via the optional 'types' parameter).
  void provide(
      const std::string& name,
      const std::string& path,
      const std::map<std::string, std::string>& types = mime::types)
  {
    // TODO(benh): Check that name is only alphanumeric (i.e., has no
    // '/') and that path is absolute.
    Asset asset;
    asset.path = path;
    asset.types = types;
    assets[name] = asset;
  }

  void lock()
  {
    pthread_mutex_lock(&m);
  }

  void unlock()
  {
    pthread_mutex_unlock(&m);
  }

  template<typename T>
  size_t eventCount()
  {
    size_t count = 0U;

    lock();
    count = std::count_if(events.begin(), events.end(), isEventType<T>);
    unlock();

    return count;
  }

private:
  friend class SocketManager;
  friend class ProcessManager;
  friend class ProcessReference;
  friend void* schedule(void*);

  // Process states.
  enum {
    BOTTOM,
    READY,
    RUNNING,
    BLOCKED,
    TERMINATING,
    TERMINATED
  } state;

  template<typename T>
  static bool isEventType(const Event* event)
  {
    return event->is<T>();
  }

  // Mutex protecting internals.
  // TODO(benh): Consider replacing with a spinlock, on multi-core systems.
  pthread_mutex_t m;

  // Enqueue the specified message, request, or function call.
  void enqueue(Event* event, bool inject = false);

  // Delegates for messages.
  std::map<std::string, UPID> delegates;

  // Handlers for messages and HTTP requests.
  struct {
    std::map<std::string, MessageHandler> message;
    std::map<std::string, HttpRequestHandler> http;
  } handlers;

  // Definition of a static asset.
  struct Asset
  {
    std::string path;
    std::map<std::string, std::string> types;
  };

  // Static assets(s) to provide.
  std::map<std::string, Asset> assets;

  // Queue of received events, requires lock()ed access!
  std::deque<Event*> events;

  // Active references.
  int refs;

  // Process PID.
  UPID pid;
};

template <typename T>
class Process : public virtual ProcessBase {
public:
  virtual ~Process() {}

  // Returns pid of process; valid even before calling spawn.
  PID<T> self() const { return PID<T>(dynamic_cast<const T*>(this)); }

protected:
  // Useful typedefs for dispatch/delay/defer to self()/this.
  typedef T Self;
  typedef T This;
};

/**
 * Initialize the library. Note that libprocess uses Google's glog and
 * you can specify options for it (e.g., a logging directory) via
 * environment variables (see the glog documentation for more
 * information).
 *
 * @param delegate process to receive root HTTP requests
 */
void initialize(const std::string& delegate = "");

/**
 * Clean up the library.
 */
void finalize();

/**
 * Returns the socket address associated with this instance of the library.
 */
network::Address address();

/**
 * Spawn a new process.
 *
 * @param process process to be spawned
 * @param manage boolean whether process should get garbage collected
 */
UPID spawn(ProcessBase* process, bool manage = false);

inline UPID spawn(ProcessBase& process, bool manage = false)
{
  return spawn(&process, manage);
}

template <typename T>
PID<T> spawn(T* t, bool manage = false)
{
  // We save the pid before spawn is called because it's possible that
  // the process has already been deleted after spawn returns (e.g.,
  // if 'manage' is true).
  PID<T> pid(t);

  if (!spawn(static_cast<ProcessBase*>(t), manage)) {
    return PID<T>();
  }

  return pid;
}

template <typename T>
PID<T> spawn(T& t, bool manage = false)
{
  return spawn(&t, manage);
}

/**
 * Send a TERMINATE message to a process, injecting the message ahead
 * of all other messages queued up for that process if requested. Note
 * that currently terminate only works for local processes (in the
 * future we plan to make this more explicit via the use of a PID
 * instead of a UPID).
 *
 * @param inject if true message will be put on front of message queue
 */
void terminate(const UPID& pid, bool inject = true);
void terminate(const ProcessBase& process, bool inject = true);
void terminate(const ProcessBase* process, bool inject = true);

/**
 * Wait for process to exit no more than specified seconds (returns
 * true if actually waited on a process).
 *
 * @param PID id of the process
 * @param secs max time to wait, 0 implies wait for ever
 */
bool wait(const UPID& pid, const Duration& duration = Seconds(-1));
bool wait(const ProcessBase& process, const Duration& duration = Seconds(-1));
bool wait(const ProcessBase* process, const Duration& duration = Seconds(-1));

/**
 * Sends a message with data without a return address.
 *
 * @param to receiver
 * @param name message name
 * @param data data to send (gets copied)
 * @param length length of data
 */
void post(const UPID& to,
          const std::string& name,
          const char* data = NULL,
          size_t length = 0);

void post(const UPID& from,
          const UPID& to,
          const std::string& name,
          const char* data = NULL,
          size_t length = 0);

// Inline implementations of above.
inline void terminate(const ProcessBase& process, bool inject)
{
  terminate(process.self(), inject);
}

inline void terminate(const ProcessBase* process, bool inject)
{
  terminate(process->self(), inject);
}

inline bool wait(const ProcessBase& process, const Duration& duration)
{
  return process::wait(process.self(), duration); // Explicit to disambiguate.
}

inline bool wait(const ProcessBase* process, const Duration& duration)
{
  return process::wait(process->self(), duration); // Explicit to disambiguate.
}

// Per thread process pointer. The extra level of indirection from
// _process_ to __process__ is used in order to take advantage of the
// ThreadLocal operators without needing the extra dereference.
extern ThreadLocal<ProcessBase>* _process_;

#define __process__ (*_process_)

// NOTE: Methods in this namespace should only be used in tests to
// inject arbitrary events.
namespace inject {
// Simulates disconnection of the link between 'from' and 'to' by
// sending an 'ExitedEvent' to 'to'.
bool exited(const UPID& from, const UPID& to);
} // namespace inject {

} // namespace process {

#endif // __PROCESS_PROCESS_HPP__
<commit_msg>Fix typo in comment.<commit_after>#ifndef __PROCESS_PROCESS_HPP__
#define __PROCESS_PROCESS_HPP__

#include <stdint.h>
#include <pthread.h>

#include <map>
#include <queue>

#include <process/address.hpp>
#include <process/clock.hpp>
#include <process/event.hpp>
#include <process/filter.hpp>
#include <process/http.hpp>
#include <process/message.hpp>
#include <process/mime.hpp>
#include <process/pid.hpp>

#include <stout/duration.hpp>
#include <stout/lambda.hpp>
#include <stout/option.hpp>
#include <stout/thread.hpp>

namespace process {

class ProcessBase : public EventVisitor
{
public:
  explicit ProcessBase(const std::string& id = "");

  virtual ~ProcessBase();

  UPID self() const { return pid; }

protected:
  // Invoked when an event is serviced.
  virtual void serve(const Event& event)
  {
    event.visit(this);
  }

  // Callbacks used to visit (i.e., handle) a specific event.
  virtual void visit(const MessageEvent& event);
  virtual void visit(const DispatchEvent& event);
  virtual void visit(const HttpEvent& event);
  virtual void visit(const ExitedEvent& event);
  virtual void visit(const TerminateEvent& event);

  // Invoked when a process gets spawned.
  virtual void initialize() {}

  // Invoked when a process is terminated (unless visit is overriden).
  virtual void finalize() {}

  // Invoked when a linked process has exited (see link).
  virtual void exited(const UPID& pid) {}

  // Invoked when a linked process can no longer be monitored (see link).
  virtual void lost(const UPID& pid) {}

  // Puts a message at front of queue.
  void inject(
      const UPID& from,
      const std::string& name,
      const char* data = NULL,
      size_t length = 0);

  // Sends a message with data to PID.
  void send(
      const UPID& to,
      const std::string& name,
      const char* data = NULL,
      size_t length = 0);

  // Links with the specified PID. Linking with a process from within
  // the same "operating system process" is guaranteed to give you
  // perfect monitoring of that process. However, linking with a
  // process on another machine might result in receiving lost
  // callbacks due to the nature of a distributed environment.
  UPID link(const UPID& pid);

  // The default visit implementation for message events invokes
  // installed message handlers, or delegates the message to another
  // process (a delegate can be installed below but a message handler
  // always takes precedence over delegating). A message handler is
  // any function which takes two arguments, the "from" pid and the
  // message body.
  typedef lambda::function<void(const UPID&, const std::string&)>
  MessageHandler;

  // Setup a handler for a message.
  void install(
      const std::string& name,
      const MessageHandler& handler)
  {
    handlers.message[name] = handler;
  }

  template <typename T>
  void install(
      const std::string& name,
      void (T::*method)(const UPID&, const std::string&))
  {
    // Note that we use dynamic_cast here so a process can use
    // multiple inheritance if it sees so fit (e.g., to implement
    // multiple callback interfaces).
    MessageHandler handler =
      lambda::bind(method, dynamic_cast<T*>(this), lambda::_1, lambda::_2);
    install(name, handler);
  }

  // Delegate incoming message's with the specified name to pid.
  void delegate(const std::string& name, const UPID& pid)
  {
    delegates[name] = pid;
  }

  // The default visit implementation for HTTP events invokes
  // installed HTTP handlers. A HTTP handler is any function which
  // takes an http::Request object and returns an http::Response.
  typedef lambda::function<Future<http::Response>(const http::Request&)>
  HttpRequestHandler;

  // Setup a handler for an HTTP request.
  void route(
      const std::string& name,
      const Option<std::string>& help,
      const HttpRequestHandler& handler);

  template <typename T>
  void route(
      const std::string& name,
      const Option<std::string>& help,
      Future<http::Response> (T::*method)(const http::Request&))
  {
    // Note that we use dynamic_cast here so a process can use
    // multiple inheritance if it sees so fit (e.g., to implement
    // multiple callback interfaces).
    HttpRequestHandler handler =
      lambda::bind(method, dynamic_cast<T*>(this), lambda::_1);
    route(name, help, handler);
  }

  // Provide the static asset(s) at the specified _absolute_ path for
  // the specified name. For example, assuming the process named
  // "server" invoked 'provide("name", "path")' then an HTTP request
  // for '/server/name' would return the asset found at 'path'. If the
  // specified path is a directory then an HTTP request for
  // '/server/name/file' would return the asset found at
  // '/path/file'. The 'Content-Type' header of the HTTP response will
  // be set to the specified type given the file extension (you can
  // manipulate this via the optional 'types' parameter).
  void provide(
      const std::string& name,
      const std::string& path,
      const std::map<std::string, std::string>& types = mime::types)
  {
    // TODO(benh): Check that name is only alphanumeric (i.e., has no
    // '/') and that path is absolute.
    Asset asset;
    asset.path = path;
    asset.types = types;
    assets[name] = asset;
  }

  void lock()
  {
    pthread_mutex_lock(&m);
  }

  void unlock()
  {
    pthread_mutex_unlock(&m);
  }

  template<typename T>
  size_t eventCount()
  {
    size_t count = 0U;

    lock();
    count = std::count_if(events.begin(), events.end(), isEventType<T>);
    unlock();

    return count;
  }

private:
  friend class SocketManager;
  friend class ProcessManager;
  friend class ProcessReference;
  friend void* schedule(void*);

  // Process states.
  enum {
    BOTTOM,
    READY,
    RUNNING,
    BLOCKED,
    TERMINATING,
    TERMINATED
  } state;

  template<typename T>
  static bool isEventType(const Event* event)
  {
    return event->is<T>();
  }

  // Mutex protecting internals.
  // TODO(benh): Consider replacing with a spinlock, on multi-core systems.
  pthread_mutex_t m;

  // Enqueue the specified message, request, or function call.
  void enqueue(Event* event, bool inject = false);

  // Delegates for messages.
  std::map<std::string, UPID> delegates;

  // Handlers for messages and HTTP requests.
  struct {
    std::map<std::string, MessageHandler> message;
    std::map<std::string, HttpRequestHandler> http;
  } handlers;

  // Definition of a static asset.
  struct Asset
  {
    std::string path;
    std::map<std::string, std::string> types;
  };

  // Static assets(s) to provide.
  std::map<std::string, Asset> assets;

  // Queue of received events, requires lock()ed access!
  std::deque<Event*> events;

  // Active references.
  int refs;

  // Process PID.
  UPID pid;
};

template <typename T>
class Process : public virtual ProcessBase {
public:
  virtual ~Process() {}

  // Returns pid of process; valid even before calling spawn.
  PID<T> self() const { return PID<T>(dynamic_cast<const T*>(this)); }

protected:
  // Useful typedefs for dispatch/delay/defer to self()/this.
  typedef T Self;
  typedef T This;
};

/**
 * Initialize the library. Note that libprocess uses Google's glog and
 * you can specify options for it (e.g., a logging directory) via
 * environment variables (see the glog documentation for more
 * information).
 *
 * @param delegate process to receive root HTTP requests
 */
void initialize(const std::string& delegate = "");

/**
 * Clean up the library.
 */
void finalize();

/**
 * Returns the socket address associated with this instance of the library.
 */
network::Address address();

/**
 * Spawn a new process.
 *
 * @param process process to be spawned
 * @param manage boolean whether process should get garbage collected
 */
UPID spawn(ProcessBase* process, bool manage = false);

inline UPID spawn(ProcessBase& process, bool manage = false)
{
  return spawn(&process, manage);
}

template <typename T>
PID<T> spawn(T* t, bool manage = false)
{
  // We save the pid before spawn is called because it's possible that
  // the process has already been deleted after spawn returns (e.g.,
  // if 'manage' is true).
  PID<T> pid(t);

  if (!spawn(static_cast<ProcessBase*>(t), manage)) {
    return PID<T>();
  }

  return pid;
}

template <typename T>
PID<T> spawn(T& t, bool manage = false)
{
  return spawn(&t, manage);
}

/**
 * Send a TERMINATE message to a process, injecting the message ahead
 * of all other messages queued up for that process if requested. Note
 * that currently terminate only works for local processes (in the
 * future we plan to make this more explicit via the use of a PID
 * instead of a UPID).
 *
 * @param inject if true message will be put on front of message queue
 */
void terminate(const UPID& pid, bool inject = true);
void terminate(const ProcessBase& process, bool inject = true);
void terminate(const ProcessBase* process, bool inject = true);

/**
 * Wait for process to exit no more than specified seconds (returns
 * true if actually waited on a process).
 *
 * @param PID id of the process
 * @param secs max time to wait, 0 implies wait for ever
 */
bool wait(const UPID& pid, const Duration& duration = Seconds(-1));
bool wait(const ProcessBase& process, const Duration& duration = Seconds(-1));
bool wait(const ProcessBase* process, const Duration& duration = Seconds(-1));

/**
 * Sends a message with data without a return address.
 *
 * @param to receiver
 * @param name message name
 * @param data data to send (gets copied)
 * @param length length of data
 */
void post(const UPID& to,
          const std::string& name,
          const char* data = NULL,
          size_t length = 0);

void post(const UPID& from,
          const UPID& to,
          const std::string& name,
          const char* data = NULL,
          size_t length = 0);

// Inline implementations of above.
inline void terminate(const ProcessBase& process, bool inject)
{
  terminate(process.self(), inject);
}

inline void terminate(const ProcessBase* process, bool inject)
{
  terminate(process->self(), inject);
}

inline bool wait(const ProcessBase& process, const Duration& duration)
{
  return process::wait(process.self(), duration); // Explicit to disambiguate.
}

inline bool wait(const ProcessBase* process, const Duration& duration)
{
  return process::wait(process->self(), duration); // Explicit to disambiguate.
}

// Per thread process pointer. The extra level of indirection from
// _process_ to __process__ is used in order to take advantage of the
// ThreadLocal operators without needing the extra dereference.
extern ThreadLocal<ProcessBase>* _process_;

#define __process__ (*_process_)

// NOTE: Methods in this namespace should only be used in tests to
// inject arbitrary events.
namespace inject {
// Simulates disconnection of the link between 'from' and 'to' by
// sending an 'ExitedEvent' to 'to'.
bool exited(const UPID& from, const UPID& to);
} // namespace inject {

} // namespace process {

#endif // __PROCESS_PROCESS_HPP__
<|endoftext|>


<commit_before>#pragma once

#include "global_config.hpp"

namespace mocc {

    inline bool fp_equiv_ulp(float_t v1, float_t v2) {
        int i1 = *(int*) &v1;
        if (i1 < 0) {
            i1 = 0x80000000 - i1;
        }
        int i2 = *(int*) &v2;
        if (i2 < 0) {
            i2 = 0x80000000 - i2;
        }

        return abs(i1 - i2) < 100;
    }

    inline bool fp_equiv_rel(float_t v1, float_t v2) {
        return fabs(v1-v2)/fabs(v1) < FLOAT_EPS;
    }
    inline bool fp_equiv_abs(float_t v1, float_t v2) {
        return fabs(v1-v2) < FLOAT_EPS;
    }
}
<commit_msg>Add inclusion for cmath in fp_utils.hpp<commit_after>#pragma once
#include <cmath>

#include "global_config.hpp"

namespace mocc {

    inline bool fp_equiv_ulp(float_t v1, float_t v2) {
        int i1 = *(int*) &v1;
        if (i1 < 0) {
            i1 = 0x80000000 - i1;
        }
        int i2 = *(int*) &v2;
        if (i2 < 0) {
            i2 = 0x80000000 - i2;
        }

        return abs(i1 - i2) < 100;
    }

    inline bool fp_equiv_rel(float_t v1, float_t v2) {
        return fabs(v1-v2)/fabs(v1) < FLOAT_EPS;
    }
    inline bool fp_equiv_abs(float_t v1, float_t v2) {
        return fabs(v1-v2) < FLOAT_EPS;
    }
}
<|endoftext|>


<commit_before>#include "../../include/InputManager.hpp"

InputManager::InputManager( sf::Event* event, sf::RenderWindow* window ) {
    this->event  = event;
    this->window = window;
}

bool InputManager::keyPressed( const sf::Event::KeyEvent key ) {
    return event->type == sf::Event::KeyPressed && event->key.code == key.code;
}

bool InputManager::keyPressed( const std::vector< sf::Event::KeyEvent > keys ) {
    for( sf::Event::KeyEvent key : keys ) {
        if( keyPressed( key ) ) {
            return true;
        }
    }

    return false;
}

bool InputManager::keyReleased( const sf::Event::KeyEvent key ) {
    return event->type == sf::Event::KeyReleased && event->key.code == key.code;
}

bool InputManager::keyReleased( const std::vector< sf::Event::KeyEvent > keys ) {
    for( sf::Event::KeyEvent key : keys ) {
        if( keyReleased( key ) ) {
            return true;
        }
    }

    return false;
}

bool InputManager::isSpriteClicked( const sf::Mouse::Button& button, const sf::Sprite& sprite ) {
    if( sf::Mouse::isButtonPressed( button ) ) {
        if( sprite.getGlobalBounds().contains(
                sf::Vector2< float >( sf::Mouse::getPosition( *window ) ) ) ) {
            return true;
        }
    }

    return false;
}
<commit_msg>Melhorada a checagem do clique<commit_after>#include "../../include/InputManager.hpp"
#include "../../include/Collision.hpp"

InputManager::InputManager( sf::Event* event, sf::RenderWindow* window ) {
    this->event  = event;
    this->window = window;
}

bool InputManager::keyPressed( const sf::Event::KeyEvent key ) {
    return event->type == sf::Event::KeyPressed && event->key.code == key.code;
}

bool InputManager::keyPressed( const std::vector< sf::Event::KeyEvent > keys ) {
    for( sf::Event::KeyEvent key : keys ) {
        if( keyPressed( key ) ) {
            return true;
        }
    }

    return false;
}

bool InputManager::keyReleased( const sf::Event::KeyEvent key ) {
    return event->type == sf::Event::KeyReleased && event->key.code == key.code;
}

bool InputManager::keyReleased( const std::vector< sf::Event::KeyEvent > keys ) {
    for( sf::Event::KeyEvent key : keys ) {
        if( keyReleased( key ) ) {
            return true;
        }
    }

    return false;
}

bool InputManager::isSpriteClicked( const sf::Mouse::Button& button, const sf::Sprite& sprite ) {
    if( sf::Mouse::isButtonPressed( button ) ) {
        sf::Vector2< float > vector( sf::Mouse::getPosition( *window ) );

        if( Collision::VectorPerfectTest( sprite, vector ) ) {
            return true;
        }
    }

    return false;
}
<|endoftext|>