<commit_before>#include "scene/styleContext.h"

#include "data/propertyItem.h"
#include "data/tileData.h"
#include "log.h"
#include "platform.h"
#include "scene/filters.h"
#include "scene/scene.h"
#include "util/mapProjection.h"
#include "util/builders.h"
#include "util/yamlUtil.h"

#define DUMP(...) // do { logMsg(__VA_ARGS__); duk_dump_context_stderr(m_ctx); } while(0)
#define DBG(...) do { logMsg(__VA_ARGS__); duk_dump_context_stderr(m_ctx); } while(0)

namespace Tangram {

static const std::string key_geom("$geometry");
static const std::string key_zoom("$zoom");

static const std::vector<std::string> s_geometryStrings = {
    "", // unknown
    "point",
    "line",
    "polygon",
};

StyleContext::StyleContext() {
    m_jsContext = createJavaScriptContext();
}

// Convert a scalar node to a boolean, double, or string (in that order)
// and for the first conversion that works, push it to the top of the JS stack.
JSValue pushYamlScalarAsJsPrimitive(JavaScriptScope& jsScope, const YAML::Node& node) {
    bool booleanValue = false;
    double numberValue = 0.;
    if (YamlUtil::getBool(node, booleanValue)) {
        return jsScope.newBoolean(booleanValue);
    } else if (YamlUtil::getDouble(node, numberValue)) {
        return jsScope.newNumber(numberValue);
    } else {
        return jsScope.newString(node.Scalar());
    }
}

JSValue pushYamlScalarAsJsFunctionOrString(JavaScriptScope& jsScope, const YAML::Node& node) {
    auto value = jsScope.newFunction(node.Scalar());
    if (value) {
        return value;
    }
    return jsScope.newString(node.Scalar());
}

JSValue StyleContext::parseSceneGlobals(JavaScriptScope& jsScope, const YAML::Node& node) {
    switch(node.Type()) {
    case YAML::NodeType::Scalar: {
        auto& scalar = node.Scalar();
        if (scalar.compare(0, 8, "function") == 0) {
            return pushYamlScalarAsJsFunctionOrString(jsScope, node);
        } else {
            return pushYamlScalarAsJsPrimitive(jsScope, node);
        }
        break;
    }
    case YAML::NodeType::Sequence: {
        auto jsArray = jsScope.newArray();
        for (size_t i = 0; i < node.size(); i++) {
            jsArray->setValueAtIndex(i, parseSceneGlobals(jsScope, node[i]));
        }
        return jsArray;
        break;
    }
    case YAML::NodeType::Map: {
        auto jsObject = jsScope.newObject();
        for (const auto& entry : node) {
            if (!entry.first.IsScalar()) {
                continue; // Can't put non-scalar keys in JS objects.
            }
            jsObject->setValueForProperty(entry.first.Scalar(), parseSceneGlobals(jsScope, entry.second));
        }
        return jsObject;
        break;
    }
    default:
        return jsScope.newNull();
        break;
    }
}

void StyleContext::setSceneGlobals(const YAML::Node& sceneGlobals) {

    if (!sceneGlobals) { return; }

    JavaScriptScope jsScope(*m_jsContext);

    auto jsValue = parseSceneGlobals(jsScope, sceneGlobals);

    m_jsContext->setGlobalValue("global", std::move(jsValue));
}

void StyleContext::initFunctions(const Scene& _scene) {

    if (_scene.id == m_sceneId) {
        return;
    }
    m_sceneId = _scene.id;

    setSceneGlobals(_scene.config()["global"]);
    setFunctions(_scene.functions());
}

bool StyleContext::setFunctions(const std::vector<std::string>& _functions) {
    uint32_t id = 0;
    bool error = false;
    for (auto& function : _functions) {
        id = m_jsContext->addFunction(function, error);
    }

    m_functionCount = id;

    DUMP("setFunctions\n");
    return !error;
}

bool StyleContext::addFunction(const std::string& _function) {
    bool error = false;
    m_jsContext->addFunction(_function, error);
    m_functionCount++;
    return !error;
}

void StyleContext::setFeature(const Feature& _feature) {

    m_feature = &_feature;

    if (m_keywordGeom != m_feature->geometryType) {
        setKeyword(key_geom, s_geometryStrings[m_feature->geometryType]);
        m_keywordGeom = m_feature->geometryType;
    }

    m_jsContext->setCurrentFeature(&_feature);
}

void StyleContext::setKeywordZoom(int _zoom) {
    if (m_keywordZoom != _zoom) {
        setKeyword(key_zoom, _zoom);
        m_keywordZoom = _zoom;
    }
}

void StyleContext::setKeyword(const std::string& _key, Value _val) {
    auto keywordKey = Filter::keywordType(_key);
    if (keywordKey == FilterKeyword::undefined) {
        LOG("Undefined Keyword: %s", _key.c_str());
        return;
    }

    // Unset shortcuts in case setKeyword was not called by
    // the helper functions above.
    if (_key == key_zoom) { m_keywordZoom = -1; }
    if (_key == key_geom) { m_keywordGeom = -1; }

    Value& entry = m_keywords[static_cast<uint8_t>(keywordKey)];
    if (entry == _val) { return; }

    {
        JavaScriptScope jsScope(*m_jsContext);
        JSValue value;
        if (_val.is<std::string>()) {
            value = jsScope.newString(_val.get<std::string>());
        } else if (_val.is<double>()) {
            value = jsScope.newNumber(_val.get<double>());
        }
        m_jsContext->setGlobalValue(_key, std::move(value));
    }

    entry = std::move(_val);
}

float StyleContext::getPixelAreaScale() {
    // scale the filter value with pixelsPerMeter
    // used with `px2` area filtering
    double metersPerPixel = MapProjection::EARTH_CIRCUMFERENCE_METERS * exp2(-m_keywordZoom) / MapProjection::tileSize();
    return metersPerPixel * metersPerPixel;
}

const Value& StyleContext::getKeyword(const std::string& _key) const {
    return getKeyword(Filter::keywordType(_key));
}

void StyleContext::clear() {
    m_jsContext->setCurrentFeature(nullptr);
}

bool StyleContext::evalFilter(FunctionID _id) {
    bool result = m_jsContext->evaluateBooleanFunction(_id);
    return result;
}

bool StyleContext::evalStyle(FunctionID _id, StyleParamKey _key, StyleParam::Value& _val) {
    _val = none_type{};

    JavaScriptScope jsScope(*m_jsContext);
    auto jsValue = jsScope.getFunctionResult(_id);
    if (!jsValue) {
        return false;
    }

    if (jsValue->isString()) {
        std::string value = jsValue->toString();

        switch (_key) {
            case StyleParamKey::outline_style:
            case StyleParamKey::repeat_group:
            case StyleParamKey::sprite:
            case StyleParamKey::sprite_default:
            case StyleParamKey::style:
            case StyleParamKey::text_align:
            case StyleParamKey::text_repeat_group:
            case StyleParamKey::text_source:
            case StyleParamKey::text_source_left:
            case StyleParamKey::text_source_right:
            case StyleParamKey::text_transform:
            case StyleParamKey::texture:
                _val = value;
                break;
            case StyleParamKey::color:
            case StyleParamKey::outline_color:
            case StyleParamKey::text_font_fill:
            case StyleParamKey::text_font_stroke_color: {
                Color result;
                if (StyleParam::parseColor(value, result)) {
                    _val = result.abgr;
                } else {
                    LOGW("Invalid color value: %s", value.c_str());
                }
                break;
            }
            default:
                _val = StyleParam::parseString(_key, value);
                break;
        }

    } else if (jsValue->isBoolean()) {
        bool value = jsValue->toBool();

        switch (_key) {
            case StyleParamKey::interactive:
            case StyleParamKey::text_interactive:
            case StyleParamKey::visible:
                _val = value;
                break;
            case StyleParamKey::extrude:
                _val = value ? glm::vec2(NAN, NAN) : glm::vec2(0.0f, 0.0f);
                break;
            default:
                break;
        }

    } else if (jsValue->isArray()) {
        auto len = jsValue->getLength();

        switch (_key) {
            case StyleParamKey::extrude: {
                if (len != 2) {
                    LOGW("Wrong array size for extrusion: '%d'.", len);
                    break;
                }

                double v1 = jsValue->getValueAtIndex(0)->toDouble();
                double v2 = jsValue->getValueAtIndex(1)->toDouble();

                _val = glm::vec2(v1, v2);
                break;
            }
            case StyleParamKey::color:
            case StyleParamKey::outline_color:
            case StyleParamKey::text_font_fill:
            case StyleParamKey::text_font_stroke_color: {
                if (len < 3 || len > 4) {
                    LOGW("Wrong array size for color: '%d'.", len);
                    break;
                }
                double r = jsValue->getValueAtIndex(0)->toDouble();
                double g = jsValue->getValueAtIndex(1)->toDouble();
                double b = jsValue->getValueAtIndex(2)->toDouble();
                double a = 1.0;
                if (len == 4) {
                    a = jsValue->getValueAtIndex(3)->toDouble();
                }
                _val = ColorF(r, g, b, a).toColor().abgr;
                break;
            }
            default:
                break;
        }
    } else if (jsValue->isNumber()) {
        double number = jsValue->toDouble();
        if (std::isnan(number)) {
            LOGD("duk evaluates JS method to NAN.\n");
        }
        switch (_key) {
            case StyleParamKey::text_source:
            case StyleParamKey::text_source_left:
            case StyleParamKey::text_source_right:
                _val = doubleToString(number);
                break;
            case StyleParamKey::extrude:
                _val = glm::vec2(0.f, number);
                break;
            case StyleParamKey::placement_spacing: {
                _val = StyleParam::Width{static_cast<float>(number), Unit::pixel};
                break;
            }
            case StyleParamKey::width:
            case StyleParamKey::outline_width: {
                // TODO more efficient way to return pixels.
                // atm this only works by return value as string
                _val = StyleParam::Width{static_cast<float>(number)};
                break;
            }
            case StyleParamKey::angle:
            case StyleParamKey::text_font_stroke_width:
            case StyleParamKey::placement_min_length_ratio: {
                _val = static_cast<float>(number);
                break;
            }
            case StyleParamKey::size: {
                StyleParam::SizeValue vec;
                vec.x.value = static_cast<float>(number);
                _val = vec;
                break;
            }
            case StyleParamKey::order:
            case StyleParamKey::outline_order:
            case StyleParamKey::priority:
            case StyleParamKey::color:
            case StyleParamKey::outline_color:
            case StyleParamKey::text_font_fill:
            case StyleParamKey::text_font_stroke_color: {
                _val = static_cast<uint32_t>(number);
                break;
            }
            default:
                break;
        }
    } else if (jsValue->isUndefined()) {
        // Explicitly set value as 'undefined'. This is important for some styling rules.
        _val = Undefined();
    } else {
        LOGW("Unhandled return type from Javascript style function for %d.", _key);
    }

    DUMP("parseStyleResult\n");

    return !_val.is<none_type>();
}

} // namespace Tangram
<commit_msg>Clean up control flow in StyleContext<commit_after>#include "scene/styleContext.h"

#include "data/propertyItem.h"
#include "data/tileData.h"
#include "log.h"
#include "platform.h"
#include "scene/filters.h"
#include "scene/scene.h"
#include "util/mapProjection.h"
#include "util/builders.h"
#include "util/yamlUtil.h"

#define DUMP(...) // do { logMsg(__VA_ARGS__); duk_dump_context_stderr(m_ctx); } while(0)
#define DBG(...) do { logMsg(__VA_ARGS__); duk_dump_context_stderr(m_ctx); } while(0)

namespace Tangram {

static const std::string key_geom("$geometry");
static const std::string key_zoom("$zoom");

static const std::vector<std::string> s_geometryStrings = {
    "", // unknown
    "point",
    "line",
    "polygon",
};

StyleContext::StyleContext() {
    m_jsContext = createJavaScriptContext();
}

// Convert a scalar node to a boolean, double, or string (in that order)
// and for the first conversion that works, push it to the top of the JS stack.
JSValue pushYamlScalarAsJsPrimitive(JavaScriptScope& jsScope, const YAML::Node& node) {
    bool booleanValue = false;
    double numberValue = 0.;
    if (YamlUtil::getBool(node, booleanValue)) {
        return jsScope.newBoolean(booleanValue);
    } else if (YamlUtil::getDouble(node, numberValue)) {
        return jsScope.newNumber(numberValue);
    } else {
        return jsScope.newString(node.Scalar());
    }
}

JSValue pushYamlScalarAsJsFunctionOrString(JavaScriptScope& jsScope, const YAML::Node& node) {
    auto value = jsScope.newFunction(node.Scalar());
    if (value) {
        return value;
    }
    return jsScope.newString(node.Scalar());
}

JSValue StyleContext::parseSceneGlobals(JavaScriptScope& jsScope, const YAML::Node& node) {
    switch(node.Type()) {
    case YAML::NodeType::Scalar: {
        auto& scalar = node.Scalar();
        if (scalar.compare(0, 8, "function") == 0) {
            return pushYamlScalarAsJsFunctionOrString(jsScope, node);
        }
        return pushYamlScalarAsJsPrimitive(jsScope, node);
    }
    case YAML::NodeType::Sequence: {
        auto jsArray = jsScope.newArray();
        for (size_t i = 0; i < node.size(); i++) {
            jsArray->setValueAtIndex(i, parseSceneGlobals(jsScope, node[i]));
        }
        return jsArray;
    }
    case YAML::NodeType::Map: {
        auto jsObject = jsScope.newObject();
        for (const auto& entry : node) {
            if (!entry.first.IsScalar()) {
                continue; // Can't put non-scalar keys in JS objects.
            }
            jsObject->setValueForProperty(entry.first.Scalar(), parseSceneGlobals(jsScope, entry.second));
        }
        return jsObject;
    }
    default:
        return jsScope.newNull();
    }
}

void StyleContext::setSceneGlobals(const YAML::Node& sceneGlobals) {

    if (!sceneGlobals) { return; }

    JavaScriptScope jsScope(*m_jsContext);

    auto jsValue = parseSceneGlobals(jsScope, sceneGlobals);

    m_jsContext->setGlobalValue("global", std::move(jsValue));
}

void StyleContext::initFunctions(const Scene& _scene) {

    if (_scene.id == m_sceneId) {
        return;
    }
    m_sceneId = _scene.id;

    setSceneGlobals(_scene.config()["global"]);
    setFunctions(_scene.functions());
}

bool StyleContext::setFunctions(const std::vector<std::string>& _functions) {
    uint32_t id = 0;
    bool error = false;
    for (auto& function : _functions) {
        id = m_jsContext->addFunction(function, error);
    }

    m_functionCount = id;

    DUMP("setFunctions\n");
    return !error;
}

bool StyleContext::addFunction(const std::string& _function) {
    bool error = false;
    m_jsContext->addFunction(_function, error);
    m_functionCount++;
    return !error;
}

void StyleContext::setFeature(const Feature& _feature) {

    m_feature = &_feature;

    if (m_keywordGeom != m_feature->geometryType) {
        setKeyword(key_geom, s_geometryStrings[m_feature->geometryType]);
        m_keywordGeom = m_feature->geometryType;
    }

    m_jsContext->setCurrentFeature(&_feature);
}

void StyleContext::setKeywordZoom(int _zoom) {
    if (m_keywordZoom != _zoom) {
        setKeyword(key_zoom, _zoom);
        m_keywordZoom = _zoom;
    }
}

void StyleContext::setKeyword(const std::string& _key, Value _val) {
    auto keywordKey = Filter::keywordType(_key);
    if (keywordKey == FilterKeyword::undefined) {
        LOG("Undefined Keyword: %s", _key.c_str());
        return;
    }

    // Unset shortcuts in case setKeyword was not called by
    // the helper functions above.
    if (_key == key_zoom) { m_keywordZoom = -1; }
    if (_key == key_geom) { m_keywordGeom = -1; }

    Value& entry = m_keywords[static_cast<uint8_t>(keywordKey)];
    if (entry == _val) { return; }

    {
        JavaScriptScope jsScope(*m_jsContext);
        JSValue value;
        if (_val.is<std::string>()) {
            value = jsScope.newString(_val.get<std::string>());
        } else if (_val.is<double>()) {
            value = jsScope.newNumber(_val.get<double>());
        }
        m_jsContext->setGlobalValue(_key, std::move(value));
    }

    entry = std::move(_val);
}

float StyleContext::getPixelAreaScale() {
    // scale the filter value with pixelsPerMeter
    // used with `px2` area filtering
    double metersPerPixel = MapProjection::EARTH_CIRCUMFERENCE_METERS * exp2(-m_keywordZoom) / MapProjection::tileSize();
    return metersPerPixel * metersPerPixel;
}

const Value& StyleContext::getKeyword(const std::string& _key) const {
    return getKeyword(Filter::keywordType(_key));
}

void StyleContext::clear() {
    m_jsContext->setCurrentFeature(nullptr);
}

bool StyleContext::evalFilter(FunctionID _id) {
    bool result = m_jsContext->evaluateBooleanFunction(_id);
    return result;
}

bool StyleContext::evalStyle(FunctionID _id, StyleParamKey _key, StyleParam::Value& _val) {
    _val = none_type{};

    JavaScriptScope jsScope(*m_jsContext);
    auto jsValue = jsScope.getFunctionResult(_id);
    if (!jsValue) {
        return false;
    }

    if (jsValue->isString()) {
        std::string value = jsValue->toString();

        switch (_key) {
            case StyleParamKey::outline_style:
            case StyleParamKey::repeat_group:
            case StyleParamKey::sprite:
            case StyleParamKey::sprite_default:
            case StyleParamKey::style:
            case StyleParamKey::text_align:
            case StyleParamKey::text_repeat_group:
            case StyleParamKey::text_source:
            case StyleParamKey::text_source_left:
            case StyleParamKey::text_source_right:
            case StyleParamKey::text_transform:
            case StyleParamKey::texture:
                _val = value;
                break;
            case StyleParamKey::color:
            case StyleParamKey::outline_color:
            case StyleParamKey::text_font_fill:
            case StyleParamKey::text_font_stroke_color: {
                Color result;
                if (StyleParam::parseColor(value, result)) {
                    _val = result.abgr;
                } else {
                    LOGW("Invalid color value: %s", value.c_str());
                }
                break;
            }
            default:
                _val = StyleParam::parseString(_key, value);
                break;
        }

    } else if (jsValue->isBoolean()) {
        bool value = jsValue->toBool();

        switch (_key) {
            case StyleParamKey::interactive:
            case StyleParamKey::text_interactive:
            case StyleParamKey::visible:
                _val = value;
                break;
            case StyleParamKey::extrude:
                _val = value ? glm::vec2(NAN, NAN) : glm::vec2(0.0f, 0.0f);
                break;
            default:
                break;
        }

    } else if (jsValue->isArray()) {
        auto len = jsValue->getLength();

        switch (_key) {
            case StyleParamKey::extrude: {
                if (len != 2) {
                    LOGW("Wrong array size for extrusion: '%d'.", len);
                    break;
                }

                double v1 = jsValue->getValueAtIndex(0)->toDouble();
                double v2 = jsValue->getValueAtIndex(1)->toDouble();

                _val = glm::vec2(v1, v2);
                break;
            }
            case StyleParamKey::color:
            case StyleParamKey::outline_color:
            case StyleParamKey::text_font_fill:
            case StyleParamKey::text_font_stroke_color: {
                if (len < 3 || len > 4) {
                    LOGW("Wrong array size for color: '%d'.", len);
                    break;
                }
                double r = jsValue->getValueAtIndex(0)->toDouble();
                double g = jsValue->getValueAtIndex(1)->toDouble();
                double b = jsValue->getValueAtIndex(2)->toDouble();
                double a = 1.0;
                if (len == 4) {
                    a = jsValue->getValueAtIndex(3)->toDouble();
                }
                _val = ColorF(r, g, b, a).toColor().abgr;
                break;
            }
            default:
                break;
        }
    } else if (jsValue->isNumber()) {
        double number = jsValue->toDouble();
        if (std::isnan(number)) {
            LOGD("duk evaluates JS method to NAN.\n");
        }
        switch (_key) {
            case StyleParamKey::text_source:
            case StyleParamKey::text_source_left:
            case StyleParamKey::text_source_right:
                _val = doubleToString(number);
                break;
            case StyleParamKey::extrude:
                _val = glm::vec2(0.f, number);
                break;
            case StyleParamKey::placement_spacing: {
                _val = StyleParam::Width{static_cast<float>(number), Unit::pixel};
                break;
            }
            case StyleParamKey::width:
            case StyleParamKey::outline_width: {
                // TODO more efficient way to return pixels.
                // atm this only works by return value as string
                _val = StyleParam::Width{static_cast<float>(number)};
                break;
            }
            case StyleParamKey::angle:
            case StyleParamKey::text_font_stroke_width:
            case StyleParamKey::placement_min_length_ratio: {
                _val = static_cast<float>(number);
                break;
            }
            case StyleParamKey::size: {
                StyleParam::SizeValue vec;
                vec.x.value = static_cast<float>(number);
                _val = vec;
                break;
            }
            case StyleParamKey::order:
            case StyleParamKey::outline_order:
            case StyleParamKey::priority:
            case StyleParamKey::color:
            case StyleParamKey::outline_color:
            case StyleParamKey::text_font_fill:
            case StyleParamKey::text_font_stroke_color: {
                _val = static_cast<uint32_t>(number);
                break;
            }
            default:
                break;
        }
    } else if (jsValue->isUndefined()) {
        // Explicitly set value as 'undefined'. This is important for some styling rules.
        _val = Undefined();
    } else {
        LOGW("Unhandled return type from Javascript style function for %d.", _key);
    }

    DUMP("parseStyleResult\n");

    return !_val.is<none_type>();
}

} // namespace Tangram
<|endoftext|>


<commit_before>#ifndef HUBODATA_HPP
#define HUBODATA_HPP

extern "C" {
#include "hubo_sensor_c.h"
}

#include <vector>
#include <string>
#include <map>
#include <iostream>
#include <stdlib.h>
#include "hubo_sensor_stream.hpp"

namespace HuboState {

typedef std::vector<hubo_joint_state_t> JointStateArray;
typedef std::vector<hubo_imu_state_t> ImuStateArray;
typedef std::vector<hubo_ft_state_t> ForceTorqueStateArray;

inline size_t get_data_component_count(const hubo_data* data)
{
    if(NULL == data)
        return 0;

    if(hubo_data_header_check(data) != HUBO_DATA_OKAY)
        return 0;

    const hubo_data_header_t* header = (hubo_data_header_t*)data;
    return header->array_size;
}

template<class DataClass>
size_t predict_data_size(size_t array_size)
{
    return sizeof(hubo_data_header_t) + sizeof(DataClass)*array_size;
}

template<class DataClass>
size_t get_data_size(const hubo_data* data)
{
    if(NULL == data)
        return 0;

    if(hubo_data_header_check(data) != HUBO_DATA_OKAY)
        return 0;

    return predict_data_size<DataClass>(get_data_component_count(data));
}

template<class DataClass>
hubo_data* initialize_data(size_t array_size)
{
    hubo_data* new_data = (hubo_data*)malloc(predict_data_size<DataClass>(array_size));

    hubo_data_header_t header;
    strcpy(header.code, HUBO_DATA_HEADER_CODE);
    header.array_size = array_size;
    header.time = 0;

    memcpy(new_data, &header, sizeof(hubo_data_header_t));

    return new_data;
}

inline hubo_data_error_t set_data_timestamp(hubo_data* data, double time)
{
    if(NULL == data)
        return HUBO_DATA_NULL;

    if(hubo_data_header_check(data) == HUBO_DATA_OKAY)
    {
        hubo_data_header_t* header = (hubo_data_header_t*)data;
        header->time = time;

        return HUBO_DATA_OKAY;
    }
    else
    {
        return HUBO_DATA_MALFORMED_HEADER;
    }

    return HUBO_DATA_IMPOSSIBLE;
}

inline double get_data_timestamp(hubo_data* data)
{
    if(NULL == data)
        return HUBO_DATA_NULL;

    if(hubo_data_header_check(data) == HUBO_DATA_OKAY)
    {
        hubo_data_header_t* header = (hubo_data_header_t*)data;
        return header->time;
    }
    else
    {
        std::cout << "Requesting timestamp of hubo_data with malformed header!" << std::endl;
        return -1;
    }

    return HUBO_DATA_IMPOSSIBLE;
}

template<class DataClass>
DataClass* get_data_component(hubo_data* data, size_t index)
{
    if(NULL == data)
        return NULL;

    if(hubo_data_header_check(data) == HUBO_DATA_OKAY)
    {
        const hubo_data_header_t* header = (hubo_data_header_t*)data;
        if(index < header->array_size)
        {
            return (DataClass*)(data
                    + sizeof(hubo_data_header_t)
                    + sizeof(DataClass)*index);
        }
        else
        {
            return NULL;
        }
    }
    else
    {
        return NULL;
    }

    return NULL;
}

template<class DataClass>
hubo_data_error_t set_data_component(hubo_data* data,
                               const DataClass& component,
                               size_t index)
{
    if(hubo_data_header_check(data) == HUBO_DATA_OKAY)
    {
        const hubo_data_header_t* header = (hubo_data_header_t*)data;
        if(index < header->array_size)
        {
            DataClass* data_location = get_data_component<DataClass>(data,index);
            if(data_location != NULL)
            {
                memcpy(data_location, &component, sizeof(DataClass));
                return HUBO_DATA_OKAY;
            }
            else
            {
                return HUBO_DATA_IMPOSSIBLE;
            }
        }
        else
        {
            return HUBO_DATA_OUT_OF_BOUNDS;
        }
    }
    else
    {
        return HUBO_DATA_MALFORMED_HEADER;
    }

    return HUBO_DATA_IMPOSSIBLE;
}

template<class DataClass>
std::vector<DataClass> get_vector_from_data(hubo_data* data)
{
    std::vector<DataClass> data_vector;
    size_t components = get_data_component_count(data);
    data_vector.reserve(components);
    for(size_t i=0; i<components; ++i)
    {
        data_vector.push_back(*get_data_component<DataClass>(data, i));
    }

    return data_vector;
}

typedef std::map<std::string, size_t> NameMap;

template<class DataClass>
class HuboData
{
public:

    HuboData()
    {
        _construction();
    }

    HuboData(const HuboData& copy)
    {
        _construction();

        if(copy.is_initialized())
        {
            _deep_copy_data(copy);
        }
    }

    HuboData& operator=(const HuboData& copy)
    {
        if(copy.is_initialized())
        {
            _deep_copy_data(copy);
        }
    }

    DataClass& operator[](size_t index)
    {
        if(!_check_initialized("[] array member access"))
        {
            return _dummy_member;
        }

        DataClass* result = get_data_component<DataClass>(_raw_data, index);
        if(NULL == result)
        {
            if(index == (size_t)(-1))
            {
                std::cout << "You have requested an InvalidIndex for channel '"
                          << _channel_name << "'.\n Requested: " << index
                          << ", Data Count: " << get_data_component_count(_raw_data) << std::endl;
            }
            else
            {
                std::cout << "You have requested an out of bounds data member for channel '"
                         << _channel_name << "'.\n Requested: " << index
                         << ", Data Count: " << get_data_component_count(_raw_data) << std::endl;
            }
        }

        return *result;
    }

    const DataClass& const_entry(size_t index) const
    {
        if(!_check_initialized("const_entry member access"))
        {
            return _dummy_member;
        }

        DataClass* result = get_data_component<DataClass>(_raw_data, index);
        if(NULL == result)
        {
            if(index == (size_t)(-1))
            {
                std::cout << "You have requested an InvalidIndex for channel '"
                          << _channel_name << "'.\n Requested: " << index
                          << ", Data Count: " << get_data_component_count(_raw_data) << std::endl;
            }
            else
            {
                std::cout << "You have requested an out of bounds data member for channel '"
                         << _channel_name << "'.\n Requested: " << index
                         << ", Data Count: " << get_data_component_count(_raw_data) << std::endl;
            }
            return _dummy_member;
        }

        return *result;
    }

    DataClass& operator[](const std::string& name)
    {
        NameMap::iterator it = _mapping.find(name);
        if(it == _mapping.end())
        {
            std::cout << "You have requested a data member which does not exist for channel '"
                         << "', Requested: '" << name << "'" << std::endl;
            return _dummy_member;
        }

        return (*this)[it->second];
    }

    bool initialize(const std::vector<std::string>& names, const std::string& channel_name)
    {
        free(_raw_data);
        _raw_data = initialize_data<DataClass>(names.size());

        _mapping.clear();
        _names.clear();
        for(size_t i=0; i<names.size(); ++i)
        {
            NameMap::iterator it = _mapping.find(names[i]);
            if(it == _mapping.end())
            {
                _mapping[names[i]] = i;
            }
            else
            {
                std::cout << "You have a repeated data member name ('" << names[i] << "')\n"
                            << " -- Already exists as entry #" << it->second << "\n"
                            << " -- Attempted to assign it to entry #" << i << std::endl;
                _mapping.clear();
                return false;
            }
        }
        _names = names;

        _channel_name = channel_name;
        ach_status_t r = ach_open(&_channel, channel_name.c_str(), NULL);
        if( ACH_OK == r )
        {
            _initialized = true;
            return true;
        }

        _initialized = false;

        std::cout << "Failed to open channel '" << _channel_name << "': "
                     << ach_result_to_string(r) << std::endl;

        return false;
    }

    bool receive_data(double timeout_seconds = 0)
    {
        if(!_check_initialized("receive_data"))
            return ACH_ENOENT;

        size_t fs;
        struct timespec wait_time;
        clock_gettime( ACH_DEFAULT_CLOCK, &wait_time );
        int nano_wait = wait_time.tv_nsec + (int)(timeout_seconds*1E9);
        wait_time.tv_sec += (int)(nano_wait/1E9);
        wait_time.tv_nsec = (int)(nano_wait%((int)1E9));
        ach_status_t r = ach_get(&_channel, _raw_data,
                                 get_data_size<DataClass>(_raw_data),
                                 &fs, &wait_time, ACH_O_LAST | ACH_O_WAIT);

        if( ACH_TIMEOUT == r )
        {
            if(verbose)
            {
                std::cout << "Ach channel '" << _channel_name << "' timed out!" << std::endl;
            }
            return false;
        }

        if(fs != get_data_size<DataClass>(_raw_data))
        {
            std::cout << "Framesize mismatch: " << fs << " received, "
                      << get_data_size<DataClass>(_raw_data) << " expected!" << std::endl;
        }

        if( ACH_OK == r || ACH_STALE_FRAMES == r || ACH_MISSED_FRAME == r )
        {
            if(verbose)
            {
                std::cout << "Ach result for channel '" << _channel_name << "': "
                             << ach_result_to_string(r) << std::endl;
            }
            return true;
        }
        else
        {
            std::cout << "Unexpected ach_get result for channel '" << _channel_name <<"': "
                      << ach_result_to_string(r) << std::endl;
            return false;
        }

        return false;
    }

    bool send_data(double timestamp)
    {
        if(!_check_initialized("send_data"))
            return false;

        set_data_timestamp(_raw_data, timestamp);

        ach_status_t r = ach_put(&_channel, _raw_data, get_data_size<DataClass>(_raw_data));

        if(ACH_OK == r)
            return true;

        std::cout << "Unexpected ach_put result for channel '" << _channel_name << "': "
                     << ach_result_to_string(r) << std::endl;
        return false;
    }

    std::vector<DataClass> get_data(bool refresh = false)
    {
        if(!_check_initialized("get_data"))
        {
            std::vector<DataClass> empty;
            return empty;
        }

        if(refresh)
            receive_data(0);

        return get_vector_from_data<DataClass>(_raw_data);
    }

    const std::string& get_entry_name(size_t i) const
    {
        if( i < array_count() )
            return _names[i];
        else
            return _dummy_string;
    }

    double get_time() const
    {
        return get_data_timestamp(_raw_data);
    }

    bool set_data(const std::vector<DataClass>& copy)
    {
        if(!_check_initialized("set_data"))
            return false;

        if(copy.size() != get_data_component_count(_raw_data))
        {
            std::cout << "set_data mismatch for channel '" << _channel_name
                      << "'! Input size: " << copy.size() << ", Actual data size: "
                      << get_data_component_count(_raw_data) << std::endl;
            return false;
        }

        for(size_t i=0; i<copy.size(); ++i)
        {
            (*this)[i] = copy[i];
        }

        return true;
    }

    ~HuboData()
    {
        free(_raw_data);
    }

    std::string get_channel_name() const { return _channel_name; }
    bool is_initialized() const { return _initialized; }

    size_t array_count() const
    {
        return get_data_component_count(_raw_data);
    }

    bool verbose;
    hubo_data* _raw_data;

protected:

    void _construction()
    {
        _raw_data = NULL;
        memset(&_channel, 0, sizeof(ach_channel_t));
        _initialized = false;
        verbose = false;
        memset(&_dummy_member, 0, sizeof(DataClass));
        _dummy_string = "dummy";
    }

    void _deep_copy_data(const HuboData& copy)
    {
        initialize(get_data_size<DataClass>(copy._raw_data),
                   copy._channel_name);
        memcpy(_raw_data, copy._raw_data, get_data_size<DataClass>(copy._raw_data));
    }

    bool _initialized;
    bool _check_initialized(std::string operation = "an operation") const
    {
        if(_initialized)
            return true;
        else
        {
            std::cout << "Illegal: Attempting to perform '" << operation << "' on a HuboData object "
                         << "before it has been initialized!" << std::endl;
            return false;
        }
    }

    NameMap _mapping;
    std::vector<std::string> _names;
    std::string _channel_name;
    ach_channel_t _channel;
    DataClass _dummy_member;
    std::string _dummy_string;

};

} // namespace HuboState

template<class DataClass>
std::ostream& operator<<(std::ostream& stream, const HuboState::HuboData<DataClass>& data)
{
    if(!data.is_initialized())
    {
        stream << "Uninitialized HuboData" << std::endl;
        return stream;
    }

    stream << "Channel: '" << data.get_channel_name() << "', timestamp: " << data.get_time()
              << ", entry count: " << data.array_count() << "\n";

    size_t s = 0;
    for(size_t i=0; i<data.array_count(); ++i)
    {
        const std::string& entry_name = data.get_entry_name(i);
        if(entry_name.size() > s)
            s = entry_name.size();
    }

    for(size_t i=0; i<data.array_count(); ++i)
    {
        stream.width(s);
        stream << data.get_entry_name(i) << " | " << data.const_entry(i) << "\n";
    }

    return stream;
}

#endif // HUBODATA_HPP
<commit_msg>better warning messages<commit_after>#ifndef HUBODATA_HPP
#define HUBODATA_HPP

extern "C" {
#include "hubo_sensor_c.h"
}

#include <vector>
#include <string>
#include <map>
#include <iostream>
#include <stdlib.h>
#include "hubo_sensor_stream.hpp"

namespace HuboState {

typedef std::vector<hubo_joint_state_t> JointStateArray;
typedef std::vector<hubo_imu_state_t> ImuStateArray;
typedef std::vector<hubo_ft_state_t> ForceTorqueStateArray;

inline size_t get_data_component_count(const hubo_data* data)
{
    if(NULL == data)
        return 0;

    if(hubo_data_header_check(data) != HUBO_DATA_OKAY)
        return 0;

    const hubo_data_header_t* header = (hubo_data_header_t*)data;
    return header->array_size;
}

template<class DataClass>
size_t predict_data_size(size_t array_size)
{
    return sizeof(hubo_data_header_t) + sizeof(DataClass)*array_size;
}

template<class DataClass>
size_t get_data_size(const hubo_data* data)
{
    if(NULL == data)
        return 0;

    if(hubo_data_header_check(data) != HUBO_DATA_OKAY)
        return 0;

    return predict_data_size<DataClass>(get_data_component_count(data));
}

template<class DataClass>
hubo_data* initialize_data(size_t array_size)
{
    hubo_data* new_data = (hubo_data*)malloc(predict_data_size<DataClass>(array_size));

    hubo_data_header_t header;
    strcpy(header.code, HUBO_DATA_HEADER_CODE);
    header.array_size = array_size;
    header.time = 0;

    memcpy(new_data, &header, sizeof(hubo_data_header_t));

    return new_data;
}

inline hubo_data_error_t set_data_timestamp(hubo_data* data, double time)
{
    if(NULL == data)
        return HUBO_DATA_NULL;

    if(hubo_data_header_check(data) == HUBO_DATA_OKAY)
    {
        hubo_data_header_t* header = (hubo_data_header_t*)data;
        header->time = time;

        return HUBO_DATA_OKAY;
    }
    else
    {
        return HUBO_DATA_MALFORMED_HEADER;
    }

    return HUBO_DATA_IMPOSSIBLE;
}

inline double get_data_timestamp(hubo_data* data)
{
    if(NULL == data)
        return HUBO_DATA_NULL;

    if(hubo_data_header_check(data) == HUBO_DATA_OKAY)
    {
        hubo_data_header_t* header = (hubo_data_header_t*)data;
        return header->time;
    }
    else
    {
        std::cout << "Requesting timestamp of hubo_data with malformed header!" << std::endl;
        return -1;
    }

    return HUBO_DATA_IMPOSSIBLE;
}

template<class DataClass>
DataClass* get_data_component(hubo_data* data, size_t index)
{
    if(NULL == data)
        return NULL;

    if(hubo_data_header_check(data) == HUBO_DATA_OKAY)
    {
        const hubo_data_header_t* header = (hubo_data_header_t*)data;
        if(index < header->array_size)
        {
            return (DataClass*)(data
                    + sizeof(hubo_data_header_t)
                    + sizeof(DataClass)*index);
        }
        else
        {
            return NULL;
        }
    }
    else
    {
        return NULL;
    }

    return NULL;
}

template<class DataClass>
hubo_data_error_t set_data_component(hubo_data* data,
                               const DataClass& component,
                               size_t index)
{
    if(hubo_data_header_check(data) == HUBO_DATA_OKAY)
    {
        const hubo_data_header_t* header = (hubo_data_header_t*)data;
        if(index < header->array_size)
        {
            DataClass* data_location = get_data_component<DataClass>(data,index);
            if(data_location != NULL)
            {
                memcpy(data_location, &component, sizeof(DataClass));
                return HUBO_DATA_OKAY;
            }
            else
            {
                return HUBO_DATA_IMPOSSIBLE;
            }
        }
        else
        {
            return HUBO_DATA_OUT_OF_BOUNDS;
        }
    }
    else
    {
        return HUBO_DATA_MALFORMED_HEADER;
    }

    return HUBO_DATA_IMPOSSIBLE;
}

template<class DataClass>
std::vector<DataClass> get_vector_from_data(hubo_data* data)
{
    std::vector<DataClass> data_vector;
    size_t components = get_data_component_count(data);
    data_vector.reserve(components);
    for(size_t i=0; i<components; ++i)
    {
        data_vector.push_back(*get_data_component<DataClass>(data, i));
    }

    return data_vector;
}

typedef std::map<std::string, size_t> NameMap;

template<class DataClass>
class HuboData
{
public:

    HuboData()
    {
        _construction();
    }

    HuboData(const HuboData& copy)
    {
        _construction();

        if(copy.is_initialized())
        {
            _deep_copy_data(copy);
        }
    }

    HuboData& operator=(const HuboData& copy)
    {
        if(copy.is_initialized())
        {
            _deep_copy_data(copy);
        }
    }

    DataClass& operator[](size_t index)
    {
        if(!_check_initialized("[] array member access"))
        {
            return _dummy_member;
        }

        DataClass* result = get_data_component<DataClass>(_raw_data, index);
        if(NULL == result)
        {
            if(index == (size_t)(-1))
            {
                std::cout << "You have requested an InvalidIndex for channel '"
                          << _channel_name << "'.\n"
                          << "(Data Count: " << get_data_component_count(_raw_data)
                          << ")" << std::endl;
            }
            else
            {
                std::cout << "You have requested an out of bounds data member for channel '"
                         << _channel_name << "'.\n Requested: " << index
                         << ", Data Count: " << get_data_component_count(_raw_data) << std::endl;
            }
        }

        return *result;
    }

    const DataClass& const_entry(size_t index) const
    {
        if(!_check_initialized("const_entry member access"))
        {
            return _dummy_member;
        }

        DataClass* result = get_data_component<DataClass>(_raw_data, index);
        if(NULL == result)
        {
            if(index == (size_t)(-1))
            {
                std::cout << "You have requested an InvalidIndex for channel '"
                          << _channel_name << "'.\n"
                          << "(Data Count: " << get_data_component_count(_raw_data)
                          << ")" << std::endl;
            }
            else
            {
                std::cout << "You have requested an out of bounds data member for channel '"
                         << _channel_name << "'.\n Requested: " << index
                         << ", Data Count: " << get_data_component_count(_raw_data) << std::endl;
            }
            return _dummy_member;
        }

        return *result;
    }

    DataClass& operator[](const std::string& name)
    {
        NameMap::iterator it = _mapping.find(name);
        if(it == _mapping.end())
        {
            std::cout << "You have requested a data member which does not exist for channel '"
                         << "', Requested: '" << name << "'" << std::endl;
            return _dummy_member;
        }

        return (*this)[it->second];
    }

    bool initialize(const std::vector<std::string>& names, const std::string& channel_name)
    {
        free(_raw_data);
        _raw_data = initialize_data<DataClass>(names.size());

        _mapping.clear();
        _names.clear();
        for(size_t i=0; i<names.size(); ++i)
        {
            NameMap::iterator it = _mapping.find(names[i]);
            if(it == _mapping.end())
            {
                _mapping[names[i]] = i;
            }
            else
            {
                std::cout << "You have a repeated data member name ('" << names[i] << "')\n"
                            << " -- Already exists as entry #" << it->second << "\n"
                            << " -- Attempted to assign it to entry #" << i << std::endl;
                _mapping.clear();
                return false;
            }
        }
        _names = names;

        _channel_name = channel_name;
        ach_status_t r = ach_open(&_channel, channel_name.c_str(), NULL);
        if( ACH_OK == r )
        {
            _initialized = true;
            return true;
        }

        _initialized = false;

        std::cout << "Failed to open channel '" << _channel_name << "': "
                     << ach_result_to_string(r) << std::endl;

        return false;
    }

    bool receive_data(double timeout_seconds = 0)
    {
        if(!_check_initialized("receive_data"))
            return ACH_ENOENT;

        size_t fs;
        struct timespec wait_time;
        clock_gettime( ACH_DEFAULT_CLOCK, &wait_time );
        int nano_wait = wait_time.tv_nsec + (int)(timeout_seconds*1E9);
        wait_time.tv_sec += (int)(nano_wait/1E9);
        wait_time.tv_nsec = (int)(nano_wait%((int)1E9));
        ach_status_t r = ach_get(&_channel, _raw_data,
                                 get_data_size<DataClass>(_raw_data),
                                 &fs, &wait_time, ACH_O_LAST | ACH_O_WAIT);

        if( ACH_TIMEOUT == r )
        {
            if(verbose)
            {
                std::cout << "Ach channel '" << _channel_name << "' timed out!" << std::endl;
            }
            return false;
        }

        if(fs != get_data_size<DataClass>(_raw_data))
        {
            std::cout << "Framesize mismatch: " << fs << " received, "
                      << get_data_size<DataClass>(_raw_data) << " expected!" << std::endl;
        }

        if( ACH_OK == r || ACH_STALE_FRAMES == r || ACH_MISSED_FRAME == r )
        {
            if(verbose)
            {
                std::cout << "Ach result for channel '" << _channel_name << "': "
                             << ach_result_to_string(r) << std::endl;
            }
            return true;
        }
        else
        {
            std::cout << "Unexpected ach_get result for channel '" << _channel_name <<"': "
                      << ach_result_to_string(r) << std::endl;
            return false;
        }

        return false;
    }

    bool send_data(double timestamp)
    {
        if(!_check_initialized("send_data"))
            return false;

        set_data_timestamp(_raw_data, timestamp);

        ach_status_t r = ach_put(&_channel, _raw_data, get_data_size<DataClass>(_raw_data));

        if(ACH_OK == r)
            return true;

        std::cout << "Unexpected ach_put result for channel '" << _channel_name << "': "
                     << ach_result_to_string(r) << std::endl;
        return false;
    }

    std::vector<DataClass> get_data(bool refresh = false)
    {
        if(!_check_initialized("get_data"))
        {
            std::vector<DataClass> empty;
            return empty;
        }

        if(refresh)
            receive_data(0);

        return get_vector_from_data<DataClass>(_raw_data);
    }

    const std::string& get_entry_name(size_t i) const
    {
        if( i < array_count() )
            return _names[i];
        else
            return _dummy_string;
    }

    double get_time() const
    {
        return get_data_timestamp(_raw_data);
    }

    bool set_data(const std::vector<DataClass>& copy)
    {
        if(!_check_initialized("set_data"))
            return false;

        if(copy.size() != get_data_component_count(_raw_data))
        {
            std::cout << "set_data mismatch for channel '" << _channel_name
                      << "'! Input size: " << copy.size() << ", Actual data size: "
                      << get_data_component_count(_raw_data) << std::endl;
            return false;
        }

        for(size_t i=0; i<copy.size(); ++i)
        {
            (*this)[i] = copy[i];
        }

        return true;
    }

    ~HuboData()
    {
        free(_raw_data);
    }

    std::string get_channel_name() const { return _channel_name; }
    bool is_initialized() const { return _initialized; }

    size_t array_count() const
    {
        return get_data_component_count(_raw_data);
    }

    bool verbose;
    hubo_data* _raw_data;

protected:

    void _construction()
    {
        _raw_data = NULL;
        memset(&_channel, 0, sizeof(ach_channel_t));
        _initialized = false;
        verbose = false;
        memset(&_dummy_member, 0, sizeof(DataClass));
        _dummy_string = "dummy";
    }

    void _deep_copy_data(const HuboData& copy)
    {
        initialize(get_data_size<DataClass>(copy._raw_data),
                   copy._channel_name);
        memcpy(_raw_data, copy._raw_data, get_data_size<DataClass>(copy._raw_data));
    }

    bool _initialized;
    bool _check_initialized(std::string operation = "an operation") const
    {
        if(_initialized)
            return true;
        else
        {
            std::cout << "Illegal: Attempting to perform '" << operation << "' on a HuboData object "
                         << "before it has been initialized!" << std::endl;
            return false;
        }
    }

    NameMap _mapping;
    std::vector<std::string> _names;
    std::string _channel_name;
    ach_channel_t _channel;
    DataClass _dummy_member;
    std::string _dummy_string;

};

} // namespace HuboState

template<class DataClass>
std::ostream& operator<<(std::ostream& stream, const HuboState::HuboData<DataClass>& data)
{
    if(!data.is_initialized())
    {
        stream << "Uninitialized HuboData" << std::endl;
        return stream;
    }

    stream << "Channel: '" << data.get_channel_name() << "', timestamp: " << data.get_time()
              << ", entry count: " << data.array_count() << "\n";

    size_t s = 0;
    for(size_t i=0; i<data.array_count(); ++i)
    {
        const std::string& entry_name = data.get_entry_name(i);
        if(entry_name.size() > s)
            s = entry_name.size();
    }

    for(size_t i=0; i<data.array_count(); ++i)
    {
        stream.width(s);
        stream << data.get_entry_name(i) << " | " << data.const_entry(i) << "\n";
    }

    return stream;
}

#endif // HUBODATA_HPP
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qcontactabstractrequest.h"
#include "qcontactabstractrequest_p.h"
#include "qcontactmanager.h"
#include "qcontactmanager_p.h"
#include "qcontactmanagerengine.h"
#include <QCoreApplication>

/*!
 * \class QContactAbstractRequest
 * \brief Allows a client to asynchronously request some functionality of a particular QContactManager.
 *
 * This class provides a mechanism for asynchronous requests to be made of a manager if it supports them.
 */

/*!
 * \enum QContactAbstractRequest::RequestType
 * Enumerates the various possible types of asynchronous requests
 * \value InvalidRequest An invalid request
 * \value ContactFetchRequest A request to fetch a list of contacts
 * \value ContactLocalIdFetchRequest A request to fetch a list of local contact ids
 * \value ContactRemoveRequest A request to remove a list of contacts
 * \value ContactSaveRequest A request to save a list of contacts
 * \value DetailDefinitionFetchRequest A request to fetch a collection of detail definitions
 * \value DetailDefinitionRemoveRequest A request to remove a list of detail definitions
 * \value DetailDefinitionSaveRequest A request to save a list of detail definitions
 * \value RelationshipFetchRequest A request to fetch relationships between contacts
 * \value RelationshipRemoveRequest A request to remove any relationships which match the request criteria
 * \value RelationshipSaveRequest A request to save a list of relationships
 */

/*!
 * \enum QContactAbstractRequest::Status
 * Enumerates the various states that a request may be in at any given time
 * \value Inactive Operation not yet started
 * \value Active Operation started, not yet finished
 * \value Cancelling Operation started then cancelled, not yet finished
 * \value Cancelled Operation is finished due to cancellation
 * \value Finished Operation successfully completed
 */

/*!
 * \fn QContactAbstractRequest::QContactAbstractRequest()
 * Constructs a new, invalid asynchronous request
 */

/*! Constructs a new request from the given request data \a otherd */
QContactAbstractRequest::QContactAbstractRequest(QContactAbstractRequestPrivate* otherd)
    : d_ptr(otherd)
{
}

/*! Cleans up the memory used by this request */
QContactAbstractRequest::~QContactAbstractRequest()
{
    if (d_ptr) {
        QContactManagerEngine *engine = QContactManagerData::engine(d_ptr->m_manager);
        if (engine) {
            engine->requestDestroyed(this);
            QCoreApplication::processEvents();
        }

        delete d_ptr;
        QContactAbstractRequestPrivate* deleted = d_ptr;
        d_ptr = 0;
        delete deleted;
    }
}

/*!
 * Returns true if the request is pending, processing or cancelling; otherwise, returns false.
 *
 * \sa status()
 */
bool QContactAbstractRequest::isActive() const
{
    return (d_ptr->m_status == QContactAbstractRequest::Active
            || d_ptr->m_status == QContactAbstractRequest::Cancelling);
}

/*!
 * Returns true if the request is finished or cancelled; otherwise, returns false.
 *
 * \sa status()
 */
bool QContactAbstractRequest::isFinished() const
{
    return (d_ptr->m_status == QContactAbstractRequest::Finished
            || d_ptr->m_status == QContactAbstractRequest::Cancelled);
}

/*! Returns the overall error of the most recent asynchronous operation */
QContactManager::Error QContactAbstractRequest::error() const
{
    QMutexLocker locker(&d_ptr->m_mutex);
    return d_ptr->m_error;
}

/*! Returns the list of errors which occurred during the most recent asynchronous operation.  Each individual error in the list corresponds to a result in the result list. */
QList<QContactManager::Error> QContactAbstractRequest::errors() const
{
    QMutexLocker locker(&d_ptr->m_mutex);
    return d_ptr->m_errors;
}

/*!
 * Returns the type of this asynchronous request
 */
QContactAbstractRequest::RequestType QContactAbstractRequest::type() const
{
    QMutexLocker locker(&d_ptr->m_mutex);
    return d_ptr->type();
}

/*!
 * Returns the current status of the request.
 *
 * \sa isFinished(), isActive()
 */
QContactAbstractRequest::Status QContactAbstractRequest::status() const
{
    return d_ptr->m_status;
}

/*! Returns a pointer to the manager of which this request instance requests operations */
QContactManager* QContactAbstractRequest::manager() const
{
    QMutexLocker locker(&d_ptr->m_mutex);
    return d_ptr->m_manager;
}

/*! Sets the manager of which this request instance requests operations to \a manager */
void QContactAbstractRequest::setManager(QContactManager* manager)
{
    QMutexLocker locker(&d_ptr->m_mutex);
    QContactManagerEngine *engine = QContactManagerData::engine(manager);
    if (engine) {
        d_ptr->m_manager = manager;
    }
}

/*! Attempts to start the request.  Returns false if the request is not in the \c QContactAbstractRequest::Inactive, \c QContactAbstractRequest::Finished or \c QContactAbstractRequest::Cancelled states,
    or if the request was unable to be performed by the manager engine; otherwise returns true. */
bool QContactAbstractRequest::start()
{
    QContactManagerEngine *engine = QContactManagerData::engine(d_ptr->m_manager);
    if (engine && !isActive()) {
        return engine->startRequest(this);
    }

    return false; // unable to start operation; another operation already in progress or no engine.
}

/*! Attempts to cancel the request.  Returns false if the request is not in the \c QContactAbstractRequest::Active state,
    or if the request is unable to be cancelled by the manager engine; otherwise returns true. */
bool QContactAbstractRequest::cancel()
{
    QContactManagerEngine *engine = QContactManagerData::engine(d_ptr->m_manager);
    if (engine && status() == QContactAbstractRequest::Active) {
        return engine->cancelRequest(this);
    }

    return false; // unable to cancel operation; not in progress or no engine.
}

/*! Blocks until the request has been completed by the manager engine, or until \a msecs milliseconds has elapsed.
    If \a msecs is zero, this function will block indefinitely.
    Returns true if the request was cancelled or completed successfully within the given period, otherwise false. */
bool QContactAbstractRequest::waitForFinished(int msecs)
{
    bool ret = false;
    QContactManagerEngine *engine = QContactManagerData::engine(d_ptr->m_manager);
    if (engine && isActive()) {
        ret = engine->waitForRequestFinished(this, msecs);
        QCoreApplication::processEvents();
    }

    return ret; // unable to wait for operation; not in progress or no engine.
}

/*! Blocks until the manager engine signals that more partial results are available for the request, or until \a msecs milliseconds has elapsed.
    If \a msecs is zero, this function will block indefinitely.
    Returns true if the request was cancelled or more partial results were made available within the given period, otherwise false. */
bool QContactAbstractRequest::waitForProgress(int msecs)
{
    bool ret = false;
    QContactManagerEngine *engine = QContactManagerData::engine(d_ptr->m_manager);
    if (engine) {
        ret = engine->waitForRequestProgress(this, msecs);
        QCoreApplication::processEvents();
    }

    return ret; // unable to wait for operation; not in progress or no engine.
}

bool QContactAbstractRequestPrivate::stateTransition(QContactAbstractRequest* req, QContactManager::Error error, QList<QContactManager::Error>& errors, QContactAbstractRequest::Status newStatus, bool deleteFinishedRequest)
{
    QMutexLocker locker(&m_mutex);
    QContactManagerEngine *engine = QContactManagerData::engine(m_manager);
    if (!engine)
        return false;
    //XXX more state transition check
    if ((m_status == QContactAbstractRequest::Cancelling && newStatus == QContactAbstractRequest::Finished) ||
        (m_status == QContactAbstractRequest::Cancelling && newStatus == QContactAbstractRequest::Active) ||
        (m_status == QContactAbstractRequest::Inactive && newStatus != QContactAbstractRequest::Active) ||
        ((m_status == QContactAbstractRequest::Finished || m_status == QContactAbstractRequest::Cancelled) && newStatus != QContactAbstractRequest::Active)) {
            return false;
    }

    m_error = error;
    m_errors = errors;
    m_status = newStatus;
    if ((newStatus == QContactAbstractRequest::Finished || newStatus == QContactAbstractRequest::Cancelled) && deleteFinishedRequest) {
        engine->requestDestroyed(req);
    }
    return true;
}
<commit_msg>Fix double free error<commit_after>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qcontactabstractrequest.h"
#include "qcontactabstractrequest_p.h"
#include "qcontactmanager.h"
#include "qcontactmanager_p.h"
#include "qcontactmanagerengine.h"
#include <QCoreApplication>

/*!
 * \class QContactAbstractRequest
 * \brief Allows a client to asynchronously request some functionality of a particular QContactManager.
 *
 * This class provides a mechanism for asynchronous requests to be made of a manager if it supports them.
 */

/*!
 * \enum QContactAbstractRequest::RequestType
 * Enumerates the various possible types of asynchronous requests
 * \value InvalidRequest An invalid request
 * \value ContactFetchRequest A request to fetch a list of contacts
 * \value ContactLocalIdFetchRequest A request to fetch a list of local contact ids
 * \value ContactRemoveRequest A request to remove a list of contacts
 * \value ContactSaveRequest A request to save a list of contacts
 * \value DetailDefinitionFetchRequest A request to fetch a collection of detail definitions
 * \value DetailDefinitionRemoveRequest A request to remove a list of detail definitions
 * \value DetailDefinitionSaveRequest A request to save a list of detail definitions
 * \value RelationshipFetchRequest A request to fetch relationships between contacts
 * \value RelationshipRemoveRequest A request to remove any relationships which match the request criteria
 * \value RelationshipSaveRequest A request to save a list of relationships
 */

/*!
 * \enum QContactAbstractRequest::Status
 * Enumerates the various states that a request may be in at any given time
 * \value Inactive Operation not yet started
 * \value Active Operation started, not yet finished
 * \value Cancelling Operation started then cancelled, not yet finished
 * \value Cancelled Operation is finished due to cancellation
 * \value Finished Operation successfully completed
 */

/*!
 * \fn QContactAbstractRequest::QContactAbstractRequest()
 * Constructs a new, invalid asynchronous request
 */

/*! Constructs a new request from the given request data \a otherd */
QContactAbstractRequest::QContactAbstractRequest(QContactAbstractRequestPrivate* otherd)
    : d_ptr(otherd)
{
}

/*! Cleans up the memory used by this request */
QContactAbstractRequest::~QContactAbstractRequest()
{
    if (d_ptr) {
        QContactManagerEngine *engine = QContactManagerData::engine(d_ptr->m_manager);
        if (engine) {
            engine->requestDestroyed(this);
            QCoreApplication::processEvents();
        }

        delete d_ptr;
        d_ptr = 0;
    }
}

/*!
 * Returns true if the request is pending, processing or cancelling; otherwise, returns false.
 *
 * \sa status()
 */
bool QContactAbstractRequest::isActive() const
{
    return (d_ptr->m_status == QContactAbstractRequest::Active
            || d_ptr->m_status == QContactAbstractRequest::Cancelling);
}

/*!
 * Returns true if the request is finished or cancelled; otherwise, returns false.
 *
 * \sa status()
 */
bool QContactAbstractRequest::isFinished() const
{
    return (d_ptr->m_status == QContactAbstractRequest::Finished
            || d_ptr->m_status == QContactAbstractRequest::Cancelled);
}

/*! Returns the overall error of the most recent asynchronous operation */
QContactManager::Error QContactAbstractRequest::error() const
{
    QMutexLocker locker(&d_ptr->m_mutex);
    return d_ptr->m_error;
}

/*! Returns the list of errors which occurred during the most recent asynchronous operation.  Each individual error in the list corresponds to a result in the result list. */
QList<QContactManager::Error> QContactAbstractRequest::errors() const
{
    QMutexLocker locker(&d_ptr->m_mutex);
    return d_ptr->m_errors;
}

/*!
 * Returns the type of this asynchronous request
 */
QContactAbstractRequest::RequestType QContactAbstractRequest::type() const
{
    QMutexLocker locker(&d_ptr->m_mutex);
    return d_ptr->type();
}

/*!
 * Returns the current status of the request.
 *
 * \sa isFinished(), isActive()
 */
QContactAbstractRequest::Status QContactAbstractRequest::status() const
{
    return d_ptr->m_status;
}

/*! Returns a pointer to the manager of which this request instance requests operations */
QContactManager* QContactAbstractRequest::manager() const
{
    QMutexLocker locker(&d_ptr->m_mutex);
    return d_ptr->m_manager;
}

/*! Sets the manager of which this request instance requests operations to \a manager */
void QContactAbstractRequest::setManager(QContactManager* manager)
{
    QMutexLocker locker(&d_ptr->m_mutex);
    QContactManagerEngine *engine = QContactManagerData::engine(manager);
    if (engine) {
        d_ptr->m_manager = manager;
    }
}

/*! Attempts to start the request.  Returns false if the request is not in the \c QContactAbstractRequest::Inactive, \c QContactAbstractRequest::Finished or \c QContactAbstractRequest::Cancelled states,
    or if the request was unable to be performed by the manager engine; otherwise returns true. */
bool QContactAbstractRequest::start()
{
    QContactManagerEngine *engine = QContactManagerData::engine(d_ptr->m_manager);
    if (engine && !isActive()) {
        return engine->startRequest(this);
    }

    return false; // unable to start operation; another operation already in progress or no engine.
}

/*! Attempts to cancel the request.  Returns false if the request is not in the \c QContactAbstractRequest::Active state,
    or if the request is unable to be cancelled by the manager engine; otherwise returns true. */
bool QContactAbstractRequest::cancel()
{
    QContactManagerEngine *engine = QContactManagerData::engine(d_ptr->m_manager);
    if (engine && status() == QContactAbstractRequest::Active) {
        return engine->cancelRequest(this);
    }

    return false; // unable to cancel operation; not in progress or no engine.
}

/*! Blocks until the request has been completed by the manager engine, or until \a msecs milliseconds has elapsed.
    If \a msecs is zero, this function will block indefinitely.
    Returns true if the request was cancelled or completed successfully within the given period, otherwise false. */
bool QContactAbstractRequest::waitForFinished(int msecs)
{
    bool ret = false;
    QContactManagerEngine *engine = QContactManagerData::engine(d_ptr->m_manager);
    if (engine && isActive()) {
        ret = engine->waitForRequestFinished(this, msecs);
        QCoreApplication::processEvents();
    }

    return ret; // unable to wait for operation; not in progress or no engine.
}

/*! Blocks until the manager engine signals that more partial results are available for the request, or until \a msecs milliseconds has elapsed.
    If \a msecs is zero, this function will block indefinitely.
    Returns true if the request was cancelled or more partial results were made available within the given period, otherwise false. */
bool QContactAbstractRequest::waitForProgress(int msecs)
{
    bool ret = false;
    QContactManagerEngine *engine = QContactManagerData::engine(d_ptr->m_manager);
    if (engine) {
        ret = engine->waitForRequestProgress(this, msecs);
        QCoreApplication::processEvents();
    }

    return ret; // unable to wait for operation; not in progress or no engine.
}

bool QContactAbstractRequestPrivate::stateTransition(QContactAbstractRequest* req, QContactManager::Error error, QList<QContactManager::Error>& errors, QContactAbstractRequest::Status newStatus, bool deleteFinishedRequest)
{
    QMutexLocker locker(&m_mutex);
    QContactManagerEngine *engine = QContactManagerData::engine(m_manager);
    if (!engine)
        return false;
    //XXX more state transition check
    if ((m_status == QContactAbstractRequest::Cancelling && newStatus == QContactAbstractRequest::Finished) ||
        (m_status == QContactAbstractRequest::Cancelling && newStatus == QContactAbstractRequest::Active) ||
        (m_status == QContactAbstractRequest::Inactive && newStatus != QContactAbstractRequest::Active) ||
        ((m_status == QContactAbstractRequest::Finished || m_status == QContactAbstractRequest::Cancelled) && newStatus != QContactAbstractRequest::Active)) {
            return false;
    }

    m_error = error;
    m_errors = errors;
    m_status = newStatus;
    if ((newStatus == QContactAbstractRequest::Finished || newStatus == QContactAbstractRequest::Cancelled) && deleteFinishedRequest) {
        engine->requestDestroyed(req);
    }
    return true;
}
<|endoftext|>


<commit_before>#include "runtime_internal.h"
#include "HalideRuntime.h"
#include "profiler_state.h"
#include "scoped_mutex_lock.h"

// Note: The profiler thread may out-live any valid user_context, or
// be used across many different user_contexts, so nothing it calls
// can depend on the user context.

extern "C" {
// Returns the address of the global halide_profiler state
WEAK profiler_state *halide_profiler_get_state() {
    static profiler_state s;
    return &s;
}
}

namespace Halide { namespace Runtime { namespace Internal {

WEAK pipeline_stats *find_or_create_pipeline(const char *pipeline_name, int num_funcs, const char **func_names) {
    profiler_state *s = halide_profiler_get_state();

    for (pipeline_stats *p = s->pipelines; p; p = (pipeline_stats *)(p->next)) {
        // The same pipeline will deliver the same global constant string, so they can be compared by pointer.
        if (p->name == pipeline_name &&
            p->num_funcs == num_funcs) {
            return p;
        }
    }
    // Create a new pipeline stats entry.
    pipeline_stats *p = (pipeline_stats *)halide_malloc(NULL, sizeof(pipeline_stats));
    if (!p) return NULL;
    p->next = s->pipelines;
    p->name = pipeline_name;
    p->first_func_id = s->first_free_id;
    p->num_funcs = num_funcs;
    p->runs = 0;
    p->time = 0;
    p->samples = 0;
    p->funcs = (func_stats *)halide_malloc(NULL, num_funcs * sizeof(func_stats));
    if (!p->funcs) {
        halide_free(NULL, p);
        return NULL;
    }
    for (int i = 0; i < num_funcs; i++) {
        p->funcs[i].time = 0;
        p->funcs[i].name = func_names[i];
    }
    s->first_free_id += num_funcs;
    s->pipelines = p;
    return p;
}

WEAK void bill_func(profiler_state *s, int func_id, uint64_t time) {
    pipeline_stats *p_prev = NULL;
    for (pipeline_stats *p = s->pipelines; p; p = (pipeline_stats *)(p->next)) {
        if (func_id >= p->first_func_id && func_id < p->first_func_id + p->num_funcs) {
            if (p_prev) {
                // Bubble the pipeline to the top to speed up future queries.
                p_prev->next = (pipeline_stats *)(p->next);
                p->next = s->pipelines;
                s->pipelines = p;
            }
            p->funcs[func_id - p->first_func_id].time += time;
            p->time += time;
            p->samples++;
            return;
        }
        p_prev = p;
    }
    // panic!
    print(NULL)
        << "Internal error in profiler: \n"
        << "Could not find pipeline for func_id " << func_id << "\n"
        << "Pipelines:\n";
    for (pipeline_stats *p = s->pipelines; p; p = (pipeline_stats *)(p->next)) {
        print(NULL) << p->name << " : " << p->first_func_id << ", " << p->num_funcs << "\n";
    }
    error(NULL) << "Could not proceed.\n";
}

extern "C" int sched_yield();

WEAK void *sampling_profiler_thread(void *) {
    profiler_state *s = halide_profiler_get_state();

    // grab the lock
    halide_mutex_lock(&s->lock);

    while (s->current_func != please_stop) {

        uint64_t t1 = halide_current_time_ns(NULL);
        uint64_t t = t1;
        while (1) {
            uint64_t t_now = halide_current_time_ns(NULL);
            uint64_t delta = t_now - t;
            // Querying the state too frequently causes cache misses
            // in the main process every time it goes to set
            // current_func. If not much time has elapsed since we
            // last checked it, delay.
            if (delta > 100000) {
                int func = s->current_func;
                if (func == please_stop) {
                    break;
                } else if (func >= 0) {
                    // Assume all time since I was last awake is due to
                    // the currently running func.
                    bill_func(s, func, t_now - t);
                }
                t = t_now;
            }
            // Release the lock, give up my time slice, reacquire.
            halide_mutex_unlock(&s->lock);
            sched_yield();
            halide_mutex_lock(&s->lock);
        }
    }

    s->started = false;

    halide_mutex_unlock(&s->lock);
    return NULL;
}

}}}

extern "C" {

// Returns a token identifying this pipeline instance.
WEAK int halide_profiler_pipeline_start(void *user_context,
                                        const char *pipeline_name,
                                        int num_funcs,
                                        const char **func_names) {
    profiler_state *s = halide_profiler_get_state();

    ScopedMutexLock lock(&s->lock);

    if (!s->started) {
        halide_spawn_thread(user_context, sampling_profiler_thread, NULL);
        s->started = true;
    }

    pipeline_stats *p = find_or_create_pipeline(pipeline_name, num_funcs, func_names);
    if (!p) {
        // Allocating space to track the statistics failed.
        return halide_error_out_of_memory(user_context);
    }
    p->runs++;

    int tok = p->first_func_id;

    return tok;
}

WEAK void halide_profiler_report(void *user_context) {
    profiler_state *s = halide_profiler_get_state();

    char line_buf[160];
    Printer<StringStreamPrinter, sizeof(line_buf)> sstr(user_context, line_buf);

    ScopedMutexLock lock(&s->lock);

    for (pipeline_stats *p = s->pipelines; p; p = (pipeline_stats *)(p->next)) {
        float t = p->time / 1000000.0f;
        if (!p->runs) continue;
        sstr.clear();
        sstr << p->name
             << "  total time: " << t << " ms"
             << "  samples: " << p->samples
             << "  runs: " << p->runs
             << "  time per run: " << t / p->runs << " ms\n";
        halide_print(user_context, sstr.str());
        if (p->time) {
            for (int i = 0; i < p->num_funcs; i++) {
                sstr.clear();
                func_stats *fs = p->funcs + i;
                sstr << "  " << fs->name << ": ";
                while (sstr.size() < 25) sstr << " ";

                float ft = fs->time / (p->runs * 1000000.0f);
                sstr << ft << "ms";
                while (sstr.size() < 40) sstr << " ";

                int percent = fs->time / (p->time / 100);
                sstr << "(" << percent << "%)\n";

                halide_print(user_context, sstr.str());
            }
        }
    }
}

WEAK void halide_profiler_reset() {
    profiler_state *s = halide_profiler_get_state();

    ScopedMutexLock lock(&s->lock);

    while (s->pipelines) {
        pipeline_stats *p = s->pipelines;
        s->pipelines = (pipeline_stats *)(p->next);
        halide_free(NULL, p->funcs);
        halide_free(NULL, p);
    }
    s->first_free_id = 0;
}

namespace {
__attribute__((destructor))
WEAK void halide_profiler_shutdown() {
    profiler_state *s = halide_profiler_get_state();
    s->current_func = please_stop;
    do {
        // Memory barrier.
        __sync_synchronize(&s->started,
                           &s->current_func);
    } while (s->started);
    s->current_func = outside_of_halide;

    // print results
    halide_profiler_report(NULL);

    // free memory
    halide_profiler_reset();
}
}

WEAK void halide_profiler_pipeline_end(void *user_context, void *state) {
    ((profiler_state *)state)->current_func = outside_of_halide;
}

}
<commit_msg>Give the sampling profiler an explicit sleep<commit_after>#include "runtime_internal.h"
#include "HalideRuntime.h"
#include "profiler_state.h"
#include "scoped_mutex_lock.h"

// Note: The profiler thread may out-live any valid user_context, or
// be used across many different user_contexts, so nothing it calls
// can depend on the user context.

extern "C" {
// Returns the address of the global halide_profiler state
WEAK profiler_state *halide_profiler_get_state() {
    static profiler_state s;
    return &s;
}
}

namespace Halide { namespace Runtime { namespace Internal {

WEAK pipeline_stats *find_or_create_pipeline(const char *pipeline_name, int num_funcs, const char **func_names) {
    profiler_state *s = halide_profiler_get_state();

    for (pipeline_stats *p = s->pipelines; p; p = (pipeline_stats *)(p->next)) {
        // The same pipeline will deliver the same global constant string, so they can be compared by pointer.
        if (p->name == pipeline_name &&
            p->num_funcs == num_funcs) {
            return p;
        }
    }
    // Create a new pipeline stats entry.
    pipeline_stats *p = (pipeline_stats *)halide_malloc(NULL, sizeof(pipeline_stats));
    if (!p) return NULL;
    p->next = s->pipelines;
    p->name = pipeline_name;
    p->first_func_id = s->first_free_id;
    p->num_funcs = num_funcs;
    p->runs = 0;
    p->time = 0;
    p->samples = 0;
    p->funcs = (func_stats *)halide_malloc(NULL, num_funcs * sizeof(func_stats));
    if (!p->funcs) {
        halide_free(NULL, p);
        return NULL;
    }
    for (int i = 0; i < num_funcs; i++) {
        p->funcs[i].time = 0;
        p->funcs[i].name = func_names[i];
    }
    s->first_free_id += num_funcs;
    s->pipelines = p;
    return p;
}

WEAK void bill_func(profiler_state *s, int func_id, uint64_t time) {
    pipeline_stats *p_prev = NULL;
    for (pipeline_stats *p = s->pipelines; p; p = (pipeline_stats *)(p->next)) {
        if (func_id >= p->first_func_id && func_id < p->first_func_id + p->num_funcs) {
            if (p_prev) {
                // Bubble the pipeline to the top to speed up future queries.
                p_prev->next = (pipeline_stats *)(p->next);
                p->next = s->pipelines;
                s->pipelines = p;
            }
            p->funcs[func_id - p->first_func_id].time += time;
            p->time += time;
            p->samples++;
            return;
        }
        p_prev = p;
    }
    // panic!
    print(NULL)
        << "Internal error in profiler: \n"
        << "Could not find pipeline for func_id " << func_id << "\n"
        << "Pipelines:\n";
    for (pipeline_stats *p = s->pipelines; p; p = (pipeline_stats *)(p->next)) {
        print(NULL) << p->name << " : " << p->first_func_id << ", " << p->num_funcs << "\n";
    }
    error(NULL) << "Could not proceed.\n";
}

extern "C" void usleep(int);

WEAK void *sampling_profiler_thread(void *) {
    profiler_state *s = halide_profiler_get_state();

    // grab the lock
    halide_mutex_lock(&s->lock);

    while (s->current_func != please_stop) {

        uint64_t t1 = halide_current_time_ns(NULL);
        uint64_t t = t1;
        while (1) {
            uint64_t t_now = halide_current_time_ns(NULL);
            int func = s->current_func;
            if (func == please_stop) {
                break;
            } else if (func >= 0) {
               // Assume all time since I was last awake is due to
               // the currently running func.
               bill_func(s, func, t_now - t);
            }
            t = t_now;

            // Release the lock, sleep, reacquire.
            halide_mutex_unlock(&s->lock);
            usleep(1000);
            halide_mutex_lock(&s->lock);
        }
    }

    s->started = false;

    halide_mutex_unlock(&s->lock);
    return NULL;
}

}}}

extern "C" {

// Returns a token identifying this pipeline instance.
WEAK int halide_profiler_pipeline_start(void *user_context,
                                        const char *pipeline_name,
                                        int num_funcs,
                                        const char **func_names) {
    profiler_state *s = halide_profiler_get_state();

    ScopedMutexLock lock(&s->lock);

    if (!s->started) {
        halide_spawn_thread(user_context, sampling_profiler_thread, NULL);
        s->started = true;
    }

    pipeline_stats *p = find_or_create_pipeline(pipeline_name, num_funcs, func_names);
    if (!p) {
        // Allocating space to track the statistics failed.
        return halide_error_out_of_memory(user_context);
    }
    p->runs++;

    int tok = p->first_func_id;

    return tok;
}

WEAK void halide_profiler_report(void *user_context) {
    profiler_state *s = halide_profiler_get_state();

    char line_buf[160];
    Printer<StringStreamPrinter, sizeof(line_buf)> sstr(user_context, line_buf);

    ScopedMutexLock lock(&s->lock);

    for (pipeline_stats *p = s->pipelines; p; p = (pipeline_stats *)(p->next)) {
        float t = p->time / 1000000.0f;
        if (!p->runs) continue;
        sstr.clear();
        sstr << p->name
             << "  total time: " << t << " ms"
             << "  samples: " << p->samples
             << "  runs: " << p->runs
             << "  time per run: " << t / p->runs << " ms\n";
        halide_print(user_context, sstr.str());
        if (p->time) {
            for (int i = 0; i < p->num_funcs; i++) {
                sstr.clear();
                func_stats *fs = p->funcs + i;
                sstr << "  " << fs->name << ": ";
                while (sstr.size() < 25) sstr << " ";

                float ft = fs->time / (p->runs * 1000000.0f);
                sstr << ft << "ms";
                while (sstr.size() < 40) sstr << " ";

                int percent = fs->time / (p->time / 100);
                sstr << "(" << percent << "%)\n";

                halide_print(user_context, sstr.str());
            }
        }
    }
}

WEAK void halide_profiler_reset() {
    profiler_state *s = halide_profiler_get_state();

    ScopedMutexLock lock(&s->lock);

    while (s->pipelines) {
        pipeline_stats *p = s->pipelines;
        s->pipelines = (pipeline_stats *)(p->next);
        halide_free(NULL, p->funcs);
        halide_free(NULL, p);
    }
    s->first_free_id = 0;
}

namespace {
__attribute__((destructor))
WEAK void halide_profiler_shutdown() {
    profiler_state *s = halide_profiler_get_state();
    s->current_func = please_stop;
    do {
        // Memory barrier.
        __sync_synchronize(&s->started,
                           &s->current_func);
    } while (s->started);
    s->current_func = outside_of_halide;

    // print results
    halide_profiler_report(NULL);

    // free memory
    halide_profiler_reset();
}
}

WEAK void halide_profiler_pipeline_end(void *user_context, void *state) {
    ((profiler_state *)state)->current_func = outside_of_halide;
}

}
<|endoftext|>


<commit_before>/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
 *
 *  Data Differential YATL (i.e. libtest)  library
 *
 *  Copyright (C) 2012 Data Differential, http://datadifferential.com/
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are
 *  met:
 *
 *      * Redistributions of source code must retain the above copyright
 *  notice, this list of conditions and the following disclaimer.
 *
 *      * Redistributions in binary form must reproduce the above
 *  copyright notice, this list of conditions and the following disclaimer
 *  in the documentation and/or other materials provided with the
 *  distribution.
 *
 *      * The names of its contributors may not be used to endorse or
 *  promote products derived from this software without specific prior
 *  written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include "gear_config.h"
#include <libtest/common.h>

namespace libtest {

bool jenkins_is_caller(void)
{
  if (bool(getenv("JENKINS_HOME")))
  {
    return true;
  }

  return false;
}

bool valgrind_is_caller(void)
{
  if (bool(getenv("TESTS_ENVIRONMENT")) and strstr(getenv("TESTS_ENVIRONMENT"), "valgrind"))
  {
    return true;
  }

  return false;
}

bool gdb_is_caller(void)
{
  if (bool(getenv("TESTS_ENVIRONMENT")) and strstr(getenv("TESTS_ENVIRONMENT"), "gdb"))
  {
    return true;
  }

  return false;
}

bool helgrind_is_caller(void)
{
  if (bool(getenv("TESTS_ENVIRONMENT")) and strstr(getenv("TESTS_ENVIRONMENT"), "helgrind"))
  {
    return true;
  }

  return false;
}

bool _in_valgrind(const char*, int, const char*)
{
  if (valgrind_is_caller())
  {
    return false;
  }

  return false;
}

} // namespace libtest
<commit_msg>Fix value.<commit_after>/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
 *
 *  Data Differential YATL (i.e. libtest)  library
 *
 *  Copyright (C) 2012 Data Differential, http://datadifferential.com/
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are
 *  met:
 *
 *      * Redistributions of source code must retain the above copyright
 *  notice, this list of conditions and the following disclaimer.
 *
 *      * Redistributions in binary form must reproduce the above
 *  copyright notice, this list of conditions and the following disclaimer
 *  in the documentation and/or other materials provided with the
 *  distribution.
 *
 *      * The names of its contributors may not be used to endorse or
 *  promote products derived from this software without specific prior
 *  written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include "gear_config.h"
#include <libtest/common.h>

namespace libtest {

bool jenkins_is_caller(void)
{
  if (bool(getenv("JENKINS_HOME")))
  {
    return true;
  }

  return false;
}

bool valgrind_is_caller(void)
{
  if (bool(getenv("TESTS_ENVIRONMENT")) and strstr(getenv("TESTS_ENVIRONMENT"), "valgrind"))
  {
    return true;
  }

  return false;
}

bool gdb_is_caller(void)
{
  if (bool(getenv("TESTS_ENVIRONMENT")) and strstr(getenv("TESTS_ENVIRONMENT"), "gdb"))
  {
    return true;
  }

  return false;
}

bool helgrind_is_caller(void)
{
  if (bool(getenv("TESTS_ENVIRONMENT")) and strstr(getenv("TESTS_ENVIRONMENT"), "helgrind"))
  {
    return true;
  }

  return false;
}

bool _in_valgrind(const char*, int, const char*)
{
  if (valgrind_is_caller())
  {
    return true;
  }

  return false;
}

} // namespace libtest
<|endoftext|>


<commit_before>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_toolkit.hxx"
#include "toolkit/awt/xthrobber.hxx"
#include "toolkit/helper/property.hxx"
#include <toolkit/helper/tkresmgr.hxx>

#ifndef _TOOLKIT_AWT_XTHROBBER_HRC_
#include "xthrobber.hrc"
#endif
#include <tools/debug.hxx>
#include <vcl/fixed.hxx>
#include <vcl/timer.hxx>
#include <vcl/throbber.hxx>

//........................................................................
namespace toolkit
{
//........................................................................

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

    //====================================================================
    //= XThrobber
    //====================================================================
    DBG_NAME( XThrobber )

    //--------------------------------------------------------------------
    XThrobber::XThrobber()
    {
        DBG_CTOR( XThrobber, NULL );
    }

    //--------------------------------------------------------------------
    XThrobber::~XThrobber()
    {
        DBG_DTOR( XThrobber, NULL );
    }

    //--------------------------------------------------------------------
    void SAL_CALL XThrobber::start() throw ( uno::RuntimeException )
    {
        ::vos::OGuard aGuard( GetMutex() );
        Throbber* pThrobber( dynamic_cast< Throbber* >( GetWindow() ) );
        if ( pThrobber != NULL)
            pThrobber->start();
    }

    //--------------------------------------------------------------------
    void SAL_CALL XThrobber::stop() throw ( uno::RuntimeException )
    {
        ::vos::OGuard aGuard( GetMutex() );
        Throbber* pThrobber( dynamic_cast< Throbber* >( GetWindow() ) );
        if ( pThrobber != NULL)
            pThrobber->stop();
    }

    //--------------------------------------------------------------------
    void XThrobber::SetWindow( Window* pWindow )
    {
        XThrobber_Base::SetWindow( pWindow );
        InitImageList();
    }

    //--------------------------------------------------------------------
    void SAL_CALL XThrobber::InitImageList()
        throw( uno::RuntimeException )
    {
        ::vos::OGuard aGuard( GetMutex() );

        Throbber* pThrobber( dynamic_cast< Throbber* >( GetWindow() ) );
        if ( pThrobber != NULL)
            return;

        uno::Sequence< uno::Reference< graphic::XGraphic > > aImageList(12);
        sal_uInt16 nIconIdStart = RID_TK_ICON_THROBBER_START;

        if ( pThrobber->GetSettings().GetStyleSettings().GetHighContrastMode() )
            nIconIdStart = RID_TK_HC_ICON_THROBBER_START;

        for ( sal_uInt16 i=0; i<12; i++ )
        {
            Image aImage = TK_RES_IMAGE( nIconIdStart + i );
            aImageList[i] = aImage.GetXGraphic();
        }

        pThrobber->setImageList( aImageList );
    }

//........................................................................
}   // namespace toolkit
//........................................................................
<commit_msg>dba34c: merge after pulling latest changes from CWS dba34b<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_toolkit.hxx"
#include "toolkit/awt/xthrobber.hxx"
#include "toolkit/helper/property.hxx"
#include <toolkit/helper/tkresmgr.hxx>

#ifndef _TOOLKIT_AWT_XTHROBBER_HRC_
#include "xthrobber.hrc"
#endif
#include <tools/debug.hxx>
#include <vcl/fixed.hxx>
#include <vcl/timer.hxx>
#include <vcl/throbber.hxx>

//........................................................................
namespace toolkit
{
//........................................................................

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

    //====================================================================
    //= XThrobber
    //====================================================================
    DBG_NAME( XThrobber )

    //--------------------------------------------------------------------
    XThrobber::XThrobber()
    {
        DBG_CTOR( XThrobber, NULL );
    }

    //--------------------------------------------------------------------
    XThrobber::~XThrobber()
    {
        DBG_DTOR( XThrobber, NULL );
    }

    //--------------------------------------------------------------------
    void SAL_CALL XThrobber::start() throw ( uno::RuntimeException )
    {
        ::vos::OGuard aGuard( GetMutex() );
        Throbber* pThrobber( dynamic_cast< Throbber* >( GetWindow() ) );
        if ( pThrobber != NULL)
            pThrobber->start();
    }

    //--------------------------------------------------------------------
    void SAL_CALL XThrobber::stop() throw ( uno::RuntimeException )
    {
        ::vos::OGuard aGuard( GetMutex() );
        Throbber* pThrobber( dynamic_cast< Throbber* >( GetWindow() ) );
        if ( pThrobber != NULL)
            pThrobber->stop();
    }

    //--------------------------------------------------------------------
    void XThrobber::SetWindow( Window* pWindow )
    {
        XThrobber_Base::SetWindow( pWindow );
        InitImageList();
    }

    //--------------------------------------------------------------------
    void SAL_CALL XThrobber::InitImageList()
        throw( uno::RuntimeException )
    {
        ::vos::OGuard aGuard( GetMutex() );

        Throbber* pThrobber( dynamic_cast< Throbber* >( GetWindow() ) );
        if ( pThrobber == NULL)
            return;

        uno::Sequence< uno::Reference< graphic::XGraphic > > aImageList(12);
        sal_uInt16 nIconIdStart = RID_TK_ICON_THROBBER_START;

        if ( pThrobber->GetSettings().GetStyleSettings().GetHighContrastMode() )
            nIconIdStart = RID_TK_HC_ICON_THROBBER_START;

        for ( sal_uInt16 i=0; i<12; i++ )
        {
            Image aImage = TK_RES_IMAGE( nIconIdStart + i );
            aImageList[i] = aImage.GetXGraphic();
        }

        pThrobber->setImageList( aImageList );
    }

//........................................................................
}   // namespace toolkit
//........................................................................
<|endoftext|>