<commit_before>#include "xmlbinder.h"
#include "raiden.h"
#include "paramset.h"
#include <string>
void XMLBinder::Init()
{
}

void XMLBinder::Release()
{
}

void PushInteger(ParamSet &set, const pugi::xml_node &node, const char *name = "name")
{
    const char *v_name = node.attribute(name).as_string();
    auto v = node.attribute("value").as_int();
    set.AddInt(v_name, std::unique_ptr<int[]>(new int[1]{v}), 1);
}

void PushFloat(ParamSet &set, const pugi::xml_node &node, const char *name = "name")
{
    const char *v_name = node.attribute(name).as_string();
    auto v = node.attribute("value").as_float();
    set.AddFloat(v_name, std::unique_ptr<float[]>(new float[1]{v}), 1);
}

void PushBool(ParamSet &set, const pugi::xml_node &node, const char *name = "name")
{
    const char *v_name = node.attribute(name).as_string();
    auto v = node.attribute("value").as_bool();
    set.AddBool(v_name, std::unique_ptr<bool[]>(new bool[1]{v}), 1);
}

void PushRGB(ParamSet &set, const pugi::xml_node &node, const char *name = "name")
{
    const char *v_name = node.attribute(name).as_string();
    float r = node.attribute("r").as_float();
    float g = node.attribute("g").as_float();
    float b = node.attribute("b").as_float();
    set.AddRGBSpectrum(v_name, std::unique_ptr<float[]>(new float[3]{r, g, b}), 3);
}

void PushPoint2f(ParamSet &set, const pugi::xml_node &node, const char *name = "name")
{
    const char *v_name = node.attribute(name).as_string();
    float x = node.attribute("x").as_float();
    float y = node.attribute("y").as_float();
    set.AddPoint2f(v_name, std::unique_ptr<Point2f[]>(new Point2f[1]{Point2f(x, y)}), 1);
}

void PushPoint3f(ParamSet &set, const pugi::xml_node &node, const char *name = "name")
{
    const char *v_name = node.attribute(name).as_string();
    float x = node.attribute("x").as_float();
    float y = node.attribute("y").as_float();
    float z = node.attribute("z").as_float();
    set.AddPoint3f(v_name, std::unique_ptr<Point3f[]>(new Point3f[1]{Point3f(x, y, z)}), 1);
}

void PushVector2f(ParamSet &set, const pugi::xml_node &node, const char *name = "name")
{
    const char *v_name = node.attribute(name).as_string();
    float x = node.attribute("x").as_float();
    float y = node.attribute("y").as_float();
    set.AddVector2f(v_name, std::unique_ptr<Vector2f[]>(new Vector2f[1]{Vector2f(x, y)}), 1);
}

void PushVector3f(ParamSet &set, const pugi::xml_node &node, const char *name = "name")
{
    const char *v_name = node.attribute(name).as_string();
    float x = node.attribute("x").as_float();
    float y = node.attribute("y").as_float();
    float z = node.attribute("z").as_float();
    set.AddVector3f(v_name, std::unique_ptr<Vector3f[]>(new Vector3f[1]{Vector3f(x, y, z)}), 1);
}

void PushNormal3f(ParamSet &set, const pugi::xml_node &node, const char *name = "name")
{
    const char *v_name = node.attribute(name).as_string();
    float x = node.attribute("x").as_float();
    float y = node.attribute("y").as_float();
    float z = node.attribute("z").as_float();
    set.AddNormal3f(v_name, std::unique_ptr<Normal3f[]>(new Normal3f[1]{Normal3f(x, y, z)}), 1);
}

void PushIntegetArray(ParamSet &set, const pugi::xml_node &node, const char *name = "name")
{
    const char *v_name = node.attribute(name).as_string();
    const char *v_value = node.child_value();
    char *t_value = (char *)malloc(strlen(v_value));
    memcpy(t_value, v_value, strlen(v_value));
    std::vector<int> splits;
    char *p = strtok(t_value, ",");
    while (p != nullptr)
    {
        splits.push_back(atoi(p));
        p = strtok(nullptr, ",");
    }
    std::unique_ptr<int[]> ints(new int[splits.size()]);
    for (uint32_t i = 0; i < splits.size(); ++i)
    {
        ints[i] = splits[i];
    }
    set.AddInt(v_value, std::move(ints), splits.size());
}

void PushFloatArray(ParamSet &set, const pugi::xml_node &node, const char *name = "name")
{
    const char *v_name = node.attribute(name).as_string();
    const char *v_value = node.child_value();
    char *t_value = (char *)malloc(strlen(v_value));
    memcpy(t_value, v_value, strlen(v_value));
    std::vector<float> splits;
    char *p = strtok(t_value, ",");
    while (p != nullptr)
    {
        splits.push_back(atof(p));
        p = strtok(nullptr, ",");
    }
    std::unique_ptr<float[]> floats(new float[splits.size()]);
    for (uint32_t i = 0; i < splits.size(); ++i)
    {
        floats[i] = splits[i];
    }
    set.AddFloat(v_value, std::move(floats), splits.size());
}

void PushTexture(ParamSet &set, const pugi::xml_node &node, const char *name = "name")
{
    const char *v_name = node.attribute(name).as_string();
    set.AddTexture(name, v_name);
}

void PushString(ParamSet &set, const pugi::xml_node &node, const char *name = "name")
{
    const char *v_name = node.attribute(name).as_string();
    set.AddString(name, std::unique_ptr<std::string[]>(new std::string[1]{v_name}), 1);
}

void XMLBinder::PharseChildNodeParamSet(ParamSet &set, const pugi::xml_node &root) const
{

    for (pugi::xml_node node = root.first_child(); node; node = node.next_sibling())
    {
        const char *name = node.name();
        if (strcmp(name, "integer") == 0)
        {
            //单个整数
            PushInteger(set, node);
        }
        else if (strcmp(name, "float") == 0)
        {
            //单个浮点数
            PushFloat(set, node);
        }
        else if (strcmp(name, "bool") == 0)
        {
            //单个布尔值
            PushBool(set, node);
        }
        else if (strcmp(name, "rgb") == 0)
        {
            PushRGB(set, node);
        }
        else if (strcmp(name, "point2f") == 0)
        {
            PushPoint2f(set, node);
        }
        else if (strcmp(name, "point3f") == 0)
        {
            PushPoint3f(set, node);
        }
        else if (strcmp(name, "vector2f") == 0)
        {
            PushVector2f(set, node);
        }
        else if (strcmp(name, "vector3f") == 0)
        {
            PushVector3f(set, node);
        }
        else if (strcmp(name, "normal3f") == 0)
        {
            PushNormal3f(set, node);
        }
        else if (strcmp(name, "integer_array") == 0)
        {
            PushIntegetArray(set, node);
        }
        else if (strcmp(name, "float_array") == 0)
        {
            PushFloatArray(set, node);
        }
        else if (strcmp(name, "texture") == 0)
        {
            PushTexture(set, node);
        }
        else if (strcmp(name, "string") == 0)
        {
            //字符串
            PushString(set, node);
        }
    }
}

void XMLBinder::ExecScript(const char *fileName)
{
    pugi::xml_parse_result result = _doc.load_file(fileName);
    LInfo << "Loading XML state:" << result.description();
    auto root = _doc.first_child();
    if (strcmp(root.name(), "Scene") == 0)
    {
        //开始解析scene层
        LInfo << "->scene node";
        for (pugi::xml_node node = root.first_child(); node; node = node.next_sibling())
        {
            const char *name = node.name();
            if (strcmp(name, "WorldBegin") == 0)
            {
                raidenWorldBegin();
            }
            else if (strcmp(name, "WorldEnd") == 0)
            {
                raidenWorldEnd();
            }
            else if (strcmp(name, "Translate") == 0)
            {
                float dx = node.attribute("x").as_float();
                float dy = node.attribute("y").as_float();
                float dz = node.attribute("z").as_float();
                raidenTranslate(dx, dy, dz);
            }
            else if (strcmp(name, "Rotate") == 0)
            {
                float angle = node.attribute("angle").as_float();
                float dx = node.attribute("x").as_float();
                float dy = node.attribute("y").as_float();
                float dz = node.attribute("z").as_float();
                raidenRotate(angle, dx, dy, dz);
            }
            else if (strcmp(name, "Scale") == 0)
            {
                float dx = node.attribute("x").as_float();
                float dy = node.attribute("y").as_float();
                float dz = node.attribute("z").as_float();
                raidenScale(dx, dy, dz);
            }
            else if (strcmp(name, "CoordinateSystem") == 0)
            {
                ParamSet params;
                auto frame_name = node.attribute("name").as_string();
                raidenCoordinateSystem(frame_name);
            }
            else if (strcmp(name, "CoordSysTransform") == 0)
            {
                ParamSet params;
                auto frame_name = node.attribute("name").as_string();
                raidenCoordSysTransform(frame_name);
            }
            //TODO 和时间有关的API还没有绑定
            else if (strcmp(name, "PixelFilter") == 0)
            {
                ParamSet params;
                auto type = node.attribute("type").as_string();
                PharseChildNodeParamSet(params, node);
                raidenPixelFilter(type, params);
            }
            else if (strcmp(name, "Accelerator") == 0)
            {
                ParamSet params;
                auto type = node.attribute("type").as_string();
                PharseChildNodeParamSet(params, node);
                raidenAccelerator(type, params);
            }
            else if (strcmp(name, "Integrator") == 0)
            {
                LInfo << "-->integrator node";
                ParamSet params;
                auto type = node.attribute("type").as_string();
                PharseChildNodeParamSet(params, node);
                raidenIntegrator(type, params);
            }
            else if (strcmp(name, "Camera") == 0)
            {
                ParamSet params;
                auto type = node.attribute("type").as_string();
                PharseChildNodeParamSet(params, node);
                raidenCamera(type, params);
            }
            else if (strcmp(name, "Film") == 0)
            {
                ParamSet params;
                auto type = node.attribute("type").as_string();
                PharseChildNodeParamSet(params, node);
                raidenFilm(type, params);
            }
            else if (strcmp(name, "Sampler") == 0)
            {
                ParamSet params;
                auto type = node.attribute("type").as_string();
                PharseChildNodeParamSet(params, node);
                raidenSampler(type, params);
            }
            else if (strcmp(name, "Shape") == 0)
            {
                ParamSet params;
                auto type = node.attribute("type").as_string();
                PharseChildNodeParamSet(params, node);
                raidenShape(type, params);
            }
            else if (strcmp(name, "Texture") == 0)
            {
                ParamSet params;
                auto t_name = node.attribute("name").as_string();
                auto type = node.attribute("type").as_string();
                auto src = node.attribute("source").as_string();
                PharseChildNodeParamSet(params, node);
                raidenTexture(t_name, type, src, params);
            }
            else if (strcmp(name, "MakeNamedMaterial") == 0)
            {
                ParamSet params;
                auto t_name = node.attribute("name").as_string();
                PushString(params, node, "type");
                PharseChildNodeParamSet(params, node);
                raidenMakeNamedMaterial(t_name, params);
            }
            else if (strcmp(name, "Material") == 0)
            {
                ParamSet params;
                auto type = node.attribute("type").as_string();
                PharseChildNodeParamSet(params, node);
                raidenMaterial(type, params);
            }
            else if (strcmp(name, "NamedMaterial") == 0)
            {
                auto t_name = node.attribute("name").as_string();
                raidenNamedMaterial(t_name);
            }
            else if (strcmp(name, "TransformBegin") == 0)
            {
                raidenTransformBegin();
            }
            else if (strcmp(name, "TransformEnd") == 0)
            {
                raidenTransformEnd();
            }
            else if (strcmp(name, "LightSource") == 0)
            {
                ParamSet params;
                auto type = node.attribute("type").as_string();
                PharseChildNodeParamSet(params, node);
                raidenLightSource(type, params);
            }
            else if (strcmp(name, "AreaLightSource") == 0)
            {
                ParamSet params;
                auto type = node.attribute("type").as_string();
                PharseChildNodeParamSet(params, node);
                raidenAreaLightSource(type,params);
            }
        }
    }
    else
    {
        LWarning << "XML file must has a root node \"scene\" but \"" << root << "\" now";
    }
}<commit_msg>XML=》AttributeBegin/End<commit_after>#include "xmlbinder.h"
#include "raiden.h"
#include "paramset.h"
#include <string>
void XMLBinder::Init()
{
}

void XMLBinder::Release()
{
}

void PushInteger(ParamSet &set, const pugi::xml_node &node, const char *name = "name")
{
    const char *v_name = node.attribute(name).as_string();
    auto v = node.attribute("value").as_int();
    set.AddInt(v_name, std::unique_ptr<int[]>(new int[1]{v}), 1);
}

void PushFloat(ParamSet &set, const pugi::xml_node &node, const char *name = "name")
{
    const char *v_name = node.attribute(name).as_string();
    auto v = node.attribute("value").as_float();
    set.AddFloat(v_name, std::unique_ptr<float[]>(new float[1]{v}), 1);
}

void PushBool(ParamSet &set, const pugi::xml_node &node, const char *name = "name")
{
    const char *v_name = node.attribute(name).as_string();
    auto v = node.attribute("value").as_bool();
    set.AddBool(v_name, std::unique_ptr<bool[]>(new bool[1]{v}), 1);
}

void PushRGB(ParamSet &set, const pugi::xml_node &node, const char *name = "name")
{
    const char *v_name = node.attribute(name).as_string();
    float r = node.attribute("r").as_float();
    float g = node.attribute("g").as_float();
    float b = node.attribute("b").as_float();
    set.AddRGBSpectrum(v_name, std::unique_ptr<float[]>(new float[3]{r, g, b}), 3);
}

void PushPoint2f(ParamSet &set, const pugi::xml_node &node, const char *name = "name")
{
    const char *v_name = node.attribute(name).as_string();
    float x = node.attribute("x").as_float();
    float y = node.attribute("y").as_float();
    set.AddPoint2f(v_name, std::unique_ptr<Point2f[]>(new Point2f[1]{Point2f(x, y)}), 1);
}

void PushPoint3f(ParamSet &set, const pugi::xml_node &node, const char *name = "name")
{
    const char *v_name = node.attribute(name).as_string();
    float x = node.attribute("x").as_float();
    float y = node.attribute("y").as_float();
    float z = node.attribute("z").as_float();
    set.AddPoint3f(v_name, std::unique_ptr<Point3f[]>(new Point3f[1]{Point3f(x, y, z)}), 1);
}

void PushVector2f(ParamSet &set, const pugi::xml_node &node, const char *name = "name")
{
    const char *v_name = node.attribute(name).as_string();
    float x = node.attribute("x").as_float();
    float y = node.attribute("y").as_float();
    set.AddVector2f(v_name, std::unique_ptr<Vector2f[]>(new Vector2f[1]{Vector2f(x, y)}), 1);
}

void PushVector3f(ParamSet &set, const pugi::xml_node &node, const char *name = "name")
{
    const char *v_name = node.attribute(name).as_string();
    float x = node.attribute("x").as_float();
    float y = node.attribute("y").as_float();
    float z = node.attribute("z").as_float();
    set.AddVector3f(v_name, std::unique_ptr<Vector3f[]>(new Vector3f[1]{Vector3f(x, y, z)}), 1);
}

void PushNormal3f(ParamSet &set, const pugi::xml_node &node, const char *name = "name")
{
    const char *v_name = node.attribute(name).as_string();
    float x = node.attribute("x").as_float();
    float y = node.attribute("y").as_float();
    float z = node.attribute("z").as_float();
    set.AddNormal3f(v_name, std::unique_ptr<Normal3f[]>(new Normal3f[1]{Normal3f(x, y, z)}), 1);
}

void PushIntegetArray(ParamSet &set, const pugi::xml_node &node, const char *name = "name")
{
    const char *v_name = node.attribute(name).as_string();
    const char *v_value = node.child_value();
    char *t_value = (char *)malloc(strlen(v_value));
    memcpy(t_value, v_value, strlen(v_value));
    std::vector<int> splits;
    char *p = strtok(t_value, ",");
    while (p != nullptr)
    {
        splits.push_back(atoi(p));
        p = strtok(nullptr, ",");
    }
    std::unique_ptr<int[]> ints(new int[splits.size()]);
    for (uint32_t i = 0; i < splits.size(); ++i)
    {
        ints[i] = splits[i];
    }
    set.AddInt(v_value, std::move(ints), splits.size());
}

void PushFloatArray(ParamSet &set, const pugi::xml_node &node, const char *name = "name")
{
    const char *v_name = node.attribute(name).as_string();
    const char *v_value = node.child_value();
    char *t_value = (char *)malloc(strlen(v_value));
    memcpy(t_value, v_value, strlen(v_value));
    std::vector<float> splits;
    char *p = strtok(t_value, ",");
    while (p != nullptr)
    {
        splits.push_back(atof(p));
        p = strtok(nullptr, ",");
    }
    std::unique_ptr<float[]> floats(new float[splits.size()]);
    for (uint32_t i = 0; i < splits.size(); ++i)
    {
        floats[i] = splits[i];
    }
    set.AddFloat(v_value, std::move(floats), splits.size());
}

void PushTexture(ParamSet &set, const pugi::xml_node &node, const char *name = "name")
{
    const char *v_name = node.attribute(name).as_string();
    set.AddTexture(name, v_name);
}

void PushString(ParamSet &set, const pugi::xml_node &node, const char *name = "name")
{
    const char *v_name = node.attribute(name).as_string();
    set.AddString(name, std::unique_ptr<std::string[]>(new std::string[1]{v_name}), 1);
}

void XMLBinder::PharseChildNodeParamSet(ParamSet &set, const pugi::xml_node &root) const
{

    for (pugi::xml_node node = root.first_child(); node; node = node.next_sibling())
    {
        const char *name = node.name();
        if (strcmp(name, "integer") == 0)
        {
            //单个整数
            PushInteger(set, node);
        }
        else if (strcmp(name, "float") == 0)
        {
            //单个浮点数
            PushFloat(set, node);
        }
        else if (strcmp(name, "bool") == 0)
        {
            //单个布尔值
            PushBool(set, node);
        }
        else if (strcmp(name, "rgb") == 0)
        {
            PushRGB(set, node);
        }
        else if (strcmp(name, "point2f") == 0)
        {
            PushPoint2f(set, node);
        }
        else if (strcmp(name, "point3f") == 0)
        {
            PushPoint3f(set, node);
        }
        else if (strcmp(name, "vector2f") == 0)
        {
            PushVector2f(set, node);
        }
        else if (strcmp(name, "vector3f") == 0)
        {
            PushVector3f(set, node);
        }
        else if (strcmp(name, "normal3f") == 0)
        {
            PushNormal3f(set, node);
        }
        else if (strcmp(name, "integer_array") == 0)
        {
            PushIntegetArray(set, node);
        }
        else if (strcmp(name, "float_array") == 0)
        {
            PushFloatArray(set, node);
        }
        else if (strcmp(name, "texture") == 0)
        {
            PushTexture(set, node);
        }
        else if (strcmp(name, "string") == 0)
        {
            //字符串
            PushString(set, node);
        }
    }
}

void XMLBinder::ExecScript(const char *fileName)
{
    pugi::xml_parse_result result = _doc.load_file(fileName);
    LInfo << "Loading XML state:" << result.description();
    auto root = _doc.first_child();
    if (strcmp(root.name(), "Scene") == 0)
    {
        //开始解析scene层
        LInfo << "->scene node";
        for (pugi::xml_node node = root.first_child(); node; node = node.next_sibling())
        {
            const char *name = node.name();
            if (strcmp(name, "WorldBegin") == 0)
            {
                raidenWorldBegin();
            }
            else if (strcmp(name, "WorldEnd") == 0)
            {
                raidenWorldEnd();
            }
            else if (strcmp(name, "Translate") == 0)
            {
                float dx = node.attribute("x").as_float();
                float dy = node.attribute("y").as_float();
                float dz = node.attribute("z").as_float();
                raidenTranslate(dx, dy, dz);
            }
            else if (strcmp(name, "Rotate") == 0)
            {
                float angle = node.attribute("angle").as_float();
                float dx = node.attribute("x").as_float();
                float dy = node.attribute("y").as_float();
                float dz = node.attribute("z").as_float();
                raidenRotate(angle, dx, dy, dz);
            }
            else if (strcmp(name, "Scale") == 0)
            {
                float dx = node.attribute("x").as_float();
                float dy = node.attribute("y").as_float();
                float dz = node.attribute("z").as_float();
                raidenScale(dx, dy, dz);
            }
            else if (strcmp(name, "CoordinateSystem") == 0)
            {
                ParamSet params;
                auto frame_name = node.attribute("name").as_string();
                raidenCoordinateSystem(frame_name);
            }
            else if (strcmp(name, "CoordSysTransform") == 0)
            {
                ParamSet params;
                auto frame_name = node.attribute("name").as_string();
                raidenCoordSysTransform(frame_name);
            }
            //TODO 和时间有关的API还没有绑定
            else if (strcmp(name, "PixelFilter") == 0)
            {
                ParamSet params;
                auto type = node.attribute("type").as_string();
                PharseChildNodeParamSet(params, node);
                raidenPixelFilter(type, params);
            }
            else if (strcmp(name, "Accelerator") == 0)
            {
                ParamSet params;
                auto type = node.attribute("type").as_string();
                PharseChildNodeParamSet(params, node);
                raidenAccelerator(type, params);
            }
            else if (strcmp(name, "Integrator") == 0)
            {
                LInfo << "-->integrator node";
                ParamSet params;
                auto type = node.attribute("type").as_string();
                PharseChildNodeParamSet(params, node);
                raidenIntegrator(type, params);
            }
            else if (strcmp(name, "Camera") == 0)
            {
                ParamSet params;
                auto type = node.attribute("type").as_string();
                PharseChildNodeParamSet(params, node);
                raidenCamera(type, params);
            }
            else if (strcmp(name, "Film") == 0)
            {
                ParamSet params;
                auto type = node.attribute("type").as_string();
                PharseChildNodeParamSet(params, node);
                raidenFilm(type, params);
            }
            else if (strcmp(name, "Sampler") == 0)
            {
                ParamSet params;
                auto type = node.attribute("type").as_string();
                PharseChildNodeParamSet(params, node);
                raidenSampler(type, params);
            }
            else if (strcmp(name, "Shape") == 0)
            {
                ParamSet params;
                auto type = node.attribute("type").as_string();
                PharseChildNodeParamSet(params, node);
                raidenShape(type, params);
            }
            else if (strcmp(name, "Texture") == 0)
            {
                ParamSet params;
                auto t_name = node.attribute("name").as_string();
                auto type = node.attribute("type").as_string();
                auto src = node.attribute("source").as_string();
                PharseChildNodeParamSet(params, node);
                raidenTexture(t_name, type, src, params);
            }
            else if (strcmp(name, "MakeNamedMaterial") == 0)
            {
                ParamSet params;
                auto t_name = node.attribute("name").as_string();
                PushString(params, node, "type");
                PharseChildNodeParamSet(params, node);
                raidenMakeNamedMaterial(t_name, params);
            }
            else if (strcmp(name, "Material") == 0)
            {
                ParamSet params;
                auto type = node.attribute("type").as_string();
                PharseChildNodeParamSet(params, node);
                raidenMaterial(type, params);
            }
            else if (strcmp(name, "NamedMaterial") == 0)
            {
                auto t_name = node.attribute("name").as_string();
                raidenNamedMaterial(t_name);
            }
            else if (strcmp(name, "TransformBegin") == 0)
            {
                raidenTransformBegin();
            }
            else if (strcmp(name, "TransformEnd") == 0)
            {
                raidenTransformEnd();
            }
            else if (strcmp(name, "LightSource") == 0)
            {
                ParamSet params;
                auto type = node.attribute("type").as_string();
                PharseChildNodeParamSet(params, node);
                raidenLightSource(type, params);
            }
            else if (strcmp(name, "AreaLightSource") == 0)
            {
                ParamSet params;
                auto type = node.attribute("type").as_string();
                PharseChildNodeParamSet(params, node);
                raidenAreaLightSource(type,params);
            }
            else if (strcmp(name, "AttributeBegin") == 0)
            {

                raidenAttributeBegin();
            }
             else if (strcmp(name, "AttributeEnd") == 0)
            {

                raidenAttributeEnd();
            }
        }
    }
    else
    {
        LWarning << "XML file must has a root node \"scene\" but \"" << root << "\" now";
    }
}<|endoftext|>


<commit_before>#include "TROOT.h"
#include "TFile.h"
#include "TTree.h"
#include "TBrowser.h"
#include "TH2.h"
#include "TMath.h"
#include "TRandom.h"
#include "TCanvas.h"

// This example is the same as tree2.C, but uses a class instead of a C-struct.
// In this example, we are mapping a class to one of the Geant3
// common blocks /gctrak/. In the real life, this common will be filled
// by Geant3 at each step and only the Tree Fill function should be called.
// The example emulates the Geant3 step routines.
//
// to run the example, do:
// .x tree2a.C+ to execute with native compiler
//
//  Note that this example cannot be run under CINT (ie .x tree2a.c)
//  because an interpreted class cannot derive from a compiled class.
//
//  Author: Rene Brun

const Int_t MAXMEC = 30;

class Gctrak : public TObject {
public:
  Float_t  vect[7];
  Float_t  getot;
  Float_t  gekin;
  Float_t  vout[7];   //! not persistent
  Int_t    nmec;
  Int_t   *lmec;      //[nmec]
  Int_t   *namec;     //[nmec]
  Int_t    nstep;     //! not persistent
  Int_t    pid;
  Float_t  destep;
  Float_t  destel;    //! not persistent
  Float_t  safety;    //! not persistent
  Float_t  sleng;     //! not persistent
  Float_t  step;      //! not persistent
  Float_t  snext;     //! not persistent
  Float_t  sfield;    //! not persistent
  Float_t  tofg;      //! not persistent
  Float_t  gekrat;    //! not persistent
  Float_t  upwght;    //! not persistent

  Gctrak() {lmec=0; namec=0;}

  ClassDef(Gctrak,1)
};

void helixStep(Float_t step, Float_t *vect, Float_t *vout)
{
  // extrapolate track in constant field
   Float_t field = 20;      //magnetic field in kilogauss
   enum Evect {kX,kY,kZ,kPX,kPY,kPZ,kPP};
   vout[kPP] = vect[kPP];
   Float_t h4    = field*2.99792e-4;
   Float_t rho   = -h4/vect[kPP];
   Float_t tet   = rho*step;
   Float_t tsint = tet*tet/6;
   Float_t sintt = 1 - tsint;
   Float_t sint  = tet*sintt;
   Float_t cos1t = tet/2;
   Float_t f1 = step*sintt;
   Float_t f2 = step*cos1t;
   Float_t f3 = step*tsint*vect[kPZ];
   Float_t f4 = -tet*cos1t;
   Float_t f5 = sint;
   Float_t f6 = tet*cos1t*vect[kPZ];
   vout[kX]   = vect[kX]  + (f1*vect[kPX] - f2*vect[kPY]);
   vout[kY]   = vect[kY]  + (f1*vect[kPY] + f2*vect[kPX]);
   vout[kZ]   = vect[kZ]  + (f1*vect[kPZ] + f3);
   vout[kPX]  = vect[kPX] + (f4*vect[kPX] - f5*vect[kPY]);
   vout[kPY]  = vect[kPY] + (f4*vect[kPY] + f5*vect[kPX]);
   vout[kPZ]  = vect[kPZ] + (f4*vect[kPZ] + f6);
}

void tree2aw()
{
   //create a Tree file tree2.root

   //create the file, the Tree and a few branches with
   //a subset of gctrak
   TFile f("tree2.root","recreate");
   TTree t2("t2","a Tree with data from a fake Geant3");
   Gctrak *gstep = new Gctrak;
   t2.Branch("track",&gstep,8000,1);

   //Initialize particle parameters at first point
   Float_t px,py,pz,p,charge=0;
   Float_t vout[7];
   Float_t mass  = 0.137;
   Bool_t newParticle = kTRUE;
   gstep->lmec    = new Int_t[MAXMEC];
   gstep->namec   = new Int_t[MAXMEC];
   gstep->step    = 0.1;
   gstep->destep  = 0;
   gstep->nmec    = 0;
   gstep->pid     = 0;

   //transport particles
   for (Int_t i=0;i<10000;i++) {
      //generate a new particle if necessary
      if (newParticle) {
         px = gRandom->Gaus(0,.02);
         py = gRandom->Gaus(0,.02);
         pz = gRandom->Gaus(0,.02);
         p  = TMath::Sqrt(px*px+py*py+pz*pz);
         charge = 1; if (gRandom->Rndm() < 0.5) charge = -1;
         gstep->pid    += 1;
         gstep->vect[0] = 0;
         gstep->vect[1] = 0;
         gstep->vect[2] = 0;
         gstep->vect[3] = px/p;
         gstep->vect[4] = py/p;
         gstep->vect[5] = pz/p;
         gstep->vect[6] = p*charge;
         gstep->getot   = TMath::Sqrt(p*p + mass*mass);
         gstep->gekin   = gstep->getot - mass;
         newParticle = kFALSE;
      }

      // fill the Tree with current step parameters
      t2.Fill();

      //transport particle in magnetic field
      helixStep(gstep->step, gstep->vect, vout); //make one step

      //apply energy loss
      gstep->destep = gstep->step*gRandom->Gaus(0.0002,0.00001);
      gstep->gekin -= gstep->destep;
      gstep->getot   = gstep->gekin + mass;
      gstep->vect[6] = charge*TMath::Sqrt(gstep->getot*gstep->getot - mass*mass);
      gstep->vect[0] = vout[0];
      gstep->vect[1] = vout[1];
      gstep->vect[2] = vout[2];
      gstep->vect[3] = vout[3];
      gstep->vect[4] = vout[4];
      gstep->vect[5] = vout[5];
      gstep->nmec    = (Int_t)(5*gRandom->Rndm());
      for (Int_t l=0;l<gstep->nmec;l++) {
         gstep->lmec[l] = l;
         gstep->namec[l] = l+100;
      }
      if (gstep->gekin < 0.001)            newParticle = kTRUE;
      if (TMath::Abs(gstep->vect[2]) > 30) newParticle = kTRUE;
   }

   //save the Tree header. The file will be automatically closed
   //when going out of the function scope
   t2.Write();
}

void tree2ar()
{
   //read the Tree generated by tree2w and fill one histogram
   //we are only interested by the destep branch.

   //note that we use "new" to create the TFile and TTree objects !
   //because we want to keep these objects alive when we leave
   //this function.
   TFile *f = new TFile("tree2.root");
   TTree *t2 = (TTree*)f->Get("t2");
   Gctrak *gstep = 0;
   t2->SetBranchAddress("track",&gstep);
   TBranch *b_destep = t2->GetBranch("destep");

   //create one histogram
   TH1F *hdestep   = new TH1F("hdestep","destep in Mev",100,1e-5,3e-5);

   //read only the destep branch for all entries
   Int_t nentries = (Int_t)t2->GetEntries();
   for (Int_t i=0;i<nentries;i++) {
      b_destep->GetEntry(i);
      hdestep->Fill(gstep->destep);
   }

   //we do not close the file.
   //We want to keep the generated histograms
   //We fill a 3-d scatter plot with the particle step coordinates
   TCanvas *c1 = new TCanvas("c1","c1",600,800);
   c1->SetFillColor(42);
   c1->Divide(1,2);
   c1->cd(1);
   hdestep->SetFillColor(45);
   hdestep->Fit("gaus");
   c1->cd(2);
   gPad->SetFillColor(37);
   t2->SetMarkerColor(kRed);
   t2->Draw("vect[0]:vect[1]:vect[2]");
   if (gROOT->IsBatch()) return;

   // invoke the x3d viewer
   gPad->GetViewer3D("x3d");
}

void tree2a() {
   tree2aw();
   tree2ar();
}
<commit_msg>Force the tutorial to be run with ACLIC. This is required when executing the tutorial with the new version of MakeTutorials.<commit_after>#include "TROOT.h"
#include "TFile.h"
#include "TTree.h"
#include "TBrowser.h"
#include "TH2.h"
#include "TMath.h"
#include "TRandom.h"
#include "TCanvas.h"

//+ This example is the same as tree2.C, but uses a class instead of a C-struct.
// In this example, we are mapping a class to one of the Geant3
// common blocks /gctrak/. In the real life, this common will be filled
// by Geant3 at each step and only the Tree Fill function should be called.
// The example emulates the Geant3 step routines.
//
// to run the example, do:
// .x tree2a.C+ to execute with native compiler
//
//  Note that this example cannot be run under CINT (ie .x tree2a.c)
//  because an interpreted class cannot derive from a compiled class.
//
//  Author: Rene Brun

const Int_t MAXMEC = 30;

class Gctrak : public TObject {
public:
  Float_t  vect[7];
  Float_t  getot;
  Float_t  gekin;
  Float_t  vout[7];   //! not persistent
  Int_t    nmec;
  Int_t   *lmec;      //[nmec]
  Int_t   *namec;     //[nmec]
  Int_t    nstep;     //! not persistent
  Int_t    pid;
  Float_t  destep;
  Float_t  destel;    //! not persistent
  Float_t  safety;    //! not persistent
  Float_t  sleng;     //! not persistent
  Float_t  step;      //! not persistent
  Float_t  snext;     //! not persistent
  Float_t  sfield;    //! not persistent
  Float_t  tofg;      //! not persistent
  Float_t  gekrat;    //! not persistent
  Float_t  upwght;    //! not persistent

  Gctrak() {lmec=0; namec=0;}

  ClassDef(Gctrak,1)
};

void helixStep(Float_t step, Float_t *vect, Float_t *vout)
{
  // extrapolate track in constant field
   Float_t field = 20;      //magnetic field in kilogauss
   enum Evect {kX,kY,kZ,kPX,kPY,kPZ,kPP};
   vout[kPP] = vect[kPP];
   Float_t h4    = field*2.99792e-4;
   Float_t rho   = -h4/vect[kPP];
   Float_t tet   = rho*step;
   Float_t tsint = tet*tet/6;
   Float_t sintt = 1 - tsint;
   Float_t sint  = tet*sintt;
   Float_t cos1t = tet/2;
   Float_t f1 = step*sintt;
   Float_t f2 = step*cos1t;
   Float_t f3 = step*tsint*vect[kPZ];
   Float_t f4 = -tet*cos1t;
   Float_t f5 = sint;
   Float_t f6 = tet*cos1t*vect[kPZ];
   vout[kX]   = vect[kX]  + (f1*vect[kPX] - f2*vect[kPY]);
   vout[kY]   = vect[kY]  + (f1*vect[kPY] + f2*vect[kPX]);
   vout[kZ]   = vect[kZ]  + (f1*vect[kPZ] + f3);
   vout[kPX]  = vect[kPX] + (f4*vect[kPX] - f5*vect[kPY]);
   vout[kPY]  = vect[kPY] + (f4*vect[kPY] + f5*vect[kPX]);
   vout[kPZ]  = vect[kPZ] + (f4*vect[kPZ] + f6);
}

void tree2aw()
{
   //create a Tree file tree2.root

   //create the file, the Tree and a few branches with
   //a subset of gctrak
   TFile f("tree2.root","recreate");
   TTree t2("t2","a Tree with data from a fake Geant3");
   Gctrak *gstep = new Gctrak;
   t2.Branch("track",&gstep,8000,1);

   //Initialize particle parameters at first point
   Float_t px,py,pz,p,charge=0;
   Float_t vout[7];
   Float_t mass  = 0.137;
   Bool_t newParticle = kTRUE;
   gstep->lmec    = new Int_t[MAXMEC];
   gstep->namec   = new Int_t[MAXMEC];
   gstep->step    = 0.1;
   gstep->destep  = 0;
   gstep->nmec    = 0;
   gstep->pid     = 0;

   //transport particles
   for (Int_t i=0;i<10000;i++) {
      //generate a new particle if necessary
      if (newParticle) {
         px = gRandom->Gaus(0,.02);
         py = gRandom->Gaus(0,.02);
         pz = gRandom->Gaus(0,.02);
         p  = TMath::Sqrt(px*px+py*py+pz*pz);
         charge = 1; if (gRandom->Rndm() < 0.5) charge = -1;
         gstep->pid    += 1;
         gstep->vect[0] = 0;
         gstep->vect[1] = 0;
         gstep->vect[2] = 0;
         gstep->vect[3] = px/p;
         gstep->vect[4] = py/p;
         gstep->vect[5] = pz/p;
         gstep->vect[6] = p*charge;
         gstep->getot   = TMath::Sqrt(p*p + mass*mass);
         gstep->gekin   = gstep->getot - mass;
         newParticle = kFALSE;
      }

      // fill the Tree with current step parameters
      t2.Fill();

      //transport particle in magnetic field
      helixStep(gstep->step, gstep->vect, vout); //make one step

      //apply energy loss
      gstep->destep = gstep->step*gRandom->Gaus(0.0002,0.00001);
      gstep->gekin -= gstep->destep;
      gstep->getot   = gstep->gekin + mass;
      gstep->vect[6] = charge*TMath::Sqrt(gstep->getot*gstep->getot - mass*mass);
      gstep->vect[0] = vout[0];
      gstep->vect[1] = vout[1];
      gstep->vect[2] = vout[2];
      gstep->vect[3] = vout[3];
      gstep->vect[4] = vout[4];
      gstep->vect[5] = vout[5];
      gstep->nmec    = (Int_t)(5*gRandom->Rndm());
      for (Int_t l=0;l<gstep->nmec;l++) {
         gstep->lmec[l] = l;
         gstep->namec[l] = l+100;
      }
      if (gstep->gekin < 0.001)            newParticle = kTRUE;
      if (TMath::Abs(gstep->vect[2]) > 30) newParticle = kTRUE;
   }

   //save the Tree header. The file will be automatically closed
   //when going out of the function scope
   t2.Write();
}

void tree2ar()
{
   //read the Tree generated by tree2w and fill one histogram
   //we are only interested by the destep branch.

   //note that we use "new" to create the TFile and TTree objects !
   //because we want to keep these objects alive when we leave
   //this function.
   TFile *f = new TFile("tree2.root");
   TTree *t2 = (TTree*)f->Get("t2");
   Gctrak *gstep = 0;
   t2->SetBranchAddress("track",&gstep);
   TBranch *b_destep = t2->GetBranch("destep");

   //create one histogram
   TH1F *hdestep   = new TH1F("hdestep","destep in Mev",100,1e-5,3e-5);

   //read only the destep branch for all entries
   Int_t nentries = (Int_t)t2->GetEntries();
   for (Int_t i=0;i<nentries;i++) {
      b_destep->GetEntry(i);
      hdestep->Fill(gstep->destep);
   }

   //we do not close the file.
   //We want to keep the generated histograms
   //We fill a 3-d scatter plot with the particle step coordinates
   TCanvas *c1 = new TCanvas("c1","c1",600,800);
   c1->SetFillColor(42);
   c1->Divide(1,2);
   c1->cd(1);
   hdestep->SetFillColor(45);
   hdestep->Fit("gaus");
   c1->cd(2);
   gPad->SetFillColor(37);
   t2->SetMarkerColor(kRed);
   t2->Draw("vect[0]:vect[1]:vect[2]");
   if (gROOT->IsBatch()) return;

   // invoke the x3d viewer
   gPad->GetViewer3D("x3d");
}

void tree2a() {
   tree2aw();
   tree2ar();
}
<|endoftext|>


<commit_before>#include "Halide.h"
#include <stdio.h>
#include <stdlib.h>

using namespace Halide;

int test_per_channel_select() {

    // This test must be run with an OpenGL target.
    const Target target = get_jit_target_from_environment().with_feature(Target::OpenGL);

    Func gpu("gpu"), cpu("cpu");
    Var x("x"), y("y"), c("c");

    gpu(x, y, c) = cast<uint8_t>(select(c == 0, 128,
                                        c == 1, x,
                                        c == 2, y,
                                        x*y));
    gpu.bound(c, 0, 4);
    gpu.glsl(x, y, c);
    gpu.compute_root();

    cpu(x, y, c) = gpu(x, y, c);

    Buffer<uint8_t> out(10, 10, 4);
    cpu.realize(out, target);

    // Verify the result
    for (int y=0; y!=out.height(); ++y) {
        for (int x=0; x!=out.width(); ++x) {
            for (int c=0; c!=out.channels(); ++c) {
                uint8_t expected;
                switch (c) {
                    case 0: expected = 128; break;
                    case 1: expected = x; break;
                    case 2: expected = y; break;
                    default: expected = x*y; break;
                }
                uint8_t actual  = out(x,y,c);

                if (expected != actual) {
                    fprintf(stderr, "Incorrect pixel (%d, %d, %d, %d) at x=%d y=%d.\n",
                            out(x, y, 0), out(x, y, 1), out(x, y, 2), out(x, y, 3),
                            x, y);
                    return 1;
                }
            }
        }
    }

    return 0;
}

int test_flag_scalar_select() {

    // This test must be run with an OpenGL target.
    const Target target = get_jit_target_from_environment().with_feature(Target::OpenGL);

    Func gpu("gpu"), cpu("cpu");
    Var x("x"), y("y"), c("c");

    int flag_value = 0;

    Param<int> flag("flag");
    flag.set(flag_value);

    gpu(x, y, c) = cast<uint8_t>(select(flag != 0, 128,
                                        255));
    gpu.bound(c, 0, 4);
    gpu.glsl(x, y, c);
    gpu.compute_root();

    // This should trigger a copy_to_host operation
    cpu(x, y, c) = gpu(x, y, c);

    Buffer<uint8_t> out(10, 10, 4);
    cpu.realize(out, target);

    // Verify the result
    for (int y=0; y!=out.height(); ++y) {
        for (int x=0; x!=out.width(); ++x) {
            for (int c=0; c!=out.channels(); ++c) {
                uint8_t expected = !flag_value ? 255 : 128;
                uint8_t actual  = out(x,y,c);

                if (expected != actual) {
                    fprintf(stderr, "Incorrect pixel (%d, %d, %d, %d) at x=%d y=%d.\n",
                            out(x, y, 0), out(x, y, 1), out(x, y, 2), out(x, y, 3),
                            x, y);
                    return 1;
                }
            }
        }
    }

    return 0;
}

int test_flag_pixel_select() {

    // This test must be run with an OpenGL target.
    const Target target = get_jit_target_from_environment().with_feature(Target::OpenGL);

    Func gpu("gpu"), cpu("cpu");
    Var x("x"), y("y"), c("c");

    int flag_value = 0;

    Param<int> flag("flag");
    flag.set(flag_value);

    Buffer<uint8_t> image(10, 10, 4);
    for (int y=0; y<image.height(); y++) {
        for (int x=0; x<image.width(); x++) {
            for (int c=0; c<image.channels(); c++) {
                image(x, y, c) = 128;
            }
        }
    }

    gpu(x, y, c) = cast<uint8_t>(select(flag != 0, image(x,y,c),
                                        255));
    gpu.bound(c, 0, 4);
    gpu.glsl(x, y, c);
    gpu.compute_root();

    // This should trigger a copy_to_host operation
    cpu(x, y, c) = gpu(x, y, c);

    Buffer<uint8_t> out(10, 10, 4);
    cpu.realize(out, target);

    // Verify the result
    for (int y=0; y!=out.height(); ++y) {
        for (int x=0; x!=out.width(); ++x) {
            for (int c=0; c!=out.channels(); ++c) {
                uint8_t expected = !flag_value ? 255 : 128;
                uint8_t actual  = out(x,y,c);

                if (expected != actual) {
                    fprintf(stderr, "Incorrect pixel (%d, %d, %d, %d) at x=%d y=%d.\n",
                            out(x, y, 0), out(x, y, 1), out(x, y, 2), out(x, y, 3),
                            x, y);
                    return 1;
                }
            }
        }
    }

    return 0;
}

int main() {

    int err = 0;

    err |= test_per_channel_select();
    err |= test_flag_scalar_select();
    err |= test_flag_pixel_select();

    if (err) {
        printf("FAILED\n");
        return 1;
    }

    printf("Success!\n");
    return 0;
}
<commit_msg>Added failing test cases for issue #1781: Internal assertion failures when compiling certain select expressions for OpenGL target.<commit_after>#include "Halide.h"
#include <stdio.h>
#include <stdlib.h>

using namespace Halide;

int test_per_channel_select() {

    printf("Testing select of channel.\n");

    // This test must be run with an OpenGL target.
    const Target target = get_jit_target_from_environment().with_feature(Target::OpenGL);

    Func gpu("gpu"), cpu("cpu");
    Var x("x"), y("y"), c("c");

    gpu(x, y, c) = cast<uint8_t>(select(c == 0, 128,
                                        c == 1, x,
                                        c == 2, y,
                                        x*y));
    gpu.bound(c, 0, 4);
    gpu.glsl(x, y, c);
    gpu.compute_root();

    cpu(x, y, c) = gpu(x, y, c);

    Buffer<uint8_t> out(10, 10, 4);
    cpu.realize(out, target);

    // Verify the result
    for (int y=0; y!=out.height(); ++y) {
        for (int x=0; x!=out.width(); ++x) {
            for (int c=0; c!=out.channels(); ++c) {
                uint8_t expected;
                switch (c) {
                    case 0: expected = 128; break;
                    case 1: expected = x; break;
                    case 2: expected = y; break;
                    default: expected = x*y; break;
                }
                uint8_t actual  = out(x,y,c);

                if (expected != actual) {
                    fprintf(stderr, "Incorrect pixel (%d, %d, %d, %d) at x=%d y=%d.\n",
                            out(x, y, 0), out(x, y, 1), out(x, y, 2), out(x, y, 3),
                            x, y);
                    return 1;
                }
            }
        }
    }

    return 0;
}

int test_flag_scalar_select() {

    printf("Testing select of scalar value with flag.\n");

    // This test must be run with an OpenGL target.
    const Target target = get_jit_target_from_environment().with_feature(Target::OpenGL);

    Func gpu("gpu"), cpu("cpu");
    Var x("x"), y("y"), c("c");

    int flag_value = 0;

    Param<int> flag("flag");
    flag.set(flag_value);

    gpu(x, y, c) = cast<uint8_t>(select(flag != 0, 128,
                                        255));
    gpu.bound(c, 0, 4);
    gpu.glsl(x, y, c);
    gpu.compute_root();

    // This should trigger a copy_to_host operation
    cpu(x, y, c) = gpu(x, y, c);

    Buffer<uint8_t> out(10, 10, 4);
    cpu.realize(out, target);

    // Verify the result
    for (int y=0; y!=out.height(); ++y) {
        for (int x=0; x!=out.width(); ++x) {
            for (int c=0; c!=out.channels(); ++c) {
                uint8_t expected = !flag_value ? 255 : 128;
                uint8_t actual  = out(x,y,c);

                if (expected != actual) {
                    fprintf(stderr, "Incorrect pixel (%d, %d, %d, %d) at x=%d y=%d.\n",
                            out(x, y, 0), out(x, y, 1), out(x, y, 2), out(x, y, 3),
                            x, y);
                    return 1;
                }
            }
        }
    }

    return 0;
}

int test_flag_pixel_select() {

    printf("Testing select of pixel value with flag.\n");

    // This test must be run with an OpenGL target.
    const Target target = get_jit_target_from_environment().with_feature(Target::OpenGL);

    Func gpu("gpu"), cpu("cpu");
    Var x("x"), y("y"), c("c");

    int flag_value = 0;

    Param<int> flag("flag");
    flag.set(flag_value);

    Buffer<uint8_t> image(10, 10, 4);
    for (int y=0; y<image.height(); y++) {
        for (int x=0; x<image.width(); x++) {
            for (int c=0; c<image.channels(); c++) {
                image(x, y, c) = 128;
            }
        }
    }

    gpu(x, y, c) = cast<uint8_t>(select(flag != 0, image(x,y,c),
                                        255));
    gpu.bound(c, 0, 4);
    gpu.glsl(x, y, c);
    gpu.compute_root();

    // This should trigger a copy_to_host operation
    cpu(x, y, c) = gpu(x, y, c);

    Buffer<uint8_t> out(10, 10, 4);
    cpu.realize(out, target);

    // Verify the result
    for (int y=0; y!=out.height(); ++y) {
        for (int x=0; x!=out.width(); ++x) {
            for (int c=0; c!=out.channels(); ++c) {
                uint8_t expected = !flag_value ? 255 : 128;
                uint8_t actual  = out(x,y,c);

                if (expected != actual) {
                    fprintf(stderr, "Incorrect pixel (%d, %d, %d, %d) at x=%d y=%d.\n",
                            out(x, y, 0), out(x, y, 1), out(x, y, 2), out(x, y, 3),
                            x, y);
                    return 1;
                }
            }
        }
    }

    return 0;
}

int test_nested_select() {

    printf("Testing nested select.\n");

    // This test must be run with an OpenGL target.
    const Target target = get_jit_target_from_environment().with_feature(Target::OpenGL);

    // Define the algorithm.
    Var x("x"), y("y"), c("c");
    Func f("f");
    Expr temp = cast<uint8_t>(select(x == 0, 1, 2));
    f(x, y, c) = select(y == 0, temp, 255 - temp);

    // Schedule f to run on the GPU.
    const int channels = 3;
    f.bound(c, 0, channels).glsl(x, y, c);

    // Generate the result.
    const int width = 10, height = 10;
    Buffer<uint8_t> out = f.realize(width, height, channels, target);

    // Check the result.
    int errors = 0;
    out.for_each_element([&](int x, int y, int c) {
        uint8_t temp = x == 0 ? 1 : 2;
        uint8_t expected = y == 0 ? temp : 255 - temp;
        uint8_t actual = out(x, y, c);
        if (expected != actual && ++errors == 1) {
            fprintf(stderr, "out(%d, %d, %d) = %d instead of %d\n",
                    x, y, c, actual, expected);
        }
    });

    return errors;
}

int test_nested_select_varying() {

    printf("Testing nested select with varying condition.\n");

    // This test must be run with an OpenGL target.
    const Target target = get_jit_target_from_environment().with_feature(Target::OpenGL);

    // Define the algorithm.
    Var x("x"), y("y"), c("c");
    Func f("f");
    Expr temp = cast<uint8_t>(select(x - c > 0, 1, 2));
    f(x, y, c) = select(y == 0, temp, 255 - temp);

    // Schedule f to run on the GPU.
    const int channels = 3;
    f.bound(c, 0, channels).glsl(x, y, c);

    // Generate the result.
    const int width = 10, height = 10;
    Buffer<uint8_t> out = f.realize(width, height, channels, target);

    // Check the result.
    int errors = 0;
    out.for_each_element([&](int x, int y, int c) {
        uint8_t temp = x - c > 0 ? 1 : 2;
        uint8_t expected = y == 0 ? temp : 255 - temp;
        uint8_t actual = out(x, y, c);
        if (expected != actual && ++errors == 1) {
            fprintf(stderr, "out(%d, %d, %d) = %d instead of %d\n",
                    x, y, c, actual, expected);
        }
    });

    return errors;
}

int main() {

    int err = 0;

    err |= test_per_channel_select();
    err |= test_flag_scalar_select();
    err |= test_flag_pixel_select();
    err |= test_nested_select();
    err |= test_nested_select_varying();

    if (err) {
        printf("FAILED\n");
        return 1;
    }

    printf("Success!\n");
    return 0;
}
<|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/gl/gl_surface.h"

#include <dwmapi.h>

#include "base/command_line.h"
#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/win/windows_version.h"
#include "ui/gfx/frame_time.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_implementation.h"
#include "ui/gl/gl_surface_egl.h"
#include "ui/gl/gl_surface_osmesa.h"
#include "ui/gl/gl_surface_stub.h"
#include "ui/gl/gl_surface_wgl.h"

// From ANGLE's egl/eglext.h.
#if !defined(EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE)
#define EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE \
  reinterpret_cast<EGLNativeDisplayType>(-2)
#endif
#if !defined(EGL_PLATFORM_ANGLE_ANGLE)
#define EGL_PLATFORM_ANGLE_ANGLE 0x3201
#endif
#if !defined(EGL_PLATFORM_ANGLE_TYPE_ANGLE)
#define EGL_PLATFORM_ANGLE_TYPE_ANGLE 0x3202
#endif
#if !defined(EGL_PLATFORM_ANGLE_TYPE_D3D11_WARP_ANGLE)
#define EGL_PLATFORM_ANGLE_TYPE_D3D11_WARP_ANGLE 0x3206
#endif

namespace gfx {

// This OSMesa GL surface can use GDI to swap the contents of the buffer to a
// view.
class NativeViewGLSurfaceOSMesa : public GLSurfaceOSMesa {
 public:
  explicit NativeViewGLSurfaceOSMesa(gfx::AcceleratedWidget window);
  virtual ~NativeViewGLSurfaceOSMesa();

  // Implement subset of GLSurface.
  virtual bool Initialize() override;
  virtual void Destroy() override;
  virtual bool IsOffscreen() override;
  virtual bool SwapBuffers() override;
  virtual bool SupportsPostSubBuffer() override;
  virtual bool PostSubBuffer(int x, int y, int width, int height) override;

 private:
  gfx::AcceleratedWidget window_;
  HDC device_context_;

  DISALLOW_COPY_AND_ASSIGN(NativeViewGLSurfaceOSMesa);
};

class WinVSyncProvider : public VSyncProvider {
 public:
  explicit WinVSyncProvider(gfx::AcceleratedWidget window) :
    window_(window)
  {
    use_dwm_ = (base::win::GetVersion() >= base::win::VERSION_VISTA);
  }

  virtual ~WinVSyncProvider() {}

  virtual void GetVSyncParameters(const UpdateVSyncCallback& callback) {
    TRACE_EVENT0("gpu", "WinVSyncProvider::GetVSyncParameters");

    base::TimeTicks timebase;
    base::TimeDelta interval;
    bool dwm_active = false;

    // Query the DWM timing info first if available. This will provide the most
    // precise values.
    if (use_dwm_) {
      DWM_TIMING_INFO timing_info;
      timing_info.cbSize = sizeof(timing_info);
      HRESULT result = DwmGetCompositionTimingInfo(NULL, &timing_info);
      if (result == S_OK) {
        dwm_active = true;
        if (gfx::FrameTime::TimestampsAreHighRes()) {
          // qpcRefreshPeriod is very accurate but noisy, and must be used with
          // a high resolution timebase to avoid frequently missing Vsync.
          timebase = gfx::FrameTime::FromQPCValue(
              static_cast<LONGLONG>(timing_info.qpcVBlank));
          interval = base::TimeDelta::FromQPCValue(
              static_cast<LONGLONG>(timing_info.qpcRefreshPeriod));
        } else if (timing_info.rateRefresh.uiDenominator > 0 &&
            timing_info.rateRefresh.uiNumerator > 0) {
          // If FrameTime is not high resolution, we do not want to translate
          // the QPC value provided by DWM into the low-resolution timebase,
          // which would be error prone and jittery. As a fallback, we assume
          // the timebase is zero and use rateRefresh, which may be rounded but
          // isn't noisy like qpcRefreshPeriod, instead. The fact that we don't
          // have a timebase here may lead to brief periods of jank when our
          // scheduling becomes offset from the hardware vsync.

          // Swap the numerator/denominator to convert frequency to period.
          interval = base::TimeDelta::FromMicroseconds(
              timing_info.rateRefresh.uiDenominator *
              base::Time::kMicrosecondsPerSecond /
              timing_info.rateRefresh.uiNumerator);
        }
      }
    }

    if (!dwm_active) {
      // When DWM compositing is active all displays are normalized to the
      // refresh rate of the primary display, and won't composite any faster.
      // If DWM compositing is disabled, though, we can use the refresh rates
      // reported by each display, which will help systems that have mis-matched
      // displays that run at different frequencies.
      HMONITOR monitor = MonitorFromWindow(window_, MONITOR_DEFAULTTONEAREST);
      MONITORINFOEX monitor_info;
      monitor_info.cbSize = sizeof(MONITORINFOEX);
      BOOL result = GetMonitorInfo(monitor, &monitor_info);
      if (result) {
        DEVMODE display_info;
        display_info.dmSize = sizeof(DEVMODE);
        display_info.dmDriverExtra = 0;
        result = EnumDisplaySettings(monitor_info.szDevice,
            ENUM_CURRENT_SETTINGS, &display_info);
        if (result && display_info.dmDisplayFrequency > 1) {
          interval = base::TimeDelta::FromMicroseconds(
              (1.0 / static_cast<double>(display_info.dmDisplayFrequency)) *
              base::Time::kMicrosecondsPerSecond);
        }
      }
    }

    if (interval.ToInternalValue() != 0) {
      callback.Run(timebase, interval);
    }
  }

 private:
  DISALLOW_COPY_AND_ASSIGN(WinVSyncProvider);

  gfx::AcceleratedWidget window_;
  bool use_dwm_;
};

// Helper routine that does one-off initialization like determining the
// pixel format.
bool GLSurface::InitializeOneOffInternal() {
  switch (GetGLImplementation()) {
    case kGLImplementationDesktopGL:
      if (!GLSurfaceWGL::InitializeOneOff()) {
        LOG(ERROR) << "GLSurfaceWGL::InitializeOneOff failed.";
        return false;
      }
      break;
    case kGLImplementationEGLGLES2:
      if (!GLSurfaceEGL::InitializeOneOff()) {
        LOG(ERROR) << "GLSurfaceEGL::InitializeOneOff failed.";
        return false;
      }
      break;
  }
  return true;
}

NativeViewGLSurfaceOSMesa::NativeViewGLSurfaceOSMesa(
    gfx::AcceleratedWidget window)
    : GLSurfaceOSMesa(OSMesaSurfaceFormatRGBA, gfx::Size(1, 1)),
      window_(window),
      device_context_(NULL) {
  DCHECK(window);
}

NativeViewGLSurfaceOSMesa::~NativeViewGLSurfaceOSMesa() {
  Destroy();
}

bool NativeViewGLSurfaceOSMesa::Initialize() {
  if (!GLSurfaceOSMesa::Initialize())
    return false;

  device_context_ = GetDC(window_);
  return true;
}

void NativeViewGLSurfaceOSMesa::Destroy() {
  if (window_ && device_context_)
    ReleaseDC(window_, device_context_);

  device_context_ = NULL;

  GLSurfaceOSMesa::Destroy();
}

bool NativeViewGLSurfaceOSMesa::IsOffscreen() {
  return false;
}

bool NativeViewGLSurfaceOSMesa::SwapBuffers() {
  DCHECK(device_context_);

  gfx::Size size = GetSize();

  // Note: negating the height below causes GDI to treat the bitmap data as row
  // 0 being at the top.
  BITMAPV4HEADER info = { sizeof(BITMAPV4HEADER) };
  info.bV4Width = size.width();
  info.bV4Height = -size.height();
  info.bV4Planes = 1;
  info.bV4BitCount = 32;
  info.bV4V4Compression = BI_BITFIELDS;
  info.bV4RedMask = 0x000000FF;
  info.bV4GreenMask = 0x0000FF00;
  info.bV4BlueMask = 0x00FF0000;
  info.bV4AlphaMask = 0xFF000000;

  // Copy the back buffer to the window's device context. Do not check whether
  // StretchDIBits succeeds or not. It will fail if the window has been
  // destroyed but it is preferable to allow rendering to silently fail if the
  // window is destroyed. This is because the primary application of this
  // class of GLContext is for testing and we do not want every GL related ui /
  // browser test to become flaky if there is a race condition between GL
  // context destruction and window destruction.
  StretchDIBits(device_context_,
                0, 0, size.width(), size.height(),
                0, 0, size.width(), size.height(),
                GetHandle(),
                reinterpret_cast<BITMAPINFO*>(&info),
                DIB_RGB_COLORS,
                SRCCOPY);

  return true;
}

bool NativeViewGLSurfaceOSMesa::SupportsPostSubBuffer() {
  return true;
}

bool NativeViewGLSurfaceOSMesa::PostSubBuffer(
    int x, int y, int width, int height) {
  DCHECK(device_context_);

  gfx::Size size = GetSize();

  // Note: negating the height below causes GDI to treat the bitmap data as row
  // 0 being at the top.
  BITMAPV4HEADER info = { sizeof(BITMAPV4HEADER) };
  info.bV4Width = size.width();
  info.bV4Height = -size.height();
  info.bV4Planes = 1;
  info.bV4BitCount = 32;
  info.bV4V4Compression = BI_BITFIELDS;
  info.bV4RedMask = 0x000000FF;
  info.bV4GreenMask = 0x0000FF00;
  info.bV4BlueMask = 0x00FF0000;
  info.bV4AlphaMask = 0xFF000000;

  // Copy the back buffer to the window's device context. Do not check whether
  // StretchDIBits succeeds or not. It will fail if the window has been
  // destroyed but it is preferable to allow rendering to silently fail if the
  // window is destroyed. This is because the primary application of this
  // class of GLContext is for testing and we do not want every GL related ui /
  // browser test to become flaky if there is a race condition between GL
  // context destruction and window destruction.
  StretchDIBits(device_context_,
                x, size.height() - y - height, width, height,
                x, y, width, height,
                GetHandle(),
                reinterpret_cast<BITMAPINFO*>(&info),
                DIB_RGB_COLORS,
                SRCCOPY);

  return true;
}

scoped_refptr<GLSurface> GLSurface::CreateViewGLSurface(
    gfx::AcceleratedWidget window) {
  TRACE_EVENT0("gpu", "GLSurface::CreateViewGLSurface");
  switch (GetGLImplementation()) {
    case kGLImplementationOSMesaGL: {
      scoped_refptr<GLSurface> surface(
          new NativeViewGLSurfaceOSMesa(window));
      if (!surface->Initialize())
        return NULL;

      return surface;
    }
    case kGLImplementationEGLGLES2: {
      DCHECK(window != gfx::kNullAcceleratedWidget);
      scoped_refptr<NativeViewGLSurfaceEGL> surface(
          new NativeViewGLSurfaceEGL(window));
      scoped_ptr<VSyncProvider> sync_provider;
      sync_provider.reset(new WinVSyncProvider(window));
      if (!surface->Initialize(sync_provider.Pass()))
        return NULL;

      return surface;
    }
    case kGLImplementationDesktopGL: {
      scoped_refptr<GLSurface> surface(new NativeViewGLSurfaceWGL(
          window));
      if (!surface->Initialize())
        return NULL;

      return surface;
    }
    case kGLImplementationMockGL:
      return new GLSurfaceStub;
    default:
      NOTREACHED();
      return NULL;
  }
}

scoped_refptr<GLSurface> GLSurface::CreateOffscreenGLSurface(
    const gfx::Size& size) {
  TRACE_EVENT0("gpu", "GLSurface::CreateOffscreenGLSurface");
  switch (GetGLImplementation()) {
    case kGLImplementationOSMesaGL: {
      scoped_refptr<GLSurface> surface(
          new GLSurfaceOSMesa(OSMesaSurfaceFormatRGBA, size));
      if (!surface->Initialize())
        return NULL;

      return surface;
    }
    case kGLImplementationEGLGLES2: {
      scoped_refptr<GLSurface> surface(new PbufferGLSurfaceEGL(size));
      if (!surface->Initialize())
        return NULL;

      return surface;
    }
    case kGLImplementationDesktopGL: {
      scoped_refptr<GLSurface> surface(new PbufferGLSurfaceWGL(size));
      if (!surface->Initialize())
        return NULL;

      return surface;
    }
    case kGLImplementationMockGL:
      return new GLSurfaceStub;
    default:
      NOTREACHED();
      return NULL;
  }
}

EGLNativeDisplayType GetPlatformDefaultEGLNativeDisplay() {
  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableD3D11) ||
      CommandLine::ForCurrentProcess()->HasSwitch(switches::kUseWarp))
    return GetDC(NULL);
  return EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE;
}

}  // namespace gfx
<commit_msg>Make the Vsync provider be the same for Vista and XP<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/gl/gl_surface.h"

#include <dwmapi.h>

#include "base/command_line.h"
#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/win/windows_version.h"
#include "ui/gfx/frame_time.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_implementation.h"
#include "ui/gl/gl_surface_egl.h"
#include "ui/gl/gl_surface_osmesa.h"
#include "ui/gl/gl_surface_stub.h"
#include "ui/gl/gl_surface_wgl.h"

// From ANGLE's egl/eglext.h.
#if !defined(EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE)
#define EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE \
  reinterpret_cast<EGLNativeDisplayType>(-2)
#endif
#if !defined(EGL_PLATFORM_ANGLE_ANGLE)
#define EGL_PLATFORM_ANGLE_ANGLE 0x3201
#endif
#if !defined(EGL_PLATFORM_ANGLE_TYPE_ANGLE)
#define EGL_PLATFORM_ANGLE_TYPE_ANGLE 0x3202
#endif
#if !defined(EGL_PLATFORM_ANGLE_TYPE_D3D11_WARP_ANGLE)
#define EGL_PLATFORM_ANGLE_TYPE_D3D11_WARP_ANGLE 0x3206
#endif

namespace gfx {

// This OSMesa GL surface can use GDI to swap the contents of the buffer to a
// view.
class NativeViewGLSurfaceOSMesa : public GLSurfaceOSMesa {
 public:
  explicit NativeViewGLSurfaceOSMesa(gfx::AcceleratedWidget window);
  virtual ~NativeViewGLSurfaceOSMesa();

  // Implement subset of GLSurface.
  virtual bool Initialize() override;
  virtual void Destroy() override;
  virtual bool IsOffscreen() override;
  virtual bool SwapBuffers() override;
  virtual bool SupportsPostSubBuffer() override;
  virtual bool PostSubBuffer(int x, int y, int width, int height) override;

 private:
  gfx::AcceleratedWidget window_;
  HDC device_context_;

  DISALLOW_COPY_AND_ASSIGN(NativeViewGLSurfaceOSMesa);
};

class WinVSyncProvider : public VSyncProvider {
 public:
  explicit WinVSyncProvider(gfx::AcceleratedWidget window) :
    window_(window)
  {
    use_dwm_ = (base::win::GetVersion() >= base::win::VERSION_WIN7);
  }

  virtual ~WinVSyncProvider() {}

  virtual void GetVSyncParameters(const UpdateVSyncCallback& callback) {
    TRACE_EVENT0("gpu", "WinVSyncProvider::GetVSyncParameters");

    base::TimeTicks timebase;
    base::TimeDelta interval;
    bool dwm_active = false;

    // Query the DWM timing info first if available. This will provide the most
    // precise values.
    if (use_dwm_) {
      DWM_TIMING_INFO timing_info;
      timing_info.cbSize = sizeof(timing_info);
      HRESULT result = DwmGetCompositionTimingInfo(NULL, &timing_info);
      if (result == S_OK) {
        dwm_active = true;
        if (gfx::FrameTime::TimestampsAreHighRes()) {
          // qpcRefreshPeriod is very accurate but noisy, and must be used with
          // a high resolution timebase to avoid frequently missing Vsync.
          timebase = gfx::FrameTime::FromQPCValue(
              static_cast<LONGLONG>(timing_info.qpcVBlank));
          interval = base::TimeDelta::FromQPCValue(
              static_cast<LONGLONG>(timing_info.qpcRefreshPeriod));
        } else if (timing_info.rateRefresh.uiDenominator > 0 &&
            timing_info.rateRefresh.uiNumerator > 0) {
          // If FrameTime is not high resolution, we do not want to translate
          // the QPC value provided by DWM into the low-resolution timebase,
          // which would be error prone and jittery. As a fallback, we assume
          // the timebase is zero and use rateRefresh, which may be rounded but
          // isn't noisy like qpcRefreshPeriod, instead. The fact that we don't
          // have a timebase here may lead to brief periods of jank when our
          // scheduling becomes offset from the hardware vsync.

          // Swap the numerator/denominator to convert frequency to period.
          interval = base::TimeDelta::FromMicroseconds(
              timing_info.rateRefresh.uiDenominator *
              base::Time::kMicrosecondsPerSecond /
              timing_info.rateRefresh.uiNumerator);
        }
      }
    }

    if (!dwm_active) {
      // When DWM compositing is active all displays are normalized to the
      // refresh rate of the primary display, and won't composite any faster.
      // If DWM compositing is disabled, though, we can use the refresh rates
      // reported by each display, which will help systems that have mis-matched
      // displays that run at different frequencies.
      HMONITOR monitor = MonitorFromWindow(window_, MONITOR_DEFAULTTONEAREST);
      MONITORINFOEX monitor_info;
      monitor_info.cbSize = sizeof(MONITORINFOEX);
      BOOL result = GetMonitorInfo(monitor, &monitor_info);
      if (result) {
        DEVMODE display_info;
        display_info.dmSize = sizeof(DEVMODE);
        display_info.dmDriverExtra = 0;
        result = EnumDisplaySettings(monitor_info.szDevice,
            ENUM_CURRENT_SETTINGS, &display_info);
        if (result && display_info.dmDisplayFrequency > 1) {
          interval = base::TimeDelta::FromMicroseconds(
              (1.0 / static_cast<double>(display_info.dmDisplayFrequency)) *
              base::Time::kMicrosecondsPerSecond);
        }
      }
    }

    if (interval.ToInternalValue() != 0) {
      callback.Run(timebase, interval);
    }
  }

 private:
  DISALLOW_COPY_AND_ASSIGN(WinVSyncProvider);

  gfx::AcceleratedWidget window_;
  bool use_dwm_;
};

// Helper routine that does one-off initialization like determining the
// pixel format.
bool GLSurface::InitializeOneOffInternal() {
  switch (GetGLImplementation()) {
    case kGLImplementationDesktopGL:
      if (!GLSurfaceWGL::InitializeOneOff()) {
        LOG(ERROR) << "GLSurfaceWGL::InitializeOneOff failed.";
        return false;
      }
      break;
    case kGLImplementationEGLGLES2:
      if (!GLSurfaceEGL::InitializeOneOff()) {
        LOG(ERROR) << "GLSurfaceEGL::InitializeOneOff failed.";
        return false;
      }
      break;
  }
  return true;
}

NativeViewGLSurfaceOSMesa::NativeViewGLSurfaceOSMesa(
    gfx::AcceleratedWidget window)
    : GLSurfaceOSMesa(OSMesaSurfaceFormatRGBA, gfx::Size(1, 1)),
      window_(window),
      device_context_(NULL) {
  DCHECK(window);
}

NativeViewGLSurfaceOSMesa::~NativeViewGLSurfaceOSMesa() {
  Destroy();
}

bool NativeViewGLSurfaceOSMesa::Initialize() {
  if (!GLSurfaceOSMesa::Initialize())
    return false;

  device_context_ = GetDC(window_);
  return true;
}

void NativeViewGLSurfaceOSMesa::Destroy() {
  if (window_ && device_context_)
    ReleaseDC(window_, device_context_);

  device_context_ = NULL;

  GLSurfaceOSMesa::Destroy();
}

bool NativeViewGLSurfaceOSMesa::IsOffscreen() {
  return false;
}

bool NativeViewGLSurfaceOSMesa::SwapBuffers() {
  DCHECK(device_context_);

  gfx::Size size = GetSize();

  // Note: negating the height below causes GDI to treat the bitmap data as row
  // 0 being at the top.
  BITMAPV4HEADER info = { sizeof(BITMAPV4HEADER) };
  info.bV4Width = size.width();
  info.bV4Height = -size.height();
  info.bV4Planes = 1;
  info.bV4BitCount = 32;
  info.bV4V4Compression = BI_BITFIELDS;
  info.bV4RedMask = 0x000000FF;
  info.bV4GreenMask = 0x0000FF00;
  info.bV4BlueMask = 0x00FF0000;
  info.bV4AlphaMask = 0xFF000000;

  // Copy the back buffer to the window's device context. Do not check whether
  // StretchDIBits succeeds or not. It will fail if the window has been
  // destroyed but it is preferable to allow rendering to silently fail if the
  // window is destroyed. This is because the primary application of this
  // class of GLContext is for testing and we do not want every GL related ui /
  // browser test to become flaky if there is a race condition between GL
  // context destruction and window destruction.
  StretchDIBits(device_context_,
                0, 0, size.width(), size.height(),
                0, 0, size.width(), size.height(),
                GetHandle(),
                reinterpret_cast<BITMAPINFO*>(&info),
                DIB_RGB_COLORS,
                SRCCOPY);

  return true;
}

bool NativeViewGLSurfaceOSMesa::SupportsPostSubBuffer() {
  return true;
}

bool NativeViewGLSurfaceOSMesa::PostSubBuffer(
    int x, int y, int width, int height) {
  DCHECK(device_context_);

  gfx::Size size = GetSize();

  // Note: negating the height below causes GDI to treat the bitmap data as row
  // 0 being at the top.
  BITMAPV4HEADER info = { sizeof(BITMAPV4HEADER) };
  info.bV4Width = size.width();
  info.bV4Height = -size.height();
  info.bV4Planes = 1;
  info.bV4BitCount = 32;
  info.bV4V4Compression = BI_BITFIELDS;
  info.bV4RedMask = 0x000000FF;
  info.bV4GreenMask = 0x0000FF00;
  info.bV4BlueMask = 0x00FF0000;
  info.bV4AlphaMask = 0xFF000000;

  // Copy the back buffer to the window's device context. Do not check whether
  // StretchDIBits succeeds or not. It will fail if the window has been
  // destroyed but it is preferable to allow rendering to silently fail if the
  // window is destroyed. This is because the primary application of this
  // class of GLContext is for testing and we do not want every GL related ui /
  // browser test to become flaky if there is a race condition between GL
  // context destruction and window destruction.
  StretchDIBits(device_context_,
                x, size.height() - y - height, width, height,
                x, y, width, height,
                GetHandle(),
                reinterpret_cast<BITMAPINFO*>(&info),
                DIB_RGB_COLORS,
                SRCCOPY);

  return true;
}

scoped_refptr<GLSurface> GLSurface::CreateViewGLSurface(
    gfx::AcceleratedWidget window) {
  TRACE_EVENT0("gpu", "GLSurface::CreateViewGLSurface");
  switch (GetGLImplementation()) {
    case kGLImplementationOSMesaGL: {
      scoped_refptr<GLSurface> surface(
          new NativeViewGLSurfaceOSMesa(window));
      if (!surface->Initialize())
        return NULL;

      return surface;
    }
    case kGLImplementationEGLGLES2: {
      DCHECK(window != gfx::kNullAcceleratedWidget);
      scoped_refptr<NativeViewGLSurfaceEGL> surface(
          new NativeViewGLSurfaceEGL(window));
      scoped_ptr<VSyncProvider> sync_provider;
      sync_provider.reset(new WinVSyncProvider(window));
      if (!surface->Initialize(sync_provider.Pass()))
        return NULL;

      return surface;
    }
    case kGLImplementationDesktopGL: {
      scoped_refptr<GLSurface> surface(new NativeViewGLSurfaceWGL(
          window));
      if (!surface->Initialize())
        return NULL;

      return surface;
    }
    case kGLImplementationMockGL:
      return new GLSurfaceStub;
    default:
      NOTREACHED();
      return NULL;
  }
}

scoped_refptr<GLSurface> GLSurface::CreateOffscreenGLSurface(
    const gfx::Size& size) {
  TRACE_EVENT0("gpu", "GLSurface::CreateOffscreenGLSurface");
  switch (GetGLImplementation()) {
    case kGLImplementationOSMesaGL: {
      scoped_refptr<GLSurface> surface(
          new GLSurfaceOSMesa(OSMesaSurfaceFormatRGBA, size));
      if (!surface->Initialize())
        return NULL;

      return surface;
    }
    case kGLImplementationEGLGLES2: {
      scoped_refptr<GLSurface> surface(new PbufferGLSurfaceEGL(size));
      if (!surface->Initialize())
        return NULL;

      return surface;
    }
    case kGLImplementationDesktopGL: {
      scoped_refptr<GLSurface> surface(new PbufferGLSurfaceWGL(size));
      if (!surface->Initialize())
        return NULL;

      return surface;
    }
    case kGLImplementationMockGL:
      return new GLSurfaceStub;
    default:
      NOTREACHED();
      return NULL;
  }
}

EGLNativeDisplayType GetPlatformDefaultEGLNativeDisplay() {
  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableD3D11) ||
      CommandLine::ForCurrentProcess()->HasSwitch(switches::kUseWarp))
    return GetDC(NULL);
  return EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE;
}

}  // namespace gfx
<|endoftext|>


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

#include "gtest/gtest.h"

#include "util.h"

#include <string>

using sopmq::shared::util;

TEST(UtilTest, HexEncoderWorks)
{
    std::string testStr("abcde");

    std::string result = util::hex_encode((const unsigned char*)testStr.c_str(), testStr.size());

    ASSERT_EQ("6162636465", result);
}<commit_msg>Add additional test for the random bytes utility<commit_after>/*
 * SOPMQ - Scalable optionally persistent message queue
 * Copyright 2014 InWorldz, LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "gtest/gtest.h"

#include "util.h"

#include <string>

using sopmq::shared::util;

TEST(UtilTest, HexEncoderWorks)
{
    std::string testStr("abcde");

    std::string result = util::hex_encode((const unsigned char*)testStr.c_str(), testStr.size());

    ASSERT_EQ("6162636465", result);
}

TEST(UtilTest, RandomBytes)
{
    std::string bytes = util::random_bytes(1024);
    ASSERT_EQ(1024, bytes.length());
}<|endoftext|>


<commit_before>#include "Test.h"

#include <string>

using namespace std;

extern "C" char *test_strstr(const char *, const char *);

class StrstrTest : public evil::Test {};

TEST_F(StrstrTest, null_str) {
    evil::UBChecker checker{1};
    ASSERT_EQ(NULL, test_strstr(NULL, ""));
}

TEST_F(StrstrTest, empty_str) {
    string s = "a";
    ASSERT_EQ(&s[0], test_strstr(&s[0], ""));
}

TEST_F(StrstrTest, no_occurrences) {
    string s = "a";
    ASSERT_EQ(NULL, test_strstr(&s[0], "b"));
    ASSERT_EQ(NULL, test_strstr(&s[0], "ab"));
}

TEST_F(StrstrTest, single_occurrence) {
    string s = "abc";
    ASSERT_EQ(&s[1], test_strstr(&s[0], "b"));
    ASSERT_EQ(&s[1], test_strstr(&s[0], "bc"));
    ASSERT_EQ(&s[0], test_strstr(&s[0], "ab"));
}

TEST_F(StrstrTest, multiple_occurrence) {
    string s = "abab";
    ASSERT_EQ(&s[0], test_strstr(&s[0], "a"));
    ASSERT_EQ(&s[0], test_strstr(&s[0], "ab"));
}
<commit_msg>Improve strstr tests<commit_after>#include "Test.h"

#include <string>

using namespace std;

extern "C" char *test_strstr(const char *, const char *);

class StrstrTest : public evil::Test {};

TEST_F(StrstrTest, null_str) {
    {
        evil::UBChecker checker{1};
        ASSERT_EQ(NULL, test_strstr(NULL, ""));
    }
    {
        evil::UBChecker checker{1};
        ASSERT_EQ(NULL, test_strstr("", NULL));
    }
    {
        evil::UBChecker checker{1};
        ASSERT_EQ(NULL, test_strstr(NULL, NULL));
    }
}

TEST_F(StrstrTest, empty_str) {
    string s = "a";
    ASSERT_EQ(&s[0], test_strstr(&s[0], ""));
}

TEST_F(StrstrTest, no_occurrences) {
    string s = "a";
    ASSERT_EQ(NULL, test_strstr(&s[0], "b"));
    ASSERT_EQ(NULL, test_strstr(&s[0], "ab"));
}

TEST_F(StrstrTest, single_occurrence) {
    string s = "abc";
    ASSERT_EQ(&s[1], test_strstr(&s[0], "b"));
    ASSERT_EQ(&s[1], test_strstr(&s[0], "bc"));
    ASSERT_EQ(&s[0], test_strstr(&s[0], "ab"));
}

TEST_F(StrstrTest, multiple_occurrence) {
    string s = "abab";
    ASSERT_EQ(&s[0], test_strstr(&s[0], "a"));
    ASSERT_EQ(&s[0], test_strstr(&s[0], "ab"));
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2013, Arvid Norberg
All rights reserved.

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.
    * Neither the name of the author nor the names of its
      contributors may 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 "libtorrent/session.hpp"
#include "test.hpp"
#include "setup_transfer.hpp"
#include "libtorrent/create_torrent.hpp"
#include <sys/stat.h> // for chmod
static const int file_sizes[] =
{ 5, 16 - 5, 16000, 17, 10, 8000, 8000, 1,1,1,1,1,100,1,1,1,1,100,1,1,1,1,1,1
	,1,1,1,1,1,1,13,65000,34,75,2,30,400,500,23000,900,43000,400,4300,6, 4};
const int num_files = sizeof(file_sizes)/sizeof(file_sizes[0]);

enum
{
	// make sure we don't accidentally require files to be writable just to
	// check their hashes
	read_only_files = 1,

	// make sure we detect corrupt files and mark the appropriate pieces
	// as not had
	corrupt_files = 2,
};

void test_checking(int flags = read_only_files)
{
	using namespace libtorrent;
	namespace lt = libtorrent;

	fprintf(stderr, "==== TEST CHECKING %s%s=====\n"
		, (flags & read_only_files) ? "read-only-files ":""
		, (flags & corrupt_files) ? "corrupt ":"");

	// make the files writable again
	for (int i = 0; i < num_files; ++i)
	{
		char name[1024];
		snprintf(name, sizeof(name), "test%d", i);
		std::string path = combine_path("tmp1_checking", "test_torrent_dir");
		path = combine_path(path, name);
#ifdef TORRENT_WINDOWS
		SetFileAttributesA(path.c_str(), FILE_ATTRIBUTE_NORMAL);
#else
		chmod(path.c_str(), S_IRUSR | S_IWUSR);
#endif
	}

	// in case the previous run was terminated
	error_code ec;
	remove_all("tmp1_checking", ec);
	if (ec) fprintf(stderr, "ERROR: removing tmp1_checking: (%d) %s\n"
		, ec.value(), ec.message().c_str());

	create_directory("tmp1_checking", ec);
	if (ec) fprintf(stderr, "ERROR: creating directory tmp1_checking: (%d) %s\n"
		, ec.value(), ec.message().c_str());
	create_directory(combine_path("tmp1_checking", "test_torrent_dir"), ec);
	if (ec) fprintf(stderr, "ERROR: creating directory test_torrent_dir: (%d) %s\n"
		, ec.value(), ec.message().c_str());

	file_storage fs;
	std::srand(10);
	int piece_size = 0x4000;

	create_random_files(combine_path("tmp1_checking", "test_torrent_dir"), file_sizes, num_files);

	add_files(fs, combine_path("tmp1_checking", "test_torrent_dir"));
	libtorrent::create_torrent t(fs, piece_size, 0x4000, libtorrent::create_torrent::optimize);

	// calculate the hash for all pieces
	set_piece_hashes(t, "tmp1_checking", ec);
	if (ec) fprintf(stderr, "ERROR: set_piece_hashes: (%d) %s\n"
		, ec.value(), ec.message().c_str());

	std::vector<char> buf;
	bencode(std::back_inserter(buf), t.generate());
	boost::shared_ptr<torrent_info> ti(new torrent_info(&buf[0], buf.size(), ec));

	fprintf(stderr, "generated torrent: %s tmp1_checking/test_torrent_dir\n"
		, to_hex(ti->info_hash().to_string()).c_str());

	// overwrite the files with new random data
	if (flags & corrupt_files)
	{
		fprintf(stderr, "corrupt file test. overwriting files\n");
		// increase the size of some files. When they're read only that forces
		// the checker to open them in write-mode to truncate them
		static const int file_sizes2[] =
		{ 5, 16 - 5, 16001, 30, 10, 8000, 8000, 1,1,1,1,1,100,1,1,1,1,100,1,1,1,1,1,1
			,1,1,1,1,1,1,13,65000,34,75,2,30,400,500,23000,900,43000,400,4300,6, 4};
		create_random_files(combine_path("tmp1_checking", "test_torrent_dir"), file_sizes2, num_files);
	}

	// make the files read only
	if (flags & read_only_files)
	{
		fprintf(stderr, "making files read-only\n");
		for (int i = 0; i < num_files; ++i)
		{
			char name[1024];
			snprintf(name, sizeof(name), "test%d", i);
			char dirname[200];
			snprintf(dirname, sizeof(dirname), "test_dir%d", i / 5);

			std::string path = combine_path(combine_path("tmp1_checking", "test_torrent_dir"), dirname);
			path = combine_path(path, name);
			fprintf(stderr, "   %s\n", path.c_str());

#ifdef TORRENT_WINDOWS
			SetFileAttributesA(path.c_str(), FILE_ATTRIBUTE_READONLY);
#else
			chmod(path.c_str(), S_IRUSR);
#endif
		}
	}

	settings_pack pack;
	pack.set_int(settings_pack::alert_mask, alert::all_categories);
	pack.set_str(settings_pack::listen_interfaces, "0.0.0.0:48000");
	pack.set_int(settings_pack::max_retry_port_bind, 1000);
	lt::session ses1(pack, fingerprint("LT", 0, 1, 0, 0));

	add_torrent_params p;
	p.save_path = "tmp1_checking";
	p.ti = ti;
	torrent_handle tor1 = ses1.add_torrent(p, ec);
	TEST_CHECK(!ec);

	torrent_status st;
	for (int i = 0; i < 5; ++i)
	{
		print_alerts(ses1, "ses1");

		st = tor1.status();

		printf("%d %f %s\n", st.state, st.progress_ppm / 10000.f, st.error.c_str());

		if (
#ifndef TORRENT_NO_DEPRECATE
			st.state != torrent_status::queued_for_checking &&
#endif
			st.state != torrent_status::checking_files
			&& st.state != torrent_status::checking_resume_data)
			break;

		if (!st.error.empty()) break;
		test_sleep(1000);
	}
	if (flags & corrupt_files)
	{
		TEST_CHECK(!st.is_seeding);

		if (read_only_files)
		{
			// we expect our checking of the files to trigger
			// attempts to truncate them, since the files are
			// read-only here, we expect the checking to fail.
			TEST_CHECK(!st.error.empty());
			if (!st.error.empty())
				fprintf(stderr, "error: %s\n", st.error.c_str());

			// wait a while to make sure libtorrent survived the error
			test_sleep(1000);

			st = tor1.status();
			TEST_CHECK(!st.is_seeding);
			TEST_CHECK(!st.error.empty());
			if (!st.error.empty())
				fprintf(stderr, "error: %s\n", st.error.c_str());
		}
		else
		{
			TEST_CHECK(st.error.empty());
			if (!st.error.empty())
				fprintf(stderr, "error: %s\n", st.error.c_str());
		}
	}
	else
	{
		TEST_CHECK(st.is_seeding);
	}

	// make the files writable again
	if (flags & read_only_files)
	{
		for (int i = 0; i < num_files; ++i)
		{
			char name[1024];
			snprintf(name, sizeof(name), "test%d", i);
			char dirname[200];
			snprintf(dirname, sizeof(dirname), "test_dir%d", i / 5);

			std::string path = combine_path(combine_path("tmp1_checking", "test_torrent_dir"), dirname);
			path = combine_path(path, name);
#ifdef TORRENT_WINDOWS
			SetFileAttributesA(path.c_str(), FILE_ATTRIBUTE_NORMAL);
#else
			chmod(path.c_str(), S_IRUSR | S_IWUSR);
#endif
		}
	}

	remove_all("tmp1_checking", ec);
	if (ec) fprintf(stderr, "ERROR: removing tmp1_checking: (%d) %s\n"
		, ec.value(), ec.message().c_str());
}

int test_main()
{
	test_checking();
	test_checking(read_only_files);
	test_checking(read_only_files | corrupt_files);
	test_checking(corrupt_files);

	return 0;
}

<commit_msg>fix test_checking<commit_after>/*

Copyright (c) 2013, Arvid Norberg
All rights reserved.

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.
    * Neither the name of the author nor the names of its
      contributors may 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 "libtorrent/session.hpp"
#include "test.hpp"
#include "setup_transfer.hpp"
#include "libtorrent/create_torrent.hpp"
#include <sys/stat.h> // for chmod
static const int file_sizes[] =
{ 5, 16 - 5, 16000, 17, 10, 8000, 8000, 1,1,1,1,1,100,1,1,1,1,100,1,1,1,1,1,1
	,1,1,1,1,1,1,13,65000,34,75,2,30,400,500,23000,900,43000,400,4300,6, 4};
const int num_files = sizeof(file_sizes)/sizeof(file_sizes[0]);

enum
{
	// make sure we don't accidentally require files to be writable just to
	// check their hashes
	read_only_files = 1,

	// make sure we detect corrupt files and mark the appropriate pieces
	// as not had
	corrupt_files = 2,
};

void test_checking(int flags = read_only_files)
{
	using namespace libtorrent;
	namespace lt = libtorrent;

	fprintf(stderr, "==== TEST CHECKING %s%s=====\n"
		, (flags & read_only_files) ? "read-only-files ":""
		, (flags & corrupt_files) ? "corrupt ":"");

	// make the files writable again
	for (int i = 0; i < num_files; ++i)
	{
		char name[1024];
		snprintf(name, sizeof(name), "test%d", i);
		std::string path = combine_path("tmp1_checking", "test_torrent_dir");
		path = combine_path(path, name);
#ifdef TORRENT_WINDOWS
		SetFileAttributesA(path.c_str(), FILE_ATTRIBUTE_NORMAL);
#else
		chmod(path.c_str(), S_IRUSR | S_IWUSR);
#endif
	}

	// in case the previous run was terminated
	error_code ec;
	remove_all("tmp1_checking", ec);
	if (ec) fprintf(stderr, "ERROR: removing tmp1_checking: (%d) %s\n"
		, ec.value(), ec.message().c_str());

	create_directory("tmp1_checking", ec);
	if (ec) fprintf(stderr, "ERROR: creating directory tmp1_checking: (%d) %s\n"
		, ec.value(), ec.message().c_str());
	create_directory(combine_path("tmp1_checking", "test_torrent_dir"), ec);
	if (ec) fprintf(stderr, "ERROR: creating directory test_torrent_dir: (%d) %s\n"
		, ec.value(), ec.message().c_str());

	file_storage fs;
	std::srand(10);
	int piece_size = 0x4000;

	create_random_files(combine_path("tmp1_checking", "test_torrent_dir"), file_sizes, num_files);

	add_files(fs, combine_path("tmp1_checking", "test_torrent_dir"));
	libtorrent::create_torrent t(fs, piece_size, 0x4000, libtorrent::create_torrent::optimize);

	// calculate the hash for all pieces
	set_piece_hashes(t, "tmp1_checking", ec);
	if (ec) fprintf(stderr, "ERROR: set_piece_hashes: (%d) %s\n"
		, ec.value(), ec.message().c_str());

	std::vector<char> buf;
	bencode(std::back_inserter(buf), t.generate());
	boost::shared_ptr<torrent_info> ti(new torrent_info(&buf[0], buf.size(), ec));

	fprintf(stderr, "generated torrent: %s tmp1_checking/test_torrent_dir\n"
		, to_hex(ti->info_hash().to_string()).c_str());

	// overwrite the files with new random data
	if (flags & corrupt_files)
	{
		fprintf(stderr, "corrupt file test. overwriting files\n");
		// increase the size of some files. When they're read only that forces
		// the checker to open them in write-mode to truncate them
		static const int file_sizes2[] =
		{ 5, 16 - 5, 16001, 30, 10, 8000, 8000, 1,1,1,1,1,100,1,1,1,1,100,1,1,1,1,1,1
			,1,1,1,1,1,1,13,65000,34,75,2,30,400,500,23000,900,43000,400,4300,6, 4};
		create_random_files(combine_path("tmp1_checking", "test_torrent_dir"), file_sizes2, num_files);
	}

	// make the files read only
	if (flags & read_only_files)
	{
		fprintf(stderr, "making files read-only\n");
		for (int i = 0; i < num_files; ++i)
		{
			char name[1024];
			snprintf(name, sizeof(name), "test%d", i);
			char dirname[200];
			snprintf(dirname, sizeof(dirname), "test_dir%d", i / 5);

			std::string path = combine_path(combine_path("tmp1_checking", "test_torrent_dir"), dirname);
			path = combine_path(path, name);
			fprintf(stderr, "   %s\n", path.c_str());

#ifdef TORRENT_WINDOWS
			SetFileAttributesA(path.c_str(), FILE_ATTRIBUTE_READONLY);
#else
			chmod(path.c_str(), S_IRUSR);
#endif
		}
	}

	settings_pack pack;
	pack.set_int(settings_pack::alert_mask, alert::all_categories);
	pack.set_str(settings_pack::listen_interfaces, "0.0.0.0:48000");
	pack.set_int(settings_pack::max_retry_port_bind, 1000);
	lt::session ses1(pack, fingerprint("LT", 0, 1, 0, 0));

	add_torrent_params p;
	p.save_path = "tmp1_checking";
	p.ti = ti;
	torrent_handle tor1 = ses1.add_torrent(p, ec);
	TEST_CHECK(!ec);

	torrent_status st;
	for (int i = 0; i < 5; ++i)
	{
		print_alerts(ses1, "ses1");

		st = tor1.status();

		printf("%d %f %s\n", st.state, st.progress_ppm / 10000.f, st.error.c_str());

		if (
#ifndef TORRENT_NO_DEPRECATE
			st.state != torrent_status::queued_for_checking &&
#endif
			st.state != torrent_status::checking_files
			&& st.state != torrent_status::checking_resume_data)
			break;

		if (!st.error.empty()) break;
		test_sleep(1000);
	}
	if (flags & corrupt_files)
	{
		TEST_CHECK(!st.is_seeding);

		if (flags & read_only_files)
		{
			// we expect our checking of the files to trigger
			// attempts to truncate them, since the files are
			// read-only here, we expect the checking to fail.
			TEST_CHECK(!st.error.empty());
			if (!st.error.empty())
				fprintf(stderr, "error: %s\n", st.error.c_str());

			// wait a while to make sure libtorrent survived the error
			test_sleep(1000);

			st = tor1.status();
			TEST_CHECK(!st.is_seeding);
			TEST_CHECK(!st.error.empty());
			if (!st.error.empty())
				fprintf(stderr, "error: %s\n", st.error.c_str());
		}
		else
		{
			TEST_CHECK(st.error.empty());
			if (!st.error.empty())
				fprintf(stderr, "error: %s\n", st.error.c_str());
		}
	}
	else
	{
		TEST_CHECK(st.is_seeding);
	}

	// make the files writable again
	if (flags & read_only_files)
	{
		for (int i = 0; i < num_files; ++i)
		{
			char name[1024];
			snprintf(name, sizeof(name), "test%d", i);
			char dirname[200];
			snprintf(dirname, sizeof(dirname), "test_dir%d", i / 5);

			std::string path = combine_path(combine_path("tmp1_checking", "test_torrent_dir"), dirname);
			path = combine_path(path, name);
#ifdef TORRENT_WINDOWS
			SetFileAttributesA(path.c_str(), FILE_ATTRIBUTE_NORMAL);
#else
			chmod(path.c_str(), S_IRUSR | S_IWUSR);
#endif
		}
	}

	remove_all("tmp1_checking", ec);
	if (ec) fprintf(stderr, "ERROR: removing tmp1_checking: (%d) %s\n"
		, ec.value(), ec.message().c_str());
}

int test_main()
{
	test_checking();
	test_checking(read_only_files);
	test_checking(read_only_files | corrupt_files);
	test_checking(corrupt_files);

	return 0;
}

<|endoftext|>


<commit_before>#include "test.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

void log(void* ignored)
{
	printf("Cleanup called on %s\n", *(char**)ignored);
}
#define CLEANUP\
	__attribute__((cleanup(log))) __attribute__((unused))\
		const char *f = __func__;

/**
 * Simple struct to test throwing.
 */
struct foo
{
	int i;
};

struct bar : foo
{
	float bar;
};

static int cleanup_count;
/**
 * Simple structure declared with a destructor.  Destroying this object will
 * increment cleanup count.  The destructor should be called automatically if
 * an instance of cl is allocated with automatic storage.
 */
struct cl
{
	int i;
	~cl() { fprintf(stderr, "cl destroyed: %d\n", i); cleanup_count++; }
};
/**
 * Test that one cl was destroyed when running the argument.
 */
#define TEST_CLEANUP(x) do {\
		int cleanups = cleanup_count;\
		{ x; }\
		TEST(cleanup_count == cleanups+1, "Cleanup ran correctly");\
	} while(0)

int inner(int i)
{
	CLEANUP
	switch (i)
	{
		case 0: throw (int)1.0;
		case 1: throw (float)1.0;
		case 2: throw (int64_t)1;
		case 3: { foo f = {2} ; throw f; }
		case 4: { bar f; f.i = 2 ; f.bar=1 ; throw f; }
	}
	return -1;
}

int outer(int i) throw(float, int, foo)
{
	//CLEANUP
	inner(i);
	return 1;
}

static void test_catch(int s)
{
	cl c;
	c.i = 12;
	fprintf(stderr, "Entering try\n");
	try
	{
		outer(s);
	}
	catch(int i)
	{
		fprintf(stderr, "Caught int %d!\n", i);
		TEST(s == 0 && i == 1, "Caught int");
		return;
	}
	catch (float f)
	{
		fprintf(stderr, "Caught float %f!\n", f);
		TEST(s == 1 && f == 1, "Caught float");
		return;
	}
	catch (foo f)
	{
		fprintf(stderr, "Caught struct {%d}!\n", f.i);
		TEST((s == 3 || s == 4) && f.i == 2, "Caught struct");
		return;
	}
	//abort();
	TEST(0, "Unreachable line reached");
}

void test_nested1(void)
{
	CLEANUP;
	cl c;
	c.i = 123;
	try
	{
		outer(0);
	}
	catch (int a)
	{
		try
		{
			TEST(a == 1, "Caught int");
			outer(1);
		}
		catch (float f)
		{
			TEST(f == 1, "Caught float inside outer catch block");
			throw;
		}
	}
}

void test_nested()
{
	try
	{
		test_nested1();
	}
	catch (float f)
	{
		fprintf(stderr, "Caught re-thrown float\n");
		TEST(f == 1, "Caught re-thrown float");
	}
}
void test_exceptions(void)
{
	TEST_CLEANUP(test_catch(0));
	TEST_CLEANUP(test_catch(1));
	TEST_CLEANUP(test_catch(3));
	TEST_CLEANUP(test_catch(4));
	//test_catch(2);
	TEST_CLEANUP(test_nested());

	//printf("Test: %s\n",
}
<commit_msg>Added test for correctly setting unexpected handler and calling it when an eception spec is violated.<commit_after>#include "test.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

#include <exception>

void log(void* ignored)
{
	printf("Cleanup called on %s\n", *(char**)ignored);
}
#define CLEANUP\
	__attribute__((cleanup(log))) __attribute__((unused))\
		const char *f = __func__;

/**
 * Simple struct to test throwing.
 */
struct foo
{
	int i;
};

struct bar : foo
{
	float bar;
};

static int cleanup_count;
/**
 * Simple structure declared with a destructor.  Destroying this object will
 * increment cleanup count.  The destructor should be called automatically if
 * an instance of cl is allocated with automatic storage.
 */
struct cl
{
	int i;
	~cl() { fprintf(stderr, "cl destroyed: %d\n", i); cleanup_count++; }
};
/**
 * Test that one cl was destroyed when running the argument.
 */
#define TEST_CLEANUP(x) do {\
		int cleanups = cleanup_count;\
		{ x; }\
		TEST(cleanup_count == cleanups+1, "Cleanup ran correctly");\
	} while(0)

int inner(int i)
{
	CLEANUP
	switch (i)
	{
		case 0: throw (int)1.0;
		case 1: throw (float)1.0;
		case 2: throw (int64_t)1;
		case 3: { foo f = {2} ; throw f; }
		case 4: { bar f; f.i = 2 ; f.bar=1 ; throw f; }
	}
	return -1;
}

int outer(int i) throw(float, int, foo)
{
	//CLEANUP
	inner(i);
	return 1;
}

static void test_catch(int s)
{
	cl c;
	c.i = 12;
	fprintf(stderr, "Entering try\n");
	try
	{
		outer(s);
	}
	catch(int i)
	{
		fprintf(stderr, "Caught int %d!\n", i);
		TEST((s == 0 && i == 1) || (s == 2 && i == 0), "Caught int");
		return;
	}
	catch (float f)
	{
		fprintf(stderr, "Caught float %f!\n", f);
		TEST(s == 1 && f == 1, "Caught float");
		return;
	}
	catch (foo f)
	{
		fprintf(stderr, "Caught struct {%d}!\n", f.i);
		TEST((s == 3 || s == 4) && f.i == 2, "Caught struct");
		return;
	}
	//abort();
	TEST(0, "Unreachable line reached");
}

void test_nested1(void)
{
	CLEANUP;
	cl c;
	c.i = 123;
	try
	{
		outer(0);
	}
	catch (int a)
	{
		try
		{
			TEST(a == 1, "Caught int");
			outer(1);
		}
		catch (float f)
		{
			TEST(f == 1, "Caught float inside outer catch block");
			throw;
		}
	}
}

void test_nested()
{
	try
	{
		test_nested1();
	}
	catch (float f)
	{
		fprintf(stderr, "Caught re-thrown float\n");
		TEST(f == 1, "Caught re-thrown float");
	}
}

static void throw_zero()
{
	throw 0;
}

void test_exceptions(void)
{
	TEST_CLEANUP(test_catch(0));
	TEST_CLEANUP(test_catch(1));
	TEST_CLEANUP(test_catch(3));
	TEST_CLEANUP(test_catch(4));
	TEST_CLEANUP(test_nested());
	std::set_unexpected(throw_zero);
	test_catch(2);

	//printf("Test: %s\n",
}
<|endoftext|>