<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2015 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#include "catch.hpp"

#include <mapnik/datasource.hpp>
#include <mapnik/datasource_cache.hpp>
#include <mapnik/util/fs.hpp>
#include <cstdlib>
#include <fstream>
#pragma GCC diagnostic push
#include <mapnik/warning_ignore.hpp>
#include <boost/algorithm/string.hpp>
#pragma GCC diagnostic pop

namespace {

std::size_t count_shapefile_features(std::string const& filename)
{
    mapnik::parameters params;
    params["type"] = "shape";
    params["file"] = filename;
    auto ds = mapnik::datasource_cache::instance().create(params);
    REQUIRE(ds != nullptr);
    CHECK(ds->type() == mapnik::datasource::datasource_t::Vector);
    auto fields = ds->get_descriptor().get_descriptors();
    mapnik::query query(ds->envelope());
    for (auto const& field : fields)
    {
        query.add_property_name(field.get_name());
    }
    auto features = ds->features(query);
    REQUIRE(features != nullptr);

    std::size_t feature_count = 0;
    auto feature = features->next();
    while (feature)
    {
        ++feature_count;
        feature = features->next();
    }

    return feature_count;
}

int create_shapefile_index(std::string const& filename, bool index_parts, bool silent = true)
{
    std::string cmd;
    if (std::getenv("DYLD_LIBRARY_PATH") != nullptr)
    {
        cmd += std::string("DYLD_LIBRARY_PATH=") + std::getenv("DYLD_LIBRARY_PATH") + " ";
    }

    cmd += "shapeindex ";
    if (index_parts) cmd+= "--index-parts ";
    cmd += filename;
    if (silent)
    {
#ifndef _WINDOWS
        cmd += " 2>/dev/null";
#else
        cmd += " 2> nul";
#endif
    }
    return std::system(cmd.c_str());
}

}

TEST_CASE("invalid shapeindex")
{
    std::string shape_plugin("./plugins/input/shape.input");
    if (mapnik::util::exists(shape_plugin))
    {
        SECTION("Invalid index")
        {
            std::string path = "test/data/shp/boundaries.shp";
            std::string index_path = path.substr(0, path.rfind(".")) + ".index";
            // remove *.index if present
            if (mapnik::util::exists(index_path))
            {
                mapnik::util::remove(index_path);
            }
            // count features

            std::size_t feature_count = count_shapefile_features(path);

            // create invalid index
            std::ofstream index(index_path.c_str(), std::ios::binary);
            std::string buf("mapnik-invalid-index.................");
            index.write(buf.c_str(), buf.size());
            index.close();

            // count features
            std::size_t feature_count_indexed = count_shapefile_features(path);
            // ensure number of features are the same
            REQUIRE(feature_count == feature_count_indexed);
            // remove *.index if present
            if (mapnik::util::exists(index_path))
            {
                mapnik::util::remove(index_path);
            }
        }
    }
}

TEST_CASE("shapeindex")
{
    std::string shape_plugin("./plugins/input/shape.input");
    if (mapnik::util::exists(shape_plugin))
    {
        SECTION("Index")
        {
            for (auto const& path : mapnik::util::list_directory("test/data/shp/"))
            {
                if (boost::iends_with(path,".shp"))
                {
                    for (bool index_parts : {false, true} )
                    {
                        CAPTURE(path);
                        CAPTURE(index_parts);

                        std::string index_path = path.substr(0, path.rfind(".")) + ".index";
                        // remove *.index if present
                        if (mapnik::util::exists(index_path))
                        {
                            mapnik::util::remove(index_path);
                        }
                        // count features
                        std::size_t feature_count = count_shapefile_features(path);
                        // create *.index
                        REQUIRE(create_shapefile_index(path, index_parts) == 0);
                        if (feature_count == 0)
                        {
                            REQUIRE(!mapnik::util::exists(index_path)); // index won't be created if there's no features
                        }
                        // count features
                        std::size_t feature_count_indexed = count_shapefile_features(path);
                        // ensure number of features are the same
                        REQUIRE(feature_count == feature_count_indexed);
                        // remove *.index if present
                        if (mapnik::util::exists(index_path))
                        {
                            mapnik::util::remove(index_path);
                        }
                    }
                }
            }
        }
    }
}
<commit_msg>clear mapped_memory_cache to ensure new '*.index` are used (MAPNIK_MEMORY_MAPPED_FILE) (ref #3306)<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2015 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#include "catch.hpp"

#include <mapnik/datasource.hpp>
#include <mapnik/datasource_cache.hpp>
#include <mapnik/mapped_memory_cache.hpp>
#include <mapnik/util/fs.hpp>
#include <cstdlib>
#include <fstream>
#pragma GCC diagnostic push
#include <mapnik/warning_ignore.hpp>
#include <boost/algorithm/string.hpp>
#pragma GCC diagnostic pop

namespace {

std::size_t count_shapefile_features(std::string const& filename)
{
#if defined(MAPNIK_MEMORY_MAPPED_FILE)
    mapnik::mapped_memory_cache::instance().clear();
#endif
    mapnik::parameters params;
    params["type"] = "shape";
    params["file"] = filename;
    auto ds = mapnik::datasource_cache::instance().create(params);
    REQUIRE(ds != nullptr);
    CHECK(ds->type() == mapnik::datasource::datasource_t::Vector);
    auto fields = ds->get_descriptor().get_descriptors();
    mapnik::query query(ds->envelope());
    for (auto const& field : fields)
    {
        query.add_property_name(field.get_name());
    }
    auto features = ds->features(query);
    REQUIRE(features != nullptr);

    std::size_t feature_count = 0;
    auto feature = features->next();
    while (feature)
    {
        ++feature_count;
        feature = features->next();
    }

    return feature_count;
}

int create_shapefile_index(std::string const& filename, bool index_parts, bool silent = true)
{
    std::string cmd;
    if (std::getenv("DYLD_LIBRARY_PATH") != nullptr)
    {
        cmd += std::string("DYLD_LIBRARY_PATH=") + std::getenv("DYLD_LIBRARY_PATH") + " ";
    }

    cmd += "shapeindex ";
    if (index_parts) cmd+= "--index-parts ";
    cmd += filename;
    if (silent)
    {
#ifndef _WINDOWS
        cmd += " 2>/dev/null";
#else
        cmd += " 2> nul";
#endif
    }
    return std::system(cmd.c_str());
}

}

TEST_CASE("invalid shapeindex")
{
    std::string shape_plugin("./plugins/input/shape.input");
    if (mapnik::util::exists(shape_plugin))
    {
        SECTION("Invalid index")
        {
            std::string path = "test/data/shp/boundaries.shp";
            std::string index_path = path.substr(0, path.rfind(".")) + ".index";
            // remove *.index if present
            if (mapnik::util::exists(index_path))
            {
                mapnik::util::remove(index_path);
            }
            // count features

            std::size_t feature_count = count_shapefile_features(path);

            // create invalid index
            std::ofstream index(index_path.c_str(), std::ios::binary);
            std::string buf("mapnik-invalid-index.................");
            index.write(buf.c_str(), buf.size());
            index.close();

            // count features
            std::size_t feature_count_indexed = count_shapefile_features(path);
            // ensure number of features are the same
            REQUIRE(feature_count == feature_count_indexed);
            // remove *.index if present
            if (mapnik::util::exists(index_path))
            {
                mapnik::util::remove(index_path);
            }
        }
    }
}

TEST_CASE("shapeindex")
{
    std::string shape_plugin("./plugins/input/shape.input");
    if (mapnik::util::exists(shape_plugin))
    {
        SECTION("Index")
        {
            for (auto const& path : mapnik::util::list_directory("test/data/shp/"))
            {
                if (boost::iends_with(path,".shp"))
                {
                    for (bool index_parts : {false, true} )
                    {
                        CAPTURE(path);
                        CAPTURE(index_parts);

                        std::string index_path = path.substr(0, path.rfind(".")) + ".index";
                        // remove *.index if present
                        if (mapnik::util::exists(index_path))
                        {
                            mapnik::util::remove(index_path);
                        }
                        // count features
                        std::size_t feature_count = count_shapefile_features(path);
                        // create *.index
                        REQUIRE(create_shapefile_index(path, index_parts) == 0);
                        if (feature_count == 0)
                        {
                            REQUIRE(!mapnik::util::exists(index_path)); // index won't be created if there's no features
                        }
                        // count features
                        std::size_t feature_count_indexed = count_shapefile_features(path);
                        // ensure number of features are the same
                        REQUIRE(feature_count == feature_count_indexed);
                        // remove *.index if present
                        if (mapnik::util::exists(index_path))
                        {
                            mapnik::util::remove(index_path);
                        }
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>/** @file   Scripting.cpp
    @author Philip Abbet

    Implementation of the scripting-related functions of the Athena-Entities module
*/

#include <Athena-Entities/Scripting.h>
#include <Athena-Entities/Transforms.h>
#include <Athena-Entities/ComponentsList.h>
#include <Athena-Scripting/ScriptingManager.h>
#include <Athena-Scripting/Utils.h>
#include <string>

using namespace Athena::Entities;
using namespace Athena::Scripting;
using namespace v8;

namespace Athena {
namespace Entities {

//-----------------------------------------------------------------------

Animation* fromJSAnimation(Handle<Value> value)
{
    if (value->IsObject())
    {
        Animation* pAnimation = 0;
        GetObjectPtr(value, &pAnimation);
        return pAnimation;
    }

    return 0;
}

//-----------------------------------------------------------------------

Handle<Object> createJSAnimation()
{
    HandleScope handle_scope;

    Handle<FunctionTemplate> func = ScriptingManager::getSingletonPtr()->getClassTemplate(
                                                        "Athena.Entities.Animation");

    Handle<Object> jsAnimation = func->GetFunction()->NewInstance();

    return handle_scope.Close(jsAnimation);
}

//-----------------------------------------------------------------------

Handle<Value> toJavaScript(Animation* pAnimation)
{
    HandleScope handle_scope;

    if (!pAnimation)
        return Handle<Value>();

    Handle<FunctionTemplate> func = ScriptingManager::getSingletonPtr()->getClassTemplate(
                                                        "Athena.Entities.Animation");

    Handle<Value> argv[1];
    argv[0] = External::Wrap(pAnimation);

    Handle<Object> jsAnimation = func->GetFunction()->NewInstance(1, argv);

    return handle_scope.Close(jsAnimation);
}

//-----------------------------------------------------------------------

AnimationsMixer* fromJSAnimationsMixer(Handle<Value> value)
{
    if (value->IsObject())
    {
        AnimationsMixer* pMixer = 0;
        GetObjectPtr(value, &pMixer);
        return pMixer;
    }

    return 0;
}

//-----------------------------------------------------------------------

Handle<Object> createJSAnimationsMixer()
{
    HandleScope handle_scope;

    Handle<FunctionTemplate> func = ScriptingManager::getSingletonPtr()->getClassTemplate(
                                                        "Athena.Entities.AnimationsMixer");

    Handle<Object> jsAnimationsMixer = func->GetFunction()->NewInstance();

    return handle_scope.Close(jsAnimationsMixer);
}

//-----------------------------------------------------------------------

Handle<Value> toJavaScript(AnimationsMixer* pMixer)
{
    HandleScope handle_scope;

    if (!pMixer)
        return Handle<Value>();

    Handle<FunctionTemplate> func = ScriptingManager::getSingletonPtr()->getClassTemplate(
                                                        "Athena.Entities.AnimationsMixer");

    Handle<Value> argv[1];
    argv[0] = External::Wrap(pMixer);

    Handle<Object> jsAnimationsMixer = func->GetFunction()->NewInstance(1, argv);

    return handle_scope.Close(jsAnimationsMixer);
}

//-----------------------------------------------------------------------

ComponentAnimation* fromJSComponentAnimation(Handle<Value> value)
{
    if (value->IsObject())
    {
        ComponentAnimation* pComponentAnimation = 0;
        GetObjectPtr(value, &pComponentAnimation);
        return pComponentAnimation;
    }

    return 0;
}

//-----------------------------------------------------------------------

Handle<Object> createJSComponentAnimation()
{
    HandleScope handle_scope;

    Handle<FunctionTemplate> func = ScriptingManager::getSingletonPtr()->getClassTemplate(
                                                        "Athena.Entities.ComponentAnimation");

    Handle<Object> jsComponentAnimation = func->GetFunction()->NewInstance();

    return handle_scope.Close(jsComponentAnimation);
}

//-----------------------------------------------------------------------

Handle<Value> toJavaScript(ComponentAnimation* pComponentAnimation)
{
    HandleScope handle_scope;

    if (!pComponentAnimation)
        return Handle<Value>();

    Handle<FunctionTemplate> func = ScriptingManager::getSingletonPtr()->getClassTemplate(
                                                        "Athena.Entities.ComponentAnimation");

    Handle<Value> argv[1];
    argv[0] = External::Wrap(pComponentAnimation);

    Handle<Object> jsComponentAnimation = func->GetFunction()->NewInstance(1, argv);

    return handle_scope.Close(jsComponentAnimation);
}

//-----------------------------------------------------------------------

tComponentID fromJSComponentID(Handle<Value> value)
{
    if (value->IsObject())
    {
        Handle<Object> object = value->ToObject();
        Handle<Function> prototype = Handle<Function>::Cast(object->GetPrototype());

        if (std::string("Athena.Entities.ComponentID") == *String::AsciiValue(prototype->Get(String::New("__classname__"))))
        {
            return tComponentID((tComponentType) object->Get(String::New("type"))->ToNumber()->NumberValue(),
                                *String::AsciiValue(object->Get(String::New("entity"))),
                                *String::AsciiValue(object->Get(String::New("component"))));
        }
    }

    return tComponentID(COMP_NONE);
}

//-----------------------------------------------------------------------

Handle<Value> toJavaScript(const tComponentID& value)
{
    Local<Object> object = ScriptingManager::getSingletonPtr()->execute("new Athena.Entities.ComponentID('" + value.toString() + "');")->ToObject();

    // Handle<Value> constructor = Context::GetCurrent()->Global()->Get(String::New("Athena.Entities.ComponentID"));
    // if (!constructor->IsUndefined())
    //     return ThrowException(String::New("BLAAAAAhD"));
    // if (!constructor->IsFunction())
    //     return ThrowException(String::New("Can't find the constructor function of Athena.Entities.ComponentID"));

    // Local<Object> object = Handle<Function>::Cast(constructor)->NewInstance();

    // object->Set(String::New("type"),      Number::New(value.type));
    // object->Set(String::New("entity"),    String::New(value.strEntity.c_str()));
    // object->Set(String::New("component"), String::New(value.strName.c_str()));

    return object;
}

//-----------------------------------------------------------------------

ComponentsList* fromJSComponentsList(Handle<Value> value)
{
    if (value->IsObject())
    {
        ComponentsList* pList = 0;
        GetObjectPtr(value, &pList);
        return pList;
    }

    return 0;
}

//-----------------------------------------------------------------------

Handle<Object> createJSComponentsList()
{
    HandleScope handle_scope;

    Handle<FunctionTemplate> func = ScriptingManager::getSingletonPtr()->getClassTemplate(
                                                        "Athena.Entities.ComponentsList");

    Handle<Object> jsList = func->GetFunction()->NewInstance();

    return handle_scope.Close(jsList);
}

//-----------------------------------------------------------------------

Handle<Value> toJavaScript(ComponentsList* pList)
{
    HandleScope handle_scope;

    if (!pList)
        return Handle<Value>();

    Handle<FunctionTemplate> func = ScriptingManager::getSingletonPtr()->getClassTemplate(
                                                        "Athena.Entities.ComponentsList");

    Handle<Value> argv[1];
    argv[0] = External::Wrap(pList);

    Handle<Object> jsList = func->GetFunction()->NewInstance(1, argv);

    return handle_scope.Close(jsList);
}

//-----------------------------------------------------------------------

Component* fromJSComponent(Handle<Value> value)
{
    if (value->IsObject())
    {
        Component* pComponent = 0;
        GetObjectPtr(value, &pComponent);
        return pComponent;
    }

    return 0;
}

//-----------------------------------------------------------------------

Handle<Object> createJSComponent()
{
    HandleScope handle_scope;

    Handle<FunctionTemplate> func = ScriptingManager::getSingletonPtr()->getClassTemplate(
                                                        "Athena.Entities.Component");

    Handle<Object> jsComponent = func->GetFunction()->NewInstance();

    return handle_scope.Close(jsComponent);
}

//-----------------------------------------------------------------------

Handle<Value> toJavaScript(Component* pComponent)
{
    HandleScope handle_scope;

    if (!pComponent)
        return Handle<Value>();

    Handle<FunctionTemplate> func = ScriptingManager::getSingletonPtr()->getClassTemplate(
                                                        "Athena.Entities.Component");

    Handle<Value> argv[1];
    argv[0] = External::Wrap(pComponent);

    Handle<Object> jsComponent = func->GetFunction()->NewInstance(1, argv);

    return handle_scope.Close(jsComponent);
}

//-----------------------------------------------------------------------

Entity* fromJSEntity(Handle<Value> value)
{
    if (value->IsObject())
    {
        Entity* pEntity = 0;
        GetObjectPtr(value, &pEntity);
        return pEntity;
    }

    return 0;
}

//-----------------------------------------------------------------------

Handle<Object> createJSEntity()
{
    HandleScope handle_scope;

    Handle<FunctionTemplate> func = ScriptingManager::getSingletonPtr()->getClassTemplate(
                                                        "Athena.Entities.Entity");

    Handle<Object> jsEntity = func->GetFunction()->NewInstance();

    return handle_scope.Close(jsEntity);
}

//-----------------------------------------------------------------------

Handle<Value> toJavaScript(Entity* pEntity)
{
    HandleScope handle_scope;

    if (!pEntity)
        return Handle<Value>();

    Handle<FunctionTemplate> func = ScriptingManager::getSingletonPtr()->getClassTemplate(
                                                        "Athena.Entities.Entity");

    Handle<Value> argv[1];
    argv[0] = External::Wrap(pEntity);

    Handle<Object> jsEntity = func->GetFunction()->NewInstance(1, argv);

    return handle_scope.Close(jsEntity);
}

//-----------------------------------------------------------------------

Scene* fromJSScene(Handle<Value> value)
{
    if (value->IsObject())
    {
        Scene* pScene = 0;
        GetObjectPtr(value, &pScene);
        return pScene;
    }

    return 0;
}

//-----------------------------------------------------------------------

Handle<Object> createJSScene()
{
    HandleScope handle_scope;

    Handle<FunctionTemplate> func = ScriptingManager::getSingletonPtr()->getClassTemplate(
                                                        "Athena.Entities.Scene");

    Handle<Object> jsScene = func->GetFunction()->NewInstance();

    return handle_scope.Close(jsScene);
}

//-----------------------------------------------------------------------

Handle<Value> toJavaScript(Scene* pScene)
{
    HandleScope handle_scope;

    if (!pScene)
        return Handle<Value>();

    Handle<FunctionTemplate> func = ScriptingManager::getSingletonPtr()->getClassTemplate(
                                                        "Athena.Entities.Scene");

    Handle<Value> argv[1];
    argv[0] = External::Wrap(pScene);

    Handle<Object> jsScene = func->GetFunction()->NewInstance(1, argv);

    return handle_scope.Close(jsScene);
}

//-----------------------------------------------------------------------

Transforms* fromJSTransforms(Handle<Value> value)
{
    if (value->IsObject())
    {
        Transforms* pTransforms = 0;
        GetObjectPtr(value, &pTransforms);
        return pTransforms;
    }

    return 0;
}

//-----------------------------------------------------------------------

Handle<Object> createJSTransforms()
{
    HandleScope handle_scope;

    Handle<FunctionTemplate> func = ScriptingManager::getSingletonPtr()->getClassTemplate(
                                                        "Athena.Entities.Transforms");

    Handle<Object> jsTransforms = func->GetFunction()->NewInstance();

    return handle_scope.Close(jsTransforms);
}

//-----------------------------------------------------------------------

Handle<Value> toJavaScript(Transforms* pTransforms)
{
    HandleScope handle_scope;

    if (!pTransforms)
        return Handle<Value>();

    Handle<FunctionTemplate> func = ScriptingManager::getSingletonPtr()->getClassTemplate(
                                                        "Athena.Entities.Transforms");

    Handle<Value> argv[1];
    argv[0] = External::Wrap(pTransforms);

    Handle<Object> jsTransforms = func->GetFunction()->NewInstance(1, argv);

    return handle_scope.Close(jsTransforms);
}

}
}
<commit_msg>[Scripting] Uses macros to implement the C++/JavaScript conversion functions<commit_after>/** @file   Scripting.cpp
    @author Philip Abbet

    Implementation of the scripting-related functions of the Athena-Entities module
*/

#include <Athena-Entities/Scripting.h>
#include <Athena-Entities/Transforms.h>
#include <Athena-Entities/ComponentsList.h>
#include <Athena-Scripting/ScriptingManager.h>
#include <Athena-Scripting/Utils.h>
#include <string>

using namespace Athena::Entities;
using namespace Athena::Scripting;
using namespace v8;

#define FROM_JS(CLASS_NAME)                                                                \
CLASS_NAME* fromJS##CLASS_NAME(Handle<Value> value)                                        \
{                                                                                \
    if (value->IsObject())                                                                 \
    {                                                                                \
        CLASS_NAME* pObject = 0;                                                           \
        GetObjectPtr(value, &pObject);                                                     \
        return pObject;                                                                    \
    }                                                                                \
                                                                                \
    return 0;                                                                              \
}

#define CREATE_JS(CLASS_NAME)                                                              \
Handle<Object> createJS##CLASS_NAME()                                                      \
{                                                                                \
    HandleScope handle_scope;                                                              \
                                                                                \
    Handle<FunctionTemplate> func = ScriptingManager::getSingletonPtr()->getClassTemplate( \
                                                        "Athena.Entities." #CLASS_NAME);   \
                                                                                \
    Handle<Object> jsObject = func->GetFunction()->NewInstance();                          \
                                                                                \
    return handle_scope.Close(jsObject);                                                   \
}

#define TO_JS(CLASS_NAME)                                                                  \
Handle<Value> toJavaScript(CLASS_NAME* pObject)                                            \
{                                                                                \
    HandleScope handle_scope;                                                              \
                                                                                \
    if (!pObject)                                                                          \
        return Handle<Value>();                                                            \
                                                                                \
    Handle<FunctionTemplate> func = ScriptingManager::getSingletonPtr()->getClassTemplate( \
                                                        "Athena.Entities." #CLASS_NAME);   \
                                                                                \
    Handle<Value> argv[1];                                                                 \
    argv[0] = External::Wrap(pObject);                                                     \
                                                                                \
    Handle<Object> jsObject = func->GetFunction()->NewInstance(1, argv);                   \
                                                                                \
    return handle_scope.Close(jsObject);                                                   \
}

#define IMPLEMENT_CONVERSIONS(CLASS_NAME)                                                  \
    FROM_JS(CLASS_NAME);                                                                   \
    CREATE_JS(CLASS_NAME);                                                                 \
    TO_JS(CLASS_NAME);

namespace Athena {
namespace Entities {

IMPLEMENT_CONVERSIONS(Animation)
IMPLEMENT_CONVERSIONS(AnimationsMixer)
IMPLEMENT_CONVERSIONS(ComponentAnimation)
IMPLEMENT_CONVERSIONS(ComponentsList)
IMPLEMENT_CONVERSIONS(Component)
IMPLEMENT_CONVERSIONS(Entity)
IMPLEMENT_CONVERSIONS(Scene)
IMPLEMENT_CONVERSIONS(Transforms)

//-----------------------------------------------------------------------

tComponentID fromJSComponentID(Handle<Value> value)
{
    if (value->IsObject())
    {
        Handle<Object> object = value->ToObject();
        Handle<Function> prototype = Handle<Function>::Cast(object->GetPrototype());

        if (std::string("Athena.Entities.ComponentID") == *String::AsciiValue(prototype->Get(String::New("__classname__"))))
        {
            return tComponentID((tComponentType) object->Get(String::New("type"))->ToNumber()->NumberValue(),
                                *String::AsciiValue(object->Get(String::New("entity"))),
                                *String::AsciiValue(object->Get(String::New("component"))));
        }
    }

    return tComponentID(COMP_NONE);
}

//-----------------------------------------------------------------------

Handle<Value> toJavaScript(const tComponentID& value)
{
    HandleScope handle_scope;

    Local<Object> object = ScriptingManager::getSingletonPtr()->execute("new Athena.Entities.ComponentID('" + value.toString() + "');")->ToObject();

    return handle_scope.Close(object);
}

}
}
<|endoftext|>


<commit_before>// GrowthRegion.cpp
// Implements the GrowthRegion class

#include "GrowthRegion.h"

#include "QueryEngine.h"
#include "SymbolicFunctionFactories.h"
#include "InstModel.h"
#include "Prototype.h"
#include "CycException.h"

#include <vector>

using namespace std;
using namespace SupplyDemand;
using namespace ActionBuilding;

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
GrowthRegion::GrowthRegion() {}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
GrowthRegion::~GrowthRegion() {}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void GrowthRegion::initModuleMembers(QueryEngine* qe) {
  LOG(LEV_DEBUG2, "greg") << "A Growth Region is being initialized";

  string query = "commodity";

  int nCommodities = qe->nElementsMatchingQuery(query);

  // populate supply demand manager info for each commodity
  for (int i=0; i<nCommodities; i++) {
    addCommodityDemand(qe->queryElement(query,i));
  }
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void GrowthRegion::addCommodityDemand(QueryEngine* qe)
{
  // instantiate product
  string name = qe->getElementContent("name");
  Commodity commodity(name);
  registerCommodity(commodity);

  // instantiate demand
  QueryEngine* demand = qe->queryElement("demand");
  string type = demand->getElementContent("type");
  string params = demand->getElementContent("parameters");
  BasicFunctionFactory bff;
  FunctionPtr demand_function = bff.getFunctionPtr(type,params);

  // register the commodity and demand
  sdmanager_.registerCommodity(commodity,demand_function);
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void GrowthRegion::enterSimulationAsModule()
{
  for (int i = 0; i != nChildren(); i++)
    {
      Model* child = children(i);
      registerCommodityProducerManager(child);
      registerBuilder(child);
    }
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void GrowthRegion::handleTick(int time)
{
  set<Commodity>::iterator it;
  for (it = commodities_.begin(); it != commodities_.end(); it++)
    {
      Commodity commodity = *it;
      double demand = sdmanager_.demand(commodity,time);
      double supply = sdmanager_.supply(commodity);
      double unmet_demand = demand - supply;

      LOG(LEV_INFO3,"greg") << "GrowthRegion: " << name()
                            << " at time: " << time
                            << " has the following values regaring "
                            << " commodity: " << commodity.name();
      LOG(LEV_INFO3,"greg") << "  * demand = " << demand;
      LOG(LEV_INFO3,"greg") << "  * supply = " << supply;
      LOG(LEV_INFO3,"greg") << "  * unmet demand = " << unmet_demand;

      if (unmet_demand > 0)
        {
          orderBuilds(commodity,unmet_demand);
        }
    }
  RegionModel::handleTick(time);
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void GrowthRegion::registerCommodity(Commodity& commodity)
{
  if (commodities_.find(commodity) != commodities_.end())
    {
      throw CycDoubleRegistrationException("A GrowthRegion ("
                                           + name() + " is trying to register a commodity twice.");
    }
  else
    {
      commodities_.insert(commodity);
    }
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void GrowthRegion::registerCommodityProducerManager(Model* child)
{
  CommodityProducerManager* cast = dynamic_cast<CommodityProducerManager*>(child);
  if (cast)
    {
      sdmanager_.registerProducerManager(cast);
    }
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void GrowthRegion::registerBuilder(Model* child)
{
  Builder* cast = dynamic_cast<Builder*>(child);
  if (cast)
    {
      buildmanager_.registerBuilder(cast);
    }
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void GrowthRegion::orderBuilds(Commodity& commodity, double unmet_demand)
{
  vector<BuildOrder> orders = buildmanager_.makeBuildDecision(commodity,unmet_demand);

  LOG(LEV_INFO3,"greg") << "The build orders have been determined. "
                        << orders.size()
                        << " different type(s) of prototypes will be built.";

  for (int i = 0; i < orders.size(); i++)
    {
      BuildOrder order = orders.at(i);
      InstModel* instcast = dynamic_cast<InstModel*>(order.builder);
      Prototype* protocast = dynamic_cast<Prototype*>(order.producer);
      if(instcast && protocast)
        {
          LOG(LEV_INFO3,"greg") << "A build order for " << order.number
                                << " prototype(s) of type "
                                << dynamic_cast<Model*>(protocast)->name()
                                << " from builder " << instcast->name()
                                << " is being placed.";

          for (int j = 0; j < order.number; j++)
            {
              LOG(LEV_DEBUG3,"greg") << "Ordering build number: " << j+1;
              instcast->build(protocast);
            }
        }
      else
        {
          throw CycOverrideException("GrowthRegion has tried to incorrectly cast an already known entity.");
        }
    }
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
extern "C" Model* constructGrowthRegion()
{
  return new GrowthRegion();
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
extern "C" void destructGrowthRegion(Model* model)
{
      delete model;
}

<commit_msg>more clarity in growth region logs<commit_after>// GrowthRegion.cpp
// Implements the GrowthRegion class

#include "GrowthRegion.h"

#include "QueryEngine.h"
#include "SymbolicFunctionFactories.h"
#include "InstModel.h"
#include "Prototype.h"
#include "CycException.h"

#include <vector>

using namespace std;
using namespace SupplyDemand;
using namespace ActionBuilding;

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
GrowthRegion::GrowthRegion() {}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
GrowthRegion::~GrowthRegion() {}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void GrowthRegion::initModuleMembers(QueryEngine* qe) {
  LOG(LEV_DEBUG2, "greg") << "A Growth Region is being initialized";

  string query = "commodity";

  int nCommodities = qe->nElementsMatchingQuery(query);

  // populate supply demand manager info for each commodity
  for (int i=0; i<nCommodities; i++) {
    addCommodityDemand(qe->queryElement(query,i));
  }
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void GrowthRegion::addCommodityDemand(QueryEngine* qe)
{
  // instantiate product
  string name = qe->getElementContent("name");
  Commodity commodity(name);
  registerCommodity(commodity);

  // instantiate demand
  QueryEngine* demand = qe->queryElement("demand");
  string type = demand->getElementContent("type");
  string params = demand->getElementContent("parameters");
  BasicFunctionFactory bff;
  FunctionPtr demand_function = bff.getFunctionPtr(type,params);

  // register the commodity and demand
  sdmanager_.registerCommodity(commodity,demand_function);
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void GrowthRegion::enterSimulationAsModule()
{
  for (int i = 0; i != nChildren(); i++)
    {
      Model* child = children(i);
      registerCommodityProducerManager(child);
      registerBuilder(child);
    }
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void GrowthRegion::handleTick(int time)
{
  set<Commodity>::iterator it;
  for (it = commodities_.begin(); it != commodities_.end(); it++)
    {
      Commodity commodity = *it;
      double demand = sdmanager_.demand(commodity,time);
      double supply = sdmanager_.supply(commodity);
      double unmet_demand = demand - supply;

      LOG(LEV_INFO3,"greg") << "GrowthRegion: " << name()
                            << " at time: " << time
                            << " has the following values regaring "
                            << " commodity: " << commodity.name();
      LOG(LEV_INFO3,"greg") << "  * demand = " << demand;
      LOG(LEV_INFO3,"greg") << "  * supply = " << supply;
      LOG(LEV_INFO3,"greg") << "  * unmet demand = " << unmet_demand;

      if (unmet_demand > 0)
        {
          orderBuilds(commodity,unmet_demand);
        }
    }
  RegionModel::handleTick(time);
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void GrowthRegion::registerCommodity(Commodity& commodity)
{
  if (commodities_.find(commodity) != commodities_.end())
    {
      throw CycDoubleRegistrationException("A GrowthRegion ("
                                           + name() + " is trying to register a commodity twice.");
    }
  else
    {
      commodities_.insert(commodity);
    }
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void GrowthRegion::registerCommodityProducerManager(Model* child)
{
  CommodityProducerManager* cast = dynamic_cast<CommodityProducerManager*>(child);
  if (cast)
    {
      sdmanager_.registerProducerManager(cast);
    }
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void GrowthRegion::registerBuilder(Model* child)
{
  Builder* cast = dynamic_cast<Builder*>(child);
  if (cast)
    {
      buildmanager_.registerBuilder(cast);
    }
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void GrowthRegion::orderBuilds(Commodity& commodity, double unmet_demand)
{
  vector<BuildOrder> orders = buildmanager_.makeBuildDecision(commodity,unmet_demand);

  LOG(LEV_INFO3,"greg") << "The build orders have been determined. "
                        << orders.size()
                        << " different type(s) of prototypes will be built.";

  for (int i = 0; i < orders.size(); i++)
    {
      BuildOrder order = orders.at(i);
      InstModel* instcast = dynamic_cast<InstModel*>(order.builder);
      Prototype* protocast = dynamic_cast<Prototype*>(order.producer);
      if(instcast && protocast)
        {
          LOG(LEV_INFO3,"greg") << "A build order for " << order.number
                                << " prototype(s) of type "
                                << dynamic_cast<Model*>(protocast)->name()
                                << " from builder " << instcast->name()
                                << " is being placed.";

          for (int j = 0; j < order.number; j++)
            {
              LOG(LEV_DEBUG2,"greg") << "Ordering build number: " << j+1;
              instcast->build(protocast);
            }
        }
      else
        {
          throw CycOverrideException("GrowthRegion has tried to incorrectly cast an already known entity.");
        }
    }
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
extern "C" Model* constructGrowthRegion()
{
  return new GrowthRegion();
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
extern "C" void destructGrowthRegion(Model* model)
{
      delete model;
}

<|endoftext|>


<commit_before>//===- FunctionAttrs.cpp - Pass which marks functions readnone or readonly ===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements a simple interprocedural pass which walks the
// call-graph, looking for functions which do not access or only read
// non-local memory, and marking them readnone/readonly.  In addition,
// it marks function arguments (of pointer type) 'nocapture' if a call
// to the function does not create any copies of the pointer value that
// outlive the call.  This more or less means that the pointer is only
// dereferenced, and not returned from the function or stored in a global.
// This pass is implemented as a bottom-up traversal of the call-graph.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "functionattrs"
#include "llvm/Transforms/IPO.h"
#include "llvm/CallGraphSCCPass.h"
#include "llvm/GlobalVariable.h"
#include "llvm/IntrinsicInst.h"
#include "llvm/LLVMContext.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/CallGraph.h"
#include "llvm/Analysis/CaptureTracking.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/UniqueVector.h"
#include "llvm/Support/InstIterator.h"
using namespace llvm;

STATISTIC(NumReadNone, "Number of functions marked readnone");
STATISTIC(NumReadOnly, "Number of functions marked readonly");
STATISTIC(NumNoCapture, "Number of arguments marked nocapture");
STATISTIC(NumNoAlias, "Number of function returns marked noalias");

namespace {
  struct FunctionAttrs : public CallGraphSCCPass {
    static char ID; // Pass identification, replacement for typeid
    FunctionAttrs() : CallGraphSCCPass(ID), AA(0) {
      initializeFunctionAttrsPass(*PassRegistry::getPassRegistry());
    }

    // runOnSCC - Analyze the SCC, performing the transformation if possible.
    bool runOnSCC(CallGraphSCC &SCC);

    // AddReadAttrs - Deduce readonly/readnone attributes for the SCC.
    bool AddReadAttrs(const CallGraphSCC &SCC);

    // AddNoCaptureAttrs - Deduce nocapture attributes for the SCC.
    bool AddNoCaptureAttrs(const CallGraphSCC &SCC);

    // IsFunctionMallocLike - Does this function allocate new memory?
    bool IsFunctionMallocLike(Function *F,
                              SmallPtrSet<Function*, 8> &) const;

    // AddNoAliasAttrs - Deduce noalias attributes for the SCC.
    bool AddNoAliasAttrs(const CallGraphSCC &SCC);

    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AU.setPreservesCFG();
      AU.addRequired<AliasAnalysis>();
      CallGraphSCCPass::getAnalysisUsage(AU);
    }

  private:
    AliasAnalysis *AA;
  };
}

char FunctionAttrs::ID = 0;
INITIALIZE_PASS_BEGIN(FunctionAttrs, "functionattrs",
                "Deduce function attributes", false, false)
INITIALIZE_AG_DEPENDENCY(CallGraph)
INITIALIZE_PASS_END(FunctionAttrs, "functionattrs",
                "Deduce function attributes", false, false)

Pass *llvm::createFunctionAttrsPass() { return new FunctionAttrs(); }

/// AddReadAttrs - Deduce readonly/readnone attributes for the SCC.
bool FunctionAttrs::AddReadAttrs(const CallGraphSCC &SCC) {
  SmallPtrSet<Function*, 8> SCCNodes;

  // Fill SCCNodes with the elements of the SCC.  Used for quickly
  // looking up whether a given CallGraphNode is in this SCC.
  for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end(); I != E; ++I)
    SCCNodes.insert((*I)->getFunction());

  // Check if any of the functions in the SCC read or write memory.  If they
  // write memory then they can't be marked readnone or readonly.
  bool ReadsMemory = false;
  for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end(); I != E; ++I) {
    Function *F = (*I)->getFunction();

    if (F == 0)
      // External node - may write memory.  Just give up.
      return false;

    if (F->doesNotAccessMemory())
      // Already perfect!
      continue;

    // Definitions with weak linkage may be overridden at linktime with
    // something that writes memory, so treat them like declarations.
    if (F->isDeclaration() || F->mayBeOverridden()) {
      if (!F->onlyReadsMemory())
        // May write memory.  Just give up.
        return false;

      ReadsMemory = true;
      continue;
    }

    // Scan the function body for instructions that may read or write memory.
    for (inst_iterator II = inst_begin(F), E = inst_end(F); II != E; ++II) {
      Instruction *I = &*II;

      // Some instructions can be ignored even if they read or write memory.
      // Detect these now, skipping to the next instruction if one is found.
      CallSite CS(cast<Value>(I));
      if (CS) {
        // Ignore calls to functions in the same SCC.
        if (CS.getCalledFunction() && SCCNodes.count(CS.getCalledFunction()))
          continue;
        switch (AA->getModRefBehavior(CS)) {
        case AliasAnalysis::DoesNotAccessMemory:
          // Ignore calls that don't access memory.
          continue;
        case AliasAnalysis::OnlyReadsMemory:
          // Handle calls that only read from memory.
          ReadsMemory = true;
          continue;
        case AliasAnalysis::AccessesArguments:
          // Check whether all pointer arguments point to local memory, and
          // ignore calls that only access local memory.
          for (CallSite::arg_iterator CI = CS.arg_begin(), CE = CS.arg_end();
               CI != CE; ++CI) {
            Value *Arg = *CI;
            if (Arg->getType()->isPointerTy()) {
              AliasAnalysis::Location Loc(Arg,
                                          AliasAnalysis::UnknownSize,
                                          I->getMetadata(LLVMContext::MD_tbaa));
              if (!AA->pointsToConstantMemory(Loc, /*OrLocal=*/true))
                // Writes memory.  Just give up.
                return false;
            }
          }
          // Only reads and writes local memory.
          continue;
        case AliasAnalysis::AccessesArgumentsReadonly:
          // Check whether all pointer arguments point to local memory, and
          // ignore calls that only access local memory.
          for (CallSite::arg_iterator CI = CS.arg_begin(), CE = CS.arg_end();
               CI != CE; ++CI) {
            Value *Arg = *CI;
            if (Arg->getType()->isPointerTy()) {
              AliasAnalysis::Location Loc(Arg,
                                          AliasAnalysis::UnknownSize,
                                          I->getMetadata(LLVMContext::MD_tbaa));
              if (!AA->pointsToConstantMemory(Loc, /*OrLocal=*/true)) {
                // Reads non-local memory.
                ReadsMemory = true;
                break;
              }
            }
          }
          // Only reads memory.
          continue;
        default:
          // Otherwise, be conservative.
          break;
        }
      } else if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
        // Ignore non-volatile loads from local memory.
        if (!LI->isVolatile()) {
          AliasAnalysis::Location Loc(LI->getPointerOperand(),
                                        AA->getTypeStoreSize(LI->getType()),
                                        LI->getMetadata(LLVMContext::MD_tbaa));
          if (AA->pointsToConstantMemory(Loc, /*OrLocal=*/true))
            continue;
        }
      } else if (StoreInst *SI = dyn_cast<StoreInst>(I)) {
        // Ignore non-volatile stores to local memory.
        if (!SI->isVolatile()) {
          const Type *StoredType = SI->getValueOperand()->getType();
          AliasAnalysis::Location Loc(SI->getPointerOperand(),
                                      AA->getTypeStoreSize(StoredType),
                                      SI->getMetadata(LLVMContext::MD_tbaa));
          if (AA->pointsToConstantMemory(Loc, /*OrLocal=*/true))
            continue;
        }
      }

      // Any remaining instructions need to be taken seriously!  Check if they
      // read or write memory.
      if (I->mayWriteToMemory())
        // Writes memory.  Just give up.
        return false;

      // If this instruction may read memory, remember that.
      ReadsMemory |= I->mayReadFromMemory();
    }
  }

  // Success!  Functions in this SCC do not access memory, or only read memory.
  // Give them the appropriate attribute.
  bool MadeChange = false;
  for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end(); I != E; ++I) {
    Function *F = (*I)->getFunction();

    if (F->doesNotAccessMemory())
      // Already perfect!
      continue;

    if (F->onlyReadsMemory() && ReadsMemory)
      // No change.
      continue;

    MadeChange = true;

    // Clear out any existing attributes.
    F->removeAttribute(~0, Attribute::ReadOnly | Attribute::ReadNone);

    // Add in the new attribute.
    F->addAttribute(~0, ReadsMemory? Attribute::ReadOnly : Attribute::ReadNone);

    if (ReadsMemory)
      ++NumReadOnly;
    else
      ++NumReadNone;
  }

  return MadeChange;
}

/// AddNoCaptureAttrs - Deduce nocapture attributes for the SCC.
bool FunctionAttrs::AddNoCaptureAttrs(const CallGraphSCC &SCC) {
  bool Changed = false;

  // Check each function in turn, determining which pointer arguments are not
  // captured.
  for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end(); I != E; ++I) {
    Function *F = (*I)->getFunction();

    if (F == 0)
      // External node - skip it;
      continue;

    // Definitions with weak linkage may be overridden at linktime with
    // something that writes memory, so treat them like declarations.
    if (F->isDeclaration() || F->mayBeOverridden())
      continue;

    for (Function::arg_iterator A = F->arg_begin(), E = F->arg_end(); A!=E; ++A)
      if (A->getType()->isPointerTy() && !A->hasNoCaptureAttr() &&
          !PointerMayBeCaptured(A, true, /*StoreCaptures=*/false)) {
        A->addAttr(Attribute::NoCapture);
        ++NumNoCapture;
        Changed = true;
      }
  }

  return Changed;
}

/// IsFunctionMallocLike - A function is malloc-like if it returns either null
/// or a pointer that doesn't alias any other pointer visible to the caller.
bool FunctionAttrs::IsFunctionMallocLike(Function *F,
                              SmallPtrSet<Function*, 8> &SCCNodes) const {
  UniqueVector<Value *> FlowsToReturn;
  for (Function::iterator I = F->begin(), E = F->end(); I != E; ++I)
    if (ReturnInst *Ret = dyn_cast<ReturnInst>(I->getTerminator()))
      FlowsToReturn.insert(Ret->getReturnValue());

  for (unsigned i = 0; i != FlowsToReturn.size(); ++i) {
    Value *RetVal = FlowsToReturn[i+1];   // UniqueVector[0] is reserved.

    if (Constant *C = dyn_cast<Constant>(RetVal)) {
      if (!C->isNullValue() && !isa<UndefValue>(C))
        return false;

      continue;
    }

    if (isa<Argument>(RetVal))
      return false;

    if (Instruction *RVI = dyn_cast<Instruction>(RetVal))
      switch (RVI->getOpcode()) {
        // Extend the analysis by looking upwards.
        case Instruction::BitCast:
        case Instruction::GetElementPtr:
          FlowsToReturn.insert(RVI->getOperand(0));
          continue;
        case Instruction::Select: {
          SelectInst *SI = cast<SelectInst>(RVI);
          FlowsToReturn.insert(SI->getTrueValue());
          FlowsToReturn.insert(SI->getFalseValue());
          continue;
        }
        case Instruction::PHI: {
          PHINode *PN = cast<PHINode>(RVI);
          for (int i = 0, e = PN->getNumIncomingValues(); i != e; ++i)
            FlowsToReturn.insert(PN->getIncomingValue(i));
          continue;
        }

        // Check whether the pointer came from an allocation.
        case Instruction::Alloca:
          break;
        case Instruction::Call:
        case Instruction::Invoke: {
          CallSite CS(RVI);
          if (CS.paramHasAttr(0, Attribute::NoAlias))
            break;
          if (CS.getCalledFunction() &&
              SCCNodes.count(CS.getCalledFunction()))
            break;
        } // fall-through
        default:
          return false;  // Did not come from an allocation.
      }

    if (PointerMayBeCaptured(RetVal, false, /*StoreCaptures=*/false))
      return false;
  }

  return true;
}

/// AddNoAliasAttrs - Deduce noalias attributes for the SCC.
bool FunctionAttrs::AddNoAliasAttrs(const CallGraphSCC &SCC) {
  SmallPtrSet<Function*, 8> SCCNodes;

  // Fill SCCNodes with the elements of the SCC.  Used for quickly
  // looking up whether a given CallGraphNode is in this SCC.
  for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end(); I != E; ++I)
    SCCNodes.insert((*I)->getFunction());

  // Check each function in turn, determining which functions return noalias
  // pointers.
  for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end(); I != E; ++I) {
    Function *F = (*I)->getFunction();

    if (F == 0)
      // External node - skip it;
      return false;

    // Already noalias.
    if (F->doesNotAlias(0))
      continue;

    // Definitions with weak linkage may be overridden at linktime, so
    // treat them like declarations.
    if (F->isDeclaration() || F->mayBeOverridden())
      return false;

    // We annotate noalias return values, which are only applicable to
    // pointer types.
    if (!F->getReturnType()->isPointerTy())
      continue;

    if (!IsFunctionMallocLike(F, SCCNodes))
      return false;
  }

  bool MadeChange = false;
  for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end(); I != E; ++I) {
    Function *F = (*I)->getFunction();
    if (F->doesNotAlias(0) || !F->getReturnType()->isPointerTy())
      continue;

    F->setDoesNotAlias(0);
    ++NumNoAlias;
    MadeChange = true;
  }

  return MadeChange;
}

bool FunctionAttrs::runOnSCC(CallGraphSCC &SCC) {
  AA = &getAnalysis<AliasAnalysis>();

  bool Changed = AddReadAttrs(SCC);
  Changed |= AddNoCaptureAttrs(SCC);
  Changed |= AddNoAliasAttrs(SCC);
  return Changed;
}
<commit_msg>Use the AliasAnalysis interface to determine how a Function accesses memory. This isn't a real improvement with present day AliasAnalysis implementations; it's mainly for consistency.<commit_after>//===- FunctionAttrs.cpp - Pass which marks functions readnone or readonly ===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements a simple interprocedural pass which walks the
// call-graph, looking for functions which do not access or only read
// non-local memory, and marking them readnone/readonly.  In addition,
// it marks function arguments (of pointer type) 'nocapture' if a call
// to the function does not create any copies of the pointer value that
// outlive the call.  This more or less means that the pointer is only
// dereferenced, and not returned from the function or stored in a global.
// This pass is implemented as a bottom-up traversal of the call-graph.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "functionattrs"
#include "llvm/Transforms/IPO.h"
#include "llvm/CallGraphSCCPass.h"
#include "llvm/GlobalVariable.h"
#include "llvm/IntrinsicInst.h"
#include "llvm/LLVMContext.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/CallGraph.h"
#include "llvm/Analysis/CaptureTracking.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/UniqueVector.h"
#include "llvm/Support/InstIterator.h"
using namespace llvm;

STATISTIC(NumReadNone, "Number of functions marked readnone");
STATISTIC(NumReadOnly, "Number of functions marked readonly");
STATISTIC(NumNoCapture, "Number of arguments marked nocapture");
STATISTIC(NumNoAlias, "Number of function returns marked noalias");

namespace {
  struct FunctionAttrs : public CallGraphSCCPass {
    static char ID; // Pass identification, replacement for typeid
    FunctionAttrs() : CallGraphSCCPass(ID), AA(0) {
      initializeFunctionAttrsPass(*PassRegistry::getPassRegistry());
    }

    // runOnSCC - Analyze the SCC, performing the transformation if possible.
    bool runOnSCC(CallGraphSCC &SCC);

    // AddReadAttrs - Deduce readonly/readnone attributes for the SCC.
    bool AddReadAttrs(const CallGraphSCC &SCC);

    // AddNoCaptureAttrs - Deduce nocapture attributes for the SCC.
    bool AddNoCaptureAttrs(const CallGraphSCC &SCC);

    // IsFunctionMallocLike - Does this function allocate new memory?
    bool IsFunctionMallocLike(Function *F,
                              SmallPtrSet<Function*, 8> &) const;

    // AddNoAliasAttrs - Deduce noalias attributes for the SCC.
    bool AddNoAliasAttrs(const CallGraphSCC &SCC);

    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AU.setPreservesCFG();
      AU.addRequired<AliasAnalysis>();
      CallGraphSCCPass::getAnalysisUsage(AU);
    }

  private:
    AliasAnalysis *AA;
  };
}

char FunctionAttrs::ID = 0;
INITIALIZE_PASS_BEGIN(FunctionAttrs, "functionattrs",
                "Deduce function attributes", false, false)
INITIALIZE_AG_DEPENDENCY(CallGraph)
INITIALIZE_PASS_END(FunctionAttrs, "functionattrs",
                "Deduce function attributes", false, false)

Pass *llvm::createFunctionAttrsPass() { return new FunctionAttrs(); }

/// AddReadAttrs - Deduce readonly/readnone attributes for the SCC.
bool FunctionAttrs::AddReadAttrs(const CallGraphSCC &SCC) {
  SmallPtrSet<Function*, 8> SCCNodes;

  // Fill SCCNodes with the elements of the SCC.  Used for quickly
  // looking up whether a given CallGraphNode is in this SCC.
  for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end(); I != E; ++I)
    SCCNodes.insert((*I)->getFunction());

  // Check if any of the functions in the SCC read or write memory.  If they
  // write memory then they can't be marked readnone or readonly.
  bool ReadsMemory = false;
  for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end(); I != E; ++I) {
    Function *F = (*I)->getFunction();

    if (F == 0)
      // External node - may write memory.  Just give up.
      return false;

    AliasAnalysis::ModRefBehavior MRB = AA->getModRefBehavior(F);
    if (MRB == AliasAnalysis::DoesNotAccessMemory)
      // Already perfect!
      continue;

    // Definitions with weak linkage may be overridden at linktime with
    // something that writes memory, so treat them like declarations.
    if (F->isDeclaration() || F->mayBeOverridden()) {
      if (!AliasAnalysis::onlyReadsMemory(MRB))
        // May write memory.  Just give up.
        return false;

      ReadsMemory = true;
      continue;
    }

    // Scan the function body for instructions that may read or write memory.
    for (inst_iterator II = inst_begin(F), E = inst_end(F); II != E; ++II) {
      Instruction *I = &*II;

      // Some instructions can be ignored even if they read or write memory.
      // Detect these now, skipping to the next instruction if one is found.
      CallSite CS(cast<Value>(I));
      if (CS) {
        // Ignore calls to functions in the same SCC.
        if (CS.getCalledFunction() && SCCNodes.count(CS.getCalledFunction()))
          continue;
        switch (AA->getModRefBehavior(CS)) {
        case AliasAnalysis::DoesNotAccessMemory:
          // Ignore calls that don't access memory.
          continue;
        case AliasAnalysis::OnlyReadsMemory:
          // Handle calls that only read from memory.
          ReadsMemory = true;
          continue;
        case AliasAnalysis::AccessesArguments:
          // Check whether all pointer arguments point to local memory, and
          // ignore calls that only access local memory.
          for (CallSite::arg_iterator CI = CS.arg_begin(), CE = CS.arg_end();
               CI != CE; ++CI) {
            Value *Arg = *CI;
            if (Arg->getType()->isPointerTy()) {
              AliasAnalysis::Location Loc(Arg,
                                          AliasAnalysis::UnknownSize,
                                          I->getMetadata(LLVMContext::MD_tbaa));
              if (!AA->pointsToConstantMemory(Loc, /*OrLocal=*/true))
                // Writes memory.  Just give up.
                return false;
            }
          }
          // Only reads and writes local memory.
          continue;
        case AliasAnalysis::AccessesArgumentsReadonly:
          // Check whether all pointer arguments point to local memory, and
          // ignore calls that only access local memory.
          for (CallSite::arg_iterator CI = CS.arg_begin(), CE = CS.arg_end();
               CI != CE; ++CI) {
            Value *Arg = *CI;
            if (Arg->getType()->isPointerTy()) {
              AliasAnalysis::Location Loc(Arg,
                                          AliasAnalysis::UnknownSize,
                                          I->getMetadata(LLVMContext::MD_tbaa));
              if (!AA->pointsToConstantMemory(Loc, /*OrLocal=*/true)) {
                // Reads non-local memory.
                ReadsMemory = true;
                break;
              }
            }
          }
          // Only reads memory.
          continue;
        default:
          // Otherwise, be conservative.
          break;
        }
      } else if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
        // Ignore non-volatile loads from local memory.
        if (!LI->isVolatile()) {
          AliasAnalysis::Location Loc(LI->getPointerOperand(),
                                        AA->getTypeStoreSize(LI->getType()),
                                        LI->getMetadata(LLVMContext::MD_tbaa));
          if (AA->pointsToConstantMemory(Loc, /*OrLocal=*/true))
            continue;
        }
      } else if (StoreInst *SI = dyn_cast<StoreInst>(I)) {
        // Ignore non-volatile stores to local memory.
        if (!SI->isVolatile()) {
          const Type *StoredType = SI->getValueOperand()->getType();
          AliasAnalysis::Location Loc(SI->getPointerOperand(),
                                      AA->getTypeStoreSize(StoredType),
                                      SI->getMetadata(LLVMContext::MD_tbaa));
          if (AA->pointsToConstantMemory(Loc, /*OrLocal=*/true))
            continue;
        }
      }

      // Any remaining instructions need to be taken seriously!  Check if they
      // read or write memory.
      if (I->mayWriteToMemory())
        // Writes memory.  Just give up.
        return false;

      // If this instruction may read memory, remember that.
      ReadsMemory |= I->mayReadFromMemory();
    }
  }

  // Success!  Functions in this SCC do not access memory, or only read memory.
  // Give them the appropriate attribute.
  bool MadeChange = false;
  for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end(); I != E; ++I) {
    Function *F = (*I)->getFunction();

    if (F->doesNotAccessMemory())
      // Already perfect!
      continue;

    if (F->onlyReadsMemory() && ReadsMemory)
      // No change.
      continue;

    MadeChange = true;

    // Clear out any existing attributes.
    F->removeAttribute(~0, Attribute::ReadOnly | Attribute::ReadNone);

    // Add in the new attribute.
    F->addAttribute(~0, ReadsMemory? Attribute::ReadOnly : Attribute::ReadNone);

    if (ReadsMemory)
      ++NumReadOnly;
    else
      ++NumReadNone;
  }

  return MadeChange;
}

/// AddNoCaptureAttrs - Deduce nocapture attributes for the SCC.
bool FunctionAttrs::AddNoCaptureAttrs(const CallGraphSCC &SCC) {
  bool Changed = false;

  // Check each function in turn, determining which pointer arguments are not
  // captured.
  for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end(); I != E; ++I) {
    Function *F = (*I)->getFunction();

    if (F == 0)
      // External node - skip it;
      continue;

    // Definitions with weak linkage may be overridden at linktime with
    // something that writes memory, so treat them like declarations.
    if (F->isDeclaration() || F->mayBeOverridden())
      continue;

    for (Function::arg_iterator A = F->arg_begin(), E = F->arg_end(); A!=E; ++A)
      if (A->getType()->isPointerTy() && !A->hasNoCaptureAttr() &&
          !PointerMayBeCaptured(A, true, /*StoreCaptures=*/false)) {
        A->addAttr(Attribute::NoCapture);
        ++NumNoCapture;
        Changed = true;
      }
  }

  return Changed;
}

/// IsFunctionMallocLike - A function is malloc-like if it returns either null
/// or a pointer that doesn't alias any other pointer visible to the caller.
bool FunctionAttrs::IsFunctionMallocLike(Function *F,
                              SmallPtrSet<Function*, 8> &SCCNodes) const {
  UniqueVector<Value *> FlowsToReturn;
  for (Function::iterator I = F->begin(), E = F->end(); I != E; ++I)
    if (ReturnInst *Ret = dyn_cast<ReturnInst>(I->getTerminator()))
      FlowsToReturn.insert(Ret->getReturnValue());

  for (unsigned i = 0; i != FlowsToReturn.size(); ++i) {
    Value *RetVal = FlowsToReturn[i+1];   // UniqueVector[0] is reserved.

    if (Constant *C = dyn_cast<Constant>(RetVal)) {
      if (!C->isNullValue() && !isa<UndefValue>(C))
        return false;

      continue;
    }

    if (isa<Argument>(RetVal))
      return false;

    if (Instruction *RVI = dyn_cast<Instruction>(RetVal))
      switch (RVI->getOpcode()) {
        // Extend the analysis by looking upwards.
        case Instruction::BitCast:
        case Instruction::GetElementPtr:
          FlowsToReturn.insert(RVI->getOperand(0));
          continue;
        case Instruction::Select: {
          SelectInst *SI = cast<SelectInst>(RVI);
          FlowsToReturn.insert(SI->getTrueValue());
          FlowsToReturn.insert(SI->getFalseValue());
          continue;
        }
        case Instruction::PHI: {
          PHINode *PN = cast<PHINode>(RVI);
          for (int i = 0, e = PN->getNumIncomingValues(); i != e; ++i)
            FlowsToReturn.insert(PN->getIncomingValue(i));
          continue;
        }

        // Check whether the pointer came from an allocation.
        case Instruction::Alloca:
          break;
        case Instruction::Call:
        case Instruction::Invoke: {
          CallSite CS(RVI);
          if (CS.paramHasAttr(0, Attribute::NoAlias))
            break;
          if (CS.getCalledFunction() &&
              SCCNodes.count(CS.getCalledFunction()))
            break;
        } // fall-through
        default:
          return false;  // Did not come from an allocation.
      }

    if (PointerMayBeCaptured(RetVal, false, /*StoreCaptures=*/false))
      return false;
  }

  return true;
}

/// AddNoAliasAttrs - Deduce noalias attributes for the SCC.
bool FunctionAttrs::AddNoAliasAttrs(const CallGraphSCC &SCC) {
  SmallPtrSet<Function*, 8> SCCNodes;

  // Fill SCCNodes with the elements of the SCC.  Used for quickly
  // looking up whether a given CallGraphNode is in this SCC.
  for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end(); I != E; ++I)
    SCCNodes.insert((*I)->getFunction());

  // Check each function in turn, determining which functions return noalias
  // pointers.
  for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end(); I != E; ++I) {
    Function *F = (*I)->getFunction();

    if (F == 0)
      // External node - skip it;
      return false;

    // Already noalias.
    if (F->doesNotAlias(0))
      continue;

    // Definitions with weak linkage may be overridden at linktime, so
    // treat them like declarations.
    if (F->isDeclaration() || F->mayBeOverridden())
      return false;

    // We annotate noalias return values, which are only applicable to
    // pointer types.
    if (!F->getReturnType()->isPointerTy())
      continue;

    if (!IsFunctionMallocLike(F, SCCNodes))
      return false;
  }

  bool MadeChange = false;
  for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end(); I != E; ++I) {
    Function *F = (*I)->getFunction();
    if (F->doesNotAlias(0) || !F->getReturnType()->isPointerTy())
      continue;

    F->setDoesNotAlias(0);
    ++NumNoAlias;
    MadeChange = true;
  }

  return MadeChange;
}

bool FunctionAttrs::runOnSCC(CallGraphSCC &SCC) {
  AA = &getAnalysis<AliasAnalysis>();

  bool Changed = AddReadAttrs(SCC);
  Changed |= AddNoCaptureAttrs(SCC);
  Changed |= AddNoAliasAttrs(SCC);
  return Changed;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <cstdlib>
#include <ctime>
#include <cassert>

#include "SearchCmd.h"
#include "StringUtils.h"

#include "MeshPart.h"
#include "AnnLocator.h"

#include "Reader.h"
#include "Timer.h"

#include "Writer.h"
#include "HdfWriter.h"

using namespace std;
using namespace cigma;

// ---------------------------------------------------------------------------

SearchCmd::SearchCmd()
{
    name = "search";

    points = 0;
    meshPart = 0;
    coordsField = 0;
}

SearchCmd::~SearchCmd()
{
    // XXX
}

// ---------------------------------------------------------------------------

void SearchCmd::setupOptions(AnyOption *opt)
{

    assert(opt != 0);

    /* setup usage */
    opt->addUsage("Usage:");
    opt->addUsage("   cigma search [options]");
    opt->addUsage("     --points    Path to search points");
    opt->addUsage("     --mesh      Path to mesh");
    opt->addUsage("     --output    Path to output dataset");

    /* setup flags and options */
    opt->setFlag("help", 'h');
    opt->setFlag("debug");

    // options for mesh
    opt->setOption("mesh");
    opt->setOption("mesh-coordinates");
    opt->setOption("mesh-connectivity");

    // options for points
    opt->setOption("points");

    // options for output
    opt->setOption("output",'o');

    // other options
    opt->setFlag("verbose",'v');
}

void SearchCmd::configure(AnyOption *opt)
{
    string inputstr;
    char *in;

    /* Check if --verbose was enabled */

    verbose = opt->getFlag("verbose");

    /* Determine the output option */
    in = opt->getValue("output");
    if (in != 0)
    {
        inputstr = in;
    }
    string outputLoc, outputExt;
    parse_dataset_path(inputstr, outputLoc, outputFile, outputExt);
    writer = NewWriter(outputExt.c_str());
    if (writer->getType() != Writer::HDF_WRITER)
    {
        cerr << "search: Please specify a target HDF5 file in --output option" << endl;
        exit(1);
    }

    /* Gather up the expected command line arguments */

    meshPartReader.load_args(opt, "mesh");
    pointsReader.load_args(opt, "points");

    meshPartReader.validate_args("search");
    pointsReader.validate_args("search");

    /* load mesh into memory */
    meshPartReader.load_mesh();
    pointsReader.load_points();

    points = pointsReader.points;
    meshPart = meshPartReader.meshPart;

    if (meshPart == 0)
    {
        cerr << "search: Could not load mesh!" << endl;
        exit(1);
    }

    if (points == 0)
    {
        cerr << "search: Could not load points!" << endl;
        exit(1);
    }

    coordsField = new FE_Field();
    coordsField->dim  = meshPart->nsd;
    coordsField->rank = meshPart->nsd;
    coordsField->meshPart = meshPart;
    coordsField->meshPart->set_cell();

    if ((coordsField->meshPart->nsd == 3) && (coordsField->meshPart->nno > 1000))
    {
        AnnLocator *locator = new AnnLocator();
        locator->nnk = 10;
        coordsField->meshPart->set_locator(locator);
    }

    return;
}

// ---------------------------------------------------------------------------

int SearchCmd::run()
{

    assert(points != 0);
    assert(meshPart != 0);

    int i,j;
    int e;
    const int nsd = meshPart->nsd;
    const int nel = meshPart->nel;
    const int npts = points->n_points();

    int *cellPointCount = new int[nel];   // how many points fall on given cell?
    int *pointCellCount = new int[npts];  // how many cells were searched for a given point?

    for (e = 0; e < nel; e++)
    {
        cellPointCount[e] = 0;
    }

    for (i = 0; i < npts; i++)
    {
        pointCellCount[i] = 0;
    }

    time_t t0,t1;
    time(&t0);

    int hitCount = 0;

    if (meshPart->locator != 0)
    {
        for (i = 0; i < points->n_points(); i++)
        {
            //double *pt = (*points)[i];
            double pt[3] = {0,0,0};
            for (j = 0; j < points->n_dim(); j++)
            {
                pt[j] = (*points)(i,j);
            }

            //bool found = meshPart->find_cell(pt, &parentCell);

            bool found = false;

            meshPart->locator->search(pt);
            for (j = 0; j < meshPart->locator->n_idx(); j++)
            {
                e = meshPart->locator->idx(j);
                if (e < 0)
                {
                    continue;
                }
                meshPart->select_cell(e);
                if (meshPart->cell->global_interior(pt))
                {
                    found = true;
                    cellPointCount[e]++;
                    pointCellCount[i] = j+1;
                    break;
                }
            }
            //*
            if (!found)
            {
                hitCount++;
                //cout << i << endl;
                for (e = 0; e < nel; e++)
                {
                    meshPart->select_cell(e);
                    if (meshPart->cell->global_interior(pt))
                    {
                        found = true;
                        cellPointCount[e]++;
                        pointCellCount[i] = e+1;
                        break;
                    }
                }
                assert(found);
            } // */
        }
        cout << "Locator missed " << hitCount << " points "
             << "(" << ((100.0*hitCount)/npts) << "%)"
             << endl;
    }
    else
    {
        for (i = 0; i < points->n_points(); i++)
        {
            double *pt = (*points)[i];
            bool found = false;
            for (e = 0; e < nel; e++)
            {
                meshPart->select_cell(e);
                if (meshPart->cell->global_interior(pt))
                {
                    found = true;
                    cellPointCount[e]++;
                    pointCellCount[i] = e+1;
                    break;
                }
            }
        }
    }

    time(&t1);
    double total_time = t1 - t0;
    cout << "Total time = " << total_time << endl;

    int ierr;

    HdfWriter *hdfWriter = static_cast<HdfWriter*>(writer);

    ierr = hdfWriter->open(outputFile.c_str());
    if (ierr < 0)
    {
        cerr << "search: Could not open output file " << outputFile << endl;
        exit(1);
    }

    string loc;

    loc = "/CellPointCount";
    ierr = hdfWriter->write_int_dataset(loc.c_str(), cellPointCount, nel, 1);
    if (ierr < 0)
    {
        cerr << "search: Could not write dataset " << loc << endl;
        exit(1);
    }

    loc = "/PointCellCount";
    ierr = hdfWriter->write_int_dataset(loc.c_str(), pointCellCount, npts, 1);
    if (ierr < 0)
    {
        cerr << "search: Could not write dataset " << loc << endl;
        exit(1);
    }

    ierr = hdfWriter->close();

    delete [] cellPointCount;
    delete [] pointCellCount;

    return 0;
}

// ---------------------------------------------------------------------------
<commit_msg>Use Locator::search_point() in SearchCmd<commit_after>#include <iostream>
#include <cstdlib>
#include <ctime>
#include <cassert>

#include "SearchCmd.h"
#include "StringUtils.h"

#include "MeshPart.h"
#include "AnnLocator.h"

#include "Reader.h"
#include "Timer.h"

#include "Writer.h"
#include "HdfWriter.h"

using namespace std;
using namespace cigma;

// ---------------------------------------------------------------------------

SearchCmd::SearchCmd()
{
    name = "search";

    points = 0;
    meshPart = 0;
    coordsField = 0;
}

SearchCmd::~SearchCmd()
{
    // XXX
}

// ---------------------------------------------------------------------------

void SearchCmd::setupOptions(AnyOption *opt)
{

    assert(opt != 0);

    /* setup usage */
    opt->addUsage("Usage:");
    opt->addUsage("   cigma search [options]");
    opt->addUsage("     --points    Path to search points");
    opt->addUsage("     --mesh      Path to mesh");
    opt->addUsage("     --output    Path to output dataset");

    /* setup flags and options */
    opt->setFlag("help", 'h');
    opt->setFlag("debug");

    // options for mesh
    opt->setOption("mesh");
    opt->setOption("mesh-coordinates");
    opt->setOption("mesh-connectivity");

    // options for points
    opt->setOption("points");

    // options for output
    opt->setOption("output",'o');

    // other options
    opt->setFlag("verbose",'v');
}

void SearchCmd::configure(AnyOption *opt)
{
    string inputstr;
    char *in;

    /* Check if --verbose was enabled */

    verbose = opt->getFlag("verbose");

    /* Determine the output option */
    in = opt->getValue("output");
    if (in != 0)
    {
        inputstr = in;
    }
    string outputLoc, outputExt;
    parse_dataset_path(inputstr, outputLoc, outputFile, outputExt);
    writer = NewWriter(outputExt.c_str());
    if (writer->getType() != Writer::HDF_WRITER)
    {
        cerr << "search: Please specify a target HDF5 file in --output option" << endl;
        exit(1);
    }

    /* Gather up the expected command line arguments */

    meshPartReader.load_args(opt, "mesh");
    pointsReader.load_args(opt, "points");

    meshPartReader.validate_args("search");
    pointsReader.validate_args("search");

    /* load mesh into memory */
    meshPartReader.load_mesh();
    pointsReader.load_points();

    points = pointsReader.points;
    meshPart = meshPartReader.meshPart;

    if (meshPart == 0)
    {
        cerr << "search: Could not load mesh!" << endl;
        exit(1);
    }

    if (points == 0)
    {
        cerr << "search: Could not load points!" << endl;
        exit(1);
    }

    coordsField = new FE_Field();
    coordsField->dim  = meshPart->nsd;
    coordsField->rank = meshPart->nsd;
    coordsField->meshPart = meshPart;
    coordsField->meshPart->set_cell();

    if ((coordsField->meshPart->nsd == 3) && (coordsField->meshPart->nno > 1000))
    {
        AnnLocator *locator = new AnnLocator();
        locator->nnk = 10;
        coordsField->meshPart->set_locator(locator);
    }

    return;
}

// ---------------------------------------------------------------------------

int SearchCmd::run()
{

    assert(points != 0);
    assert(meshPart != 0);

    int i,j;
    int e;
    const int nsd = meshPart->nsd;
    const int nel = meshPart->nel;
    const int npts = points->n_points();

    int *cellPointCount = new int[nel];   // how many points fall on given cell?
    int *pointCellCount = new int[npts];  // how many cells were searched for a given point?

    for (e = 0; e < nel; e++)
    {
        cellPointCount[e] = 0;
    }

    for (i = 0; i < npts; i++)
    {
        pointCellCount[i] = 0;
    }

    time_t t0,t1;
    time(&t0);

    int hitCount = 0;

    if (meshPart->locator != 0)
    {
        for (i = 0; i < points->n_points(); i++)
        {
            //double *pt = (*points)[i];
            double pt[3] = {0,0,0};
            for (j = 0; j < points->n_dim(); j++)
            {
                pt[j] = (*points)(i,j);
            }

            //bool found = meshPart->find_cell(pt, &parentCell);

            bool found = false;

            meshPart->locator->search_point(pt);
            for (j = 0; j < meshPart->locator->n_idx(); j++)
            {
                e = meshPart->locator->idx(j);
                if (e < 0)
                {
                    continue;
                }
                meshPart->select_cell(e);
                if (meshPart->cell->global_interior(pt))
                {
                    found = true;
                    cellPointCount[e]++;
                    pointCellCount[i] = j+1;
                    break;
                }
            }
            //*
            if (!found)
            {
                hitCount++;
                //cout << i << endl;
                for (e = 0; e < nel; e++)
                {
                    meshPart->select_cell(e);
                    if (meshPart->cell->global_interior(pt))
                    {
                        found = true;
                        cellPointCount[e]++;
                        pointCellCount[i] = e+1;
                        break;
                    }
                }
                assert(found);
            } // */
        }
        cout << "Locator missed " << hitCount << " points "
             << "(" << ((100.0*hitCount)/npts) << "%)"
             << endl;
    }
    else
    {
        for (i = 0; i < points->n_points(); i++)
        {
            double *pt = (*points)[i];
            bool found = false;
            for (e = 0; e < nel; e++)
            {
                meshPart->select_cell(e);
                if (meshPart->cell->global_interior(pt))
                {
                    found = true;
                    cellPointCount[e]++;
                    pointCellCount[i] = e+1;
                    break;
                }
            }
        }
    }

    time(&t1);
    double total_time = t1 - t0;
    cout << "Total time = " << total_time << endl;

    int ierr;

    HdfWriter *hdfWriter = static_cast<HdfWriter*>(writer);

    ierr = hdfWriter->open(outputFile.c_str());
    if (ierr < 0)
    {
        cerr << "search: Could not open output file " << outputFile << endl;
        exit(1);
    }

    string loc;

    loc = "/CellPointCount";
    ierr = hdfWriter->write_int_dataset(loc.c_str(), cellPointCount, nel, 1);
    if (ierr < 0)
    {
        cerr << "search: Could not write dataset " << loc << endl;
        exit(1);
    }

    loc = "/PointCellCount";
    ierr = hdfWriter->write_int_dataset(loc.c_str(), pointCellCount, npts, 1);
    if (ierr < 0)
    {
        cerr << "search: Could not write dataset " << loc << endl;
        exit(1);
    }

    ierr = hdfWriter->close();

    delete [] cellPointCount;
    delete [] pointCellCount;

    return 0;
}

// ---------------------------------------------------------------------------
<|endoftext|>