<commit_before>/*
**
** Author(s):
**  - Cedric GESTES <gestes@aldebaran-robotics.com>
**
** Copyright (C) 2013 Aldebaran Robotics
*/
#include "pyobject.hpp"
#include <boost/python.hpp>
#include <boost/python/raw_function.hpp>
#include "pyfuture.hpp"
#include "pysignal.hpp"
#include "pyproperty.hpp"
#include "gil.hpp"
#include "error.hpp"
#include <qitype/genericobjectbuilder.hpp>

qiLogCategory("qipy.object");

namespace qi { namespace py {

    boost::python::object import_inspect() {
      static bool plouf = false;
      static boost::python::object obj;
      if (!plouf) {
        obj = boost::python::import("inspect");
        plouf = true;
      }
      return obj;
    }

    struct PyQiFunctor {
    public:
      PyQiFunctor(const std::string &funName, qi::ObjectPtr obj)
        : _object(obj)
        , _funName(funName)
      {}

      boost::python::object operator()(boost::python::tuple pyargs, boost::python::dict pykwargs) {
        qi::GenericValue val = qi::GenericValue::from(pyargs);
        bool async = boost::python::extract<bool>(pykwargs.get("_async", false));
        std::string funN = boost::python::extract<std::string>(pykwargs.get("_overload", _funName));
        qiLogDebug() << "calling a method: " << funN << " args:" << qi::encodeJSON(val);

        qi::Future<qi::GenericValuePtr> fut;
        {
          //calling c++, so release the GIL.
          GILScopedUnlock _unlock;
          fut = _object->metaCall(funN, val.asDynamic().asTupleValuePtr());
        }
        if (!async)
          return fut.value().to<boost::python::object>();
        else
          return qi::py::makeFuture(fut);
      }

    public:
      qi::ObjectPtr _object;
      std::string   _funName;
    };

    void populateMethods(boost::python::object pyobj, qi::ObjectPtr obj) {
      qi::MetaObject::MethodMap           mm = obj->metaObject().methodMap();
      qi::MetaObject::MethodMap::iterator it;
      for (it = mm.begin(); it != mm.end(); ++it) {
        qi::MetaMethod &mem = it->second;
        //drop special methods
        if (mem.uid() < qiObjectSpecialMethodMaxUid)
          continue;
        qiLogDebug() << "adding method:" << mem.toString();
        boost::python::object fun = boost::python::raw_function(PyQiFunctor(mem.name().c_str(), obj));
        boost::python::api::setattr(pyobj, mem.name().c_str(), fun);
        // Fill __doc__ with Signature and description
        std::stringstream ssdocstring;
        ssdocstring << "Signature: " << mem.returnSignature().toString() << "\n";
        ssdocstring << mem.description();
        boost::python::object docstring(ssdocstring.str());
        boost::python::api::setattr(fun, "__doc__", docstring);
      }
    }

    void populateSignals(boost::python::object pyobj, qi::ObjectPtr obj) {
      qi::MetaObject::SignalMap           mm = obj->metaObject().signalMap();
      qi::MetaObject::SignalMap::iterator it;
      for (it = mm.begin(); it != mm.end(); ++it) {
        qi::MetaSignal &ms = it->second;
        //drop special methods
        if (ms.uid() < qiObjectSpecialMethodMaxUid)
          continue;
        qiLogDebug() << "adding signal:" << ms.toString();
        boost::python::object fun = qi::py::makePyProxySignal(obj, ms);
        boost::python::api::setattr(pyobj, ms.name(), fun);
      }
    }

    void populateProperties(boost::python::object pyobj, qi::ObjectPtr obj) {
      qi::MetaObject::PropertyMap           mm = obj->metaObject().propertyMap();
      qi::MetaObject::PropertyMap::iterator it;
      for (it = mm.begin(); it != mm.end(); ++it) {
        qi::MetaProperty &mp = it->second;
        //drop special methods
        if (mp.uid() < qiObjectSpecialMethodMaxUid)
          continue;
        qiLogDebug() << "adding property:" << mp.toString();
        boost::python::object fun = qi::py::makePyProxyProperty(obj, mp);
        boost::python::api::setattr(pyobj, mp.name().c_str(), fun);
      }
    }

    class PyQiObject {
    public:
      PyQiObject()
      {}

      PyQiObject(const qi::ObjectPtr &obj)
        : _object(obj)
      {}

      boost::python::object call(boost::python::str pyname, boost::python::tuple pyargs, boost::python::dict pykws) {
        return PyQiFunctor(boost::python::extract<std::string>(pyname), _object)(pyargs, pykws);
      }

      boost::python::object metaObject() {
        return qi::GenericValueRef(_object->metaObject()).to<boost::python::object>();
      }

      qi::ObjectPtr object() {
        return _object;
      }

    private:
      qi::ObjectPtr _object;
    };

    boost::python::object makePyQiObject(qi::ObjectPtr obj, const std::string &name) {
      boost::python::object result = boost::python::object(qi::py::PyQiObject(obj));
      qi::py::populateMethods(result, obj);
      qi::py::populateSignals(result, obj);
      qi::py::populateProperties(result, obj);
      return result;
    }

    //TODO: DO NOT DUPLICATE
    static qi::GenericValuePtr pyCallMethod(const std::vector<qi::GenericValuePtr>& cargs, boost::python::object callable) {
      qi::py::GILScopedLock _lock;
      boost::python::list   args;
      boost::python::object ret;

      std::vector<qi::GenericValuePtr>::const_iterator it = cargs.begin();
      ++it; //drop the first arg which is DynamicObject*
      for (; it != cargs.end(); ++it) {
        qiLogDebug() << "argument: " << qi::encodeJSON(*it);
        args.append(it->to<boost::python::object>());
      }
      qiLogDebug() << "before method call";
      try {
        ret = callable(*boost::python::tuple(args));
      } catch (const boost::python::error_already_set &e) {
        std::string err = PyFormatError();
        qiLogDebug() << "call exception:" << err;
        throw std::runtime_error(err);
      }

      qi::GenericValuePtr gvret = qi::GenericValueRef(ret).clone();
      qiLogDebug() << "method returned:" << qi::encodeJSON(gvret);
      return gvret;
    }

    //callback just needed to keep a ref on obj
    static void doNothing(qi::GenericObject *go, boost::python::object obj)
    {
      (void)go;
      (void)obj;
    }

    qi::ObjectPtr makeQiObjectPtr(boost::python::object obj)
    {
      //is that a qi::ObjectPtr?
      boost::python::extract<PyQiObject*> isthatyoumum(obj);

      if (isthatyoumum.check()) {
        qiLogDebug() << "this PyObject is already a qi::ObjectPtr. Just returning it.";
        return isthatyoumum()->object();
      }

      qi::GenericObjectBuilder gob;
      GILScopedLock _lock;
      boost::python::object attrs(boost::python::borrowed(PyObject_Dir(obj.ptr())));

      for (int i = 0; i < boost::python::len(attrs); ++i) {
        std::string key = boost::python::extract<std::string>(attrs[i]);
        boost::python::object m = obj.attr(attrs[i]);
        if (PyMethod_Check(m.ptr())) {
          qi::MetaMethodBuilder mmb;
          mmb.setName(key);
          boost::python::object desc = m.attr("__doc__");
          if (desc)
            mmb.setDescription(boost::python::extract<std::string>(desc));
          boost::python::object inspect = import_inspect();
          //returns: (args, varargs, keywords, defaults)
          boost::python::object tu = inspect.attr("getargspec")(m);
          int argsz = boost::python::len(tu[0]);

          argsz = argsz > 0 ? argsz - 1 : 0;

          if (argsz < 0) {
            qiLogError() << "Method " << key << " is missing the self argument.";
            continue;
          }
          std::stringstream ss;
          ss << "(";
          for (int i = 0; i < argsz; ++i)
            ss << "m";
          ss << ")";
          qiLogDebug() << "Adding method: " << ss.str();
          mmb.setName(key);
          mmb.setParametersSignature(ss.str());
          mmb.setReturnSignature("m");
          gob.xAdvertiseMethod(mmb, qi::makeDynamicGenericFunction(boost::bind(pyCallMethod, _1, m)));
          continue;
        }

        //store a pointer on PySignal class
        static boost::python::object asignal = qi::py::makePySignal("(i)").attr("__class__");
        if (PyObject_IsInstance(m.ptr(), asignal.ptr())) {
          qiLogDebug() << "Adding signal:" << key;
          gob.advertiseSignal(key, qi::py::getSignal(m));
          continue;
        }

        //TODO: check for Property
        static boost::python::object aproperty = qi::py::makePyProperty("(i)").attr("__class__");
        if (PyObject_IsInstance(m.ptr(), aproperty.ptr())) {
          qiLogDebug() << "Adding property:" << key;
          gob.advertiseProperty(key, qi::py::getProperty(m));
          continue;
        }

      }
      //this is a useless callback, needed to keep a ref on obj.
      //when the GO is destructed, the ref is released.
      return gob.object(boost::bind<void>(&doNothing, _1, obj));
    }

    static boost::python::object pyobject_param_shrinker(boost::python::tuple args, boost::python::dict kwargs) {
      PyQiObject& pys = boost::python::extract<PyQiObject&>(args[0]);
      boost::python::list l;
      for (int i = 2; i < boost::python::len(args); ++i)
        l.append(args[i]);
      return pys.call(boost::python::extract<boost::python::str>(args[1]), boost::python::tuple(l), kwargs);
    }

    void export_pyobject() {
      boost::python::class_<qi::py::PyQiObject>("Object", boost::python::no_init)
          .def("call", boost::python::raw_function(&pyobject_param_shrinker, 1))
          //TODO: .def("post")
          //TODO: .def("setProperty")
          //TODO: .def("property")
          .def("metaObject", &qi::py::PyQiObject::metaObject);
      //import inspect in our current namespace
      import_inspect();
    }
  }
}
<commit_msg>rename occurences of qiObjectSpecialMethodMaxUid to qiObjectSpecialMemberMaxUid<commit_after>/*
**
** Author(s):
**  - Cedric GESTES <gestes@aldebaran-robotics.com>
**
** Copyright (C) 2013 Aldebaran Robotics
*/
#include "pyobject.hpp"
#include <boost/python.hpp>
#include <boost/python/raw_function.hpp>
#include "pyfuture.hpp"
#include "pysignal.hpp"
#include "pyproperty.hpp"
#include "gil.hpp"
#include "error.hpp"
#include <qitype/genericobjectbuilder.hpp>

qiLogCategory("qipy.object");

namespace qi { namespace py {

    boost::python::object import_inspect() {
      static bool plouf = false;
      static boost::python::object obj;
      if (!plouf) {
        obj = boost::python::import("inspect");
        plouf = true;
      }
      return obj;
    }

    struct PyQiFunctor {
    public:
      PyQiFunctor(const std::string &funName, qi::ObjectPtr obj)
        : _object(obj)
        , _funName(funName)
      {}

      boost::python::object operator()(boost::python::tuple pyargs, boost::python::dict pykwargs) {
        qi::GenericValue val = qi::GenericValue::from(pyargs);
        bool async = boost::python::extract<bool>(pykwargs.get("_async", false));
        std::string funN = boost::python::extract<std::string>(pykwargs.get("_overload", _funName));
        qiLogDebug() << "calling a method: " << funN << " args:" << qi::encodeJSON(val);

        qi::Future<qi::GenericValuePtr> fut;
        {
          //calling c++, so release the GIL.
          GILScopedUnlock _unlock;
          fut = _object->metaCall(funN, val.asDynamic().asTupleValuePtr());
        }
        if (!async)
          return fut.value().to<boost::python::object>();
        else
          return qi::py::makeFuture(fut);
      }

    public:
      qi::ObjectPtr _object;
      std::string   _funName;
    };

    void populateMethods(boost::python::object pyobj, qi::ObjectPtr obj) {
      qi::MetaObject::MethodMap           mm = obj->metaObject().methodMap();
      qi::MetaObject::MethodMap::iterator it;
      for (it = mm.begin(); it != mm.end(); ++it) {
        qi::MetaMethod &mem = it->second;
        //drop special methods
        if (mem.uid() < qiObjectSpecialMemberMaxUid)
          continue;
        qiLogDebug() << "adding method:" << mem.toString();
        boost::python::object fun = boost::python::raw_function(PyQiFunctor(mem.name().c_str(), obj));
        boost::python::api::setattr(pyobj, mem.name().c_str(), fun);
        // Fill __doc__ with Signature and description
        std::stringstream ssdocstring;
        ssdocstring << "Signature: " << mem.returnSignature().toString() << "\n";
        ssdocstring << mem.description();
        boost::python::object docstring(ssdocstring.str());
        boost::python::api::setattr(fun, "__doc__", docstring);
      }
    }

    void populateSignals(boost::python::object pyobj, qi::ObjectPtr obj) {
      qi::MetaObject::SignalMap           mm = obj->metaObject().signalMap();
      qi::MetaObject::SignalMap::iterator it;
      for (it = mm.begin(); it != mm.end(); ++it) {
        qi::MetaSignal &ms = it->second;
        //drop special methods
        if (ms.uid() < qiObjectSpecialMemberMaxUid)
          continue;
        qiLogDebug() << "adding signal:" << ms.toString();
        boost::python::object fun = qi::py::makePyProxySignal(obj, ms);
        boost::python::api::setattr(pyobj, ms.name(), fun);
      }
    }

    void populateProperties(boost::python::object pyobj, qi::ObjectPtr obj) {
      qi::MetaObject::PropertyMap           mm = obj->metaObject().propertyMap();
      qi::MetaObject::PropertyMap::iterator it;
      for (it = mm.begin(); it != mm.end(); ++it) {
        qi::MetaProperty &mp = it->second;
        //drop special methods
        if (mp.uid() < qiObjectSpecialMemberMaxUid)
          continue;
        qiLogDebug() << "adding property:" << mp.toString();
        boost::python::object fun = qi::py::makePyProxyProperty(obj, mp);
        boost::python::api::setattr(pyobj, mp.name().c_str(), fun);
      }
    }

    class PyQiObject {
    public:
      PyQiObject()
      {}

      PyQiObject(const qi::ObjectPtr &obj)
        : _object(obj)
      {}

      boost::python::object call(boost::python::str pyname, boost::python::tuple pyargs, boost::python::dict pykws) {
        return PyQiFunctor(boost::python::extract<std::string>(pyname), _object)(pyargs, pykws);
      }

      boost::python::object metaObject() {
        return qi::GenericValueRef(_object->metaObject()).to<boost::python::object>();
      }

      qi::ObjectPtr object() {
        return _object;
      }

    private:
      qi::ObjectPtr _object;
    };

    boost::python::object makePyQiObject(qi::ObjectPtr obj, const std::string &name) {
      boost::python::object result = boost::python::object(qi::py::PyQiObject(obj));
      qi::py::populateMethods(result, obj);
      qi::py::populateSignals(result, obj);
      qi::py::populateProperties(result, obj);
      return result;
    }

    //TODO: DO NOT DUPLICATE
    static qi::GenericValuePtr pyCallMethod(const std::vector<qi::GenericValuePtr>& cargs, boost::python::object callable) {
      qi::py::GILScopedLock _lock;
      boost::python::list   args;
      boost::python::object ret;

      std::vector<qi::GenericValuePtr>::const_iterator it = cargs.begin();
      ++it; //drop the first arg which is DynamicObject*
      for (; it != cargs.end(); ++it) {
        qiLogDebug() << "argument: " << qi::encodeJSON(*it);
        args.append(it->to<boost::python::object>());
      }
      qiLogDebug() << "before method call";
      try {
        ret = callable(*boost::python::tuple(args));
      } catch (const boost::python::error_already_set &e) {
        std::string err = PyFormatError();
        qiLogDebug() << "call exception:" << err;
        throw std::runtime_error(err);
      }

      qi::GenericValuePtr gvret = qi::GenericValueRef(ret).clone();
      qiLogDebug() << "method returned:" << qi::encodeJSON(gvret);
      return gvret;
    }

    //callback just needed to keep a ref on obj
    static void doNothing(qi::GenericObject *go, boost::python::object obj)
    {
      (void)go;
      (void)obj;
    }

    qi::ObjectPtr makeQiObjectPtr(boost::python::object obj)
    {
      //is that a qi::ObjectPtr?
      boost::python::extract<PyQiObject*> isthatyoumum(obj);

      if (isthatyoumum.check()) {
        qiLogDebug() << "this PyObject is already a qi::ObjectPtr. Just returning it.";
        return isthatyoumum()->object();
      }

      qi::GenericObjectBuilder gob;
      GILScopedLock _lock;
      boost::python::object attrs(boost::python::borrowed(PyObject_Dir(obj.ptr())));

      for (int i = 0; i < boost::python::len(attrs); ++i) {
        std::string key = boost::python::extract<std::string>(attrs[i]);
        boost::python::object m = obj.attr(attrs[i]);
        if (PyMethod_Check(m.ptr())) {
          qi::MetaMethodBuilder mmb;
          mmb.setName(key);
          boost::python::object desc = m.attr("__doc__");
          if (desc)
            mmb.setDescription(boost::python::extract<std::string>(desc));
          boost::python::object inspect = import_inspect();
          //returns: (args, varargs, keywords, defaults)
          boost::python::object tu = inspect.attr("getargspec")(m);
          int argsz = boost::python::len(tu[0]);

          argsz = argsz > 0 ? argsz - 1 : 0;

          if (argsz < 0) {
            qiLogError() << "Method " << key << " is missing the self argument.";
            continue;
          }
          std::stringstream ss;
          ss << "(";
          for (int i = 0; i < argsz; ++i)
            ss << "m";
          ss << ")";
          qiLogDebug() << "Adding method: " << ss.str();
          mmb.setName(key);
          mmb.setParametersSignature(ss.str());
          mmb.setReturnSignature("m");
          gob.xAdvertiseMethod(mmb, qi::makeDynamicGenericFunction(boost::bind(pyCallMethod, _1, m)));
          continue;
        }

        //store a pointer on PySignal class
        static boost::python::object asignal = qi::py::makePySignal("(i)").attr("__class__");
        if (PyObject_IsInstance(m.ptr(), asignal.ptr())) {
          qiLogDebug() << "Adding signal:" << key;
          gob.advertiseSignal(key, qi::py::getSignal(m));
          continue;
        }

        //TODO: check for Property
        static boost::python::object aproperty = qi::py::makePyProperty("(i)").attr("__class__");
        if (PyObject_IsInstance(m.ptr(), aproperty.ptr())) {
          qiLogDebug() << "Adding property:" << key;
          gob.advertiseProperty(key, qi::py::getProperty(m));
          continue;
        }

      }
      //this is a useless callback, needed to keep a ref on obj.
      //when the GO is destructed, the ref is released.
      return gob.object(boost::bind<void>(&doNothing, _1, obj));
    }

    static boost::python::object pyobject_param_shrinker(boost::python::tuple args, boost::python::dict kwargs) {
      PyQiObject& pys = boost::python::extract<PyQiObject&>(args[0]);
      boost::python::list l;
      for (int i = 2; i < boost::python::len(args); ++i)
        l.append(args[i]);
      return pys.call(boost::python::extract<boost::python::str>(args[1]), boost::python::tuple(l), kwargs);
    }

    void export_pyobject() {
      boost::python::class_<qi::py::PyQiObject>("Object", boost::python::no_init)
          .def("call", boost::python::raw_function(&pyobject_param_shrinker, 1))
          //TODO: .def("post")
          //TODO: .def("setProperty")
          //TODO: .def("property")
          .def("metaObject", &qi::py::PyQiObject::metaObject);
      //import inspect in our current namespace
      import_inspect();
    }
  }
}
<|endoftext|>


<commit_before>#ifndef ANGELSCRIPTINTEGRATION_CALLSCRIPT_INL
#define ANGELSCRIPTINTEGRATION_CALLSCRIPT_INL

#include "../call-script.h"
#include "../change-working-dir.h"

#include <QFileInfo>

namespace AngelScriptIntegration {
namespace Implementation {

class ScriptContextReleaser
{
  AngelScript::asIScriptContext* const context;
public:

  ScriptContextReleaser(AngelScript::asIScriptContext* context)
    : context(context)
  {
  }

  ~ScriptContextReleaser()
  {
    context->Release();
  }
};

inline void _pass_arguments_to_angelscript(AngelScript::asIScriptContext*, int)
{
}

template<typename T_arg_i, typename... T_args>
void _pass_arguments_to_angelscript(AngelScript::asIScriptContext* context, int i, const T_arg_i& arg_i, const T_args&... other_args)
{
  pass_arg_to_angelscript(context, i, arg_i);

  _pass_arguments_to_angelscript(context, i+1, other_args...);
}

} // namespace Implementation

void CheckExecutionResult(AngelScript::asIScriptContext* context, int r);

template<typename T_return, typename... T_args>
T_return callScriptFunction(AngelScript::asIScriptFunction* function, const T_args&... args)
{
  Q_ASSERT(function != nullptr);
  AngelScript::asIScriptEngine* engine = function->GetEngine();

  AngelScript::asIScriptContext* context = engine->CreateContext();

  // Using the destructor to release the context to allow returning the return value directly
  Implementation::ScriptContextReleaser scriptContextReleaser(context);
  Q_UNUSED(scriptContextReleaser);

  Implementation::_pass_arguments_to_angelscript(context, 0, args...);

  context->Prepare(function);

  int r = context->Execute();

  CheckExecutionResult(context, r);

  return ResultFromAngelScript<T_return>::value(context);
}

template<typename T_return, typename... T_args>
T_return callScriptExt(AngelScript::asIScriptEngine* engine,
                       const std::string& filepath,
                       const char* functionDeclarationToCall,
                       const char* preferredModuleName,
                       const ConfigCallScript& config,
                       const T_args&... args)
{
  QFileInfo file(QString::fromStdString(filepath));

  std::string absoluteFilepath = file.absoluteFilePath().toStdString();

  ChangeWorkingDir cd(file.dir());

  std::string moduleName = getUniqueModuleName(engine, preferredModuleName);
  AngelScript::asIScriptModule* module = loadAndCompileModule(engine, absoluteFilepath.c_str(), moduleName.c_str(), config.accessMask);

  AngelScript::asIScriptFunction* function = module->GetFunctionByDecl(functionDeclarationToCall);

  Q_ASSERT(function != nullptr);
  Q_UNUSED(cd);

  return callScriptFunction<T_return>(function, args...);
}

template<typename T_return, typename... T_args>
T_return callScript(AngelScript::asIScriptEngine* engine,
                    const std::string& filepath,
                    const char* functionDeclarationToCall,
                    const char* preferredModuleName,
                    const T_args&... args)
{
  return callScript(engine, filepath, functionDeclarationToCall, preferredModuleName, ConfigCallScript(), args...);
}

} // namespace AngelScriptIntegration

#endif // ANGELSCRIPTINTEGRATION_CALLSCRIPT_INL

<commit_msg>major bugfix<commit_after>#ifndef ANGELSCRIPTINTEGRATION_CALLSCRIPT_INL
#define ANGELSCRIPTINTEGRATION_CALLSCRIPT_INL

#include "../call-script.h"
#include "../change-working-dir.h"

#include <QFileInfo>

namespace AngelScriptIntegration {
namespace Implementation {

class ScriptContextReleaser
{
  AngelScript::asIScriptContext* const context;
public:

  ScriptContextReleaser(AngelScript::asIScriptContext* context)
    : context(context)
  {
  }

  ~ScriptContextReleaser()
  {
    context->Release();
  }
};

inline void _pass_arguments_to_angelscript(AngelScript::asIScriptContext*, int)
{
}

template<typename T_arg_i, typename... T_args>
void _pass_arguments_to_angelscript(AngelScript::asIScriptContext* context, int i, const T_arg_i& arg_i, const T_args&... other_args)
{
  pass_arg_to_angelscript(context, i, arg_i);

  _pass_arguments_to_angelscript(context, i+1, other_args...);
}

} // namespace Implementation

void CheckExecutionResult(AngelScript::asIScriptContext* context, int r);

template<typename T_return, typename... T_args>
T_return callScriptFunction(AngelScript::asIScriptFunction* function, const T_args&... args)
{
  Q_ASSERT(function != nullptr);
  AngelScript::asIScriptEngine* engine = function->GetEngine();

  AngelScript::asIScriptContext* context = engine->CreateContext();

  // Using the destructor to release the context to allow returning the return value directly
  Implementation::ScriptContextReleaser scriptContextReleaser(context);
  Q_UNUSED(scriptContextReleaser);

  context->Prepare(function);

  Implementation::_pass_arguments_to_angelscript(context, 0, args...);

  int r = context->Execute();

  CheckExecutionResult(context, r);

  return ResultFromAngelScript<T_return>::value(context);
}

template<typename T_return, typename... T_args>
T_return callScriptExt(AngelScript::asIScriptEngine* engine,
                       const std::string& filepath,
                       const char* functionDeclarationToCall,
                       const char* preferredModuleName,
                       const ConfigCallScript& config,
                       const T_args&... args)
{
  QFileInfo file(QString::fromStdString(filepath));

  std::string absoluteFilepath = file.absoluteFilePath().toStdString();

  ChangeWorkingDir cd(file.dir());

  std::string moduleName = getUniqueModuleName(engine, preferredModuleName);
  AngelScript::asIScriptModule* module = loadAndCompileModule(engine, absoluteFilepath.c_str(), moduleName.c_str(), config.accessMask);

  AngelScript::asIScriptFunction* function = module->GetFunctionByDecl(functionDeclarationToCall);

  Q_ASSERT(function != nullptr);
  Q_UNUSED(cd);

  return callScriptFunction<T_return>(function, args...);
}

template<typename T_return, typename... T_args>
T_return callScript(AngelScript::asIScriptEngine* engine,
                    const std::string& filepath,
                    const char* functionDeclarationToCall,
                    const char* preferredModuleName,
                    const T_args&... args)
{
  return callScript(engine, filepath, functionDeclarationToCall, preferredModuleName, ConfigCallScript(), args...);
}

} // namespace AngelScriptIntegration

#endif // ANGELSCRIPTINTEGRATION_CALLSCRIPT_INL

<|endoftext|>


<commit_before>#include <QPrintDialog>
#include <QPainter>
#include <QDebug>
#include <QPrintPreviewWidget>
#include <QPrintPreviewDialog>
#include "converters/convertertopdf.hpp"
#include "converters/convertertohtml.hpp"
#include "engine.hpp"

namespace qtreports
{

    Engine::Engine( QObject * parent ) :
        QObject( parent ),
        m_isOpened( false ),
        m_connectionIsSet( false ),
        m_dataSourceIsSet( false )
    {}

    Engine::Engine( const QString & path, QObject * parent ) :
        Engine( parent )
    {
        open( path );
    }

    Engine::~Engine() {}

    bool	Engine::open( const QString & path )
    {
        if( isOpened() )
        {
            close();
        }

        detail::Parser parser;
        if( !parser.parse( path ) )
        {
            m_lastError = "Parsing error: " + parser.getLastError();
            return false;
        }

        m_isOpened = true;
        m_compiledPath = path;
        m_report = parser.getReport();

        fillColumnsFromReport(); //MB as ProcessedDB::createColumns( ReportPtr )

        return true;
    }

    bool    Engine::close()
    {
        m_isOpened = false;
        m_compiledPath.clear();
        m_report.clear();

        return true;
    }

    bool	Engine::setParameters( const QMap< QString, QString > & map )
    {
        if( m_report.isNull() )
        {
            m_lastError = "Report is empty. Please open report file";
            return false;
        }

        auto detail = m_report->getDetail();
        if( detail.isNull() )
        {
            m_lastError = "Report->Detail is empty. Please open report file";
            return false;
        }

        for( auto && band : detail->getBands() )
        {
            for( auto && textField : band->getTextFields() )
            {
                auto text = textField->getText();
                text = text.replace( "\n", "" ).replace( "\r", "" ).replace( " ", "" );
                if( text.startsWith( "$P{" ) && text.contains( "}" ) )
                {
                    auto name = text.split( "{" ).at( 1 ).split( "}" ).at( 0 );
                    textField->setText( map[ name ] );
                }
            }
        }

        return true;
    }

    bool	Engine::setConnection( const QSqlDatabase & connection )
    {
        if( !connection.isOpen() )
        {
            m_lastError = "Connection not open";
            return false;
        }

        if( m_report.isNull() )
        {
            m_lastError = "Report is empty. Please open report file";
            return false;
        }

        m_dbConnection = connection;
        m_connectionIsSet = true;

        if( !prepareDB() )
        {
            m_lastError = "Error in prepareDB: " + m_lastError;
            return false;
        }

        m_report->setRowCount( m_processedDB.getMaxRowCount() );

        for( auto && field : m_report->getFields() )
        {
            QVector < QVariant > tmp_vec;
            if( m_processedDB.getColumn( field->getName(), tmp_vec ) )
            {
                m_report->setFieldData( field->getName(), tmp_vec );
            }
        }

        return true;
    }

    bool    Engine::setDataSource( const QMap< QString, QVector< QVariant > > & source )
    {
        //Need check parameters
        //m_dataSource = columnsSet;
        m_dataSourceIsSet = true;

        prepareDataSource( source );

        return true;
    }

    bool    Engine::setQuery( const QString & query )
    {
        //Need check parameters
        auto queries = query.split( ";", QString::SkipEmptyParts );
        executeQueries( queries );

        m_lastError = query;
        return true;
    }

    bool    Engine::addScript( const QString & script )
    {
        //Need check parameters
        m_scripts.append( script );

        return true;
    }

    bool    Engine::setDataModel( const QAbstractItemModel & model )
    {
        //Need check parameters
        Q_UNUSED( model )
        return true;
    }

    bool	Engine::createPDF( const QString & path )
    {
        if( m_report.isNull() )
        {
            m_lastError = "Report is empty. Please open report file";
            return false;
        }

        detail::ConverterToPDF converter( m_report );
        auto result = converter.convert( path );
        if( !result )
        {
            m_lastError = converter.getLastError();
            return false;
        }

        return true;
    }

    bool	Engine::createHTML( const QString & path )
    {
        if( m_report.isNull() )
        {
            m_lastError = "Report is empty. Please open report file";
            return false;
        }

        detail::ConverterToHTML converter( m_report );
        auto result = converter.convert( path );
        if( !result )
        {
            m_lastError = converter.getLastError();
            return false;
        }

        return true;
    }

    const QWidgetPtr	Engine::createWidget()
    {
        if( m_report.isNull() )
        {
            m_lastError = "Report is empty. Please open report file";
            return QWidgetPtr();
        }

        detail::ConverterToQWidget converter( m_report );
        auto result = converter.convert( detail::ConverterToQWidget::WidgetType::Report );
        if( !result )
        {
            m_lastError = converter.getLastError();
            return QWidgetPtr();
        }

        return converter.getQWidget();
    }

    const QWidgetPtr	Engine::createLayout()
    {
        if( m_report.isNull() )
        {
            m_lastError = "Report is empty. Please open report file";
            return QWidgetPtr();
        }

        detail::ConverterToQWidget converter( m_report );
        auto result = converter.convert( detail::ConverterToQWidget::WidgetType::Layout );
        if( !result )
        {
            m_lastError = converter.getLastError();
            return QWidgetPtr();
        }

        return converter.getQWidget();
    }

    bool	Engine::print()
    {
        QPrinter printer;

        m_printedWidget = createWidget();
        if( m_printedWidget.isNull() )
        {
            m_lastError = "Cannot create widget. Error: " + m_lastError;
            return false;
        }

        m_printedWidget->resize( 595, 595 );

        //Magic
        m_printedWidget->show();
        m_printedWidget->hide();

        QPrintPreviewDialog preview( &printer );
        connect(
            &preview, &QPrintPreviewDialog::paintRequested,
            this, &Engine::drawPreview
            );
        preview.exec();

        m_printedWidget.clear();

        return true;
    }

    void	Engine::drawPreview( QPrinter * printer )
    {
        if( m_printedWidget.isNull() )
        {
            return;
        }

        QRectF rect = printer->pageRect();
        QPainter painter( printer );
        qreal scale = rect.width() / m_printedWidget->width();

        m_printedWidget->resize( m_printedWidget->width(), rect.height() / scale );
        painter.scale( scale, scale );

        auto height = m_printedWidget->height() * scale;
        auto count = static_cast< int >( std::ceil( height / rect.height() ) );
        for( int i = 0; i < count; ++i )
        {
            i != 0 ? printer->newPage() : 0;
            m_printedWidget->render( &painter, QPoint( 0, -i * rect.height() / scale ) );
        }
    }

    bool    Engine::prepareDB() {
        return setQuery( m_report->getQuery() );
    }

    void    Engine::prepareDataSource( const QMap< QString, QVector< QVariant > > & source )
    {
        QMapIterator <QString, QVector <QVariant> > iterator( source );
        while( iterator.hasNext() )
        {
            iterator.next();
            //m_processedDB.addFieldData( iterator.key(), iterator.value() );
            auto field = m_report->getField( iterator.key() );
            if( field.isNull() )
            {
                continue;
            }

            field->setData( iterator.value() );
        }
    }

    void    Engine::fillColumnsFromReport()
    {
        QMap <QString, detail::FieldPtr> fieldMap = m_report->getFields();
        QMapIterator <QString, detail::FieldPtr> fieldIterator( fieldMap );
        while( fieldIterator.hasNext() )
        {
            fieldIterator.next();
            m_processedDB.addColumn( fieldIterator.key() );
        }

        /*for( auto && field : m_report->getFields() )
        {
            m_processedDB.addColumn( field->getName() );
        }*/
    }

    void    Engine::executeQueries( const QStringList & queries )
    {
        /*
        QStringListIterator iterator(m_queriesList);
        while(iterator.hasNext()) {
            QString query = iterator.next();
            QSqlQueryModel * model = new QSqlQueryModel();
        */
        for( auto && query : queries )
        {
            auto model = new QSqlQueryModel();
            model->setQuery( query, m_dbConnection );
            for( int row = 0; row < model->rowCount(); row++ )
            {
                QSqlRecord rec = model->record( row );
                for( int col = 0; col < rec.count(); col++ )
                {
                    m_processedDB.addFieldData( rec.fieldName( col ), rec.field( col ).value() );
                }
            }
        }
    }

    bool    Engine::isOpened() const
    {
        return m_isOpened;
    }

    const QString   Engine::getLastError() const
    {
        return m_lastError;
    }

}
<commit_msg>Update engine.cpp<commit_after>#include <QPrintDialog>
#include <QPainter>
#include <QDebug>
#include <QPrintPreviewWidget>
#include <QPrintPreviewDialog>
#include "converters/convertertopdf.hpp"
#include "converters/convertertohtml.hpp"
#include "engine.hpp"

namespace qtreports
{

    Engine::Engine( QObject * parent ) :
        QObject( parent ),
        m_isOpened( false ),
        m_connectionIsSet( false ),
        m_dataSourceIsSet( false )
    {}

    Engine::Engine( const QString & path, QObject * parent ) :
        Engine( parent )
    {
        open( path );
    }

    Engine::~Engine() {}

    bool	Engine::open( const QString & path )
    {
        if( isOpened() )
        {
            close();
        }

        detail::Parser parser;
        if( !parser.parse( path ) )
        {
            m_lastError = "Parsing error: " + parser.getLastError();
            return false;
        }

        m_isOpened = true;
        m_compiledPath = path;
        m_report = parser.getReport();

        fillColumnsFromReport(); //MB as ProcessedDB::createColumns( ReportPtr )

        return true;
    }

    bool    Engine::close()
    {
        m_isOpened = false;
        m_compiledPath.clear();
        m_report.clear();

        return true;
    }

    bool	Engine::setParameters( const QMap< QString, QString > & map )
    {
        if( m_report.isNull() )
        {
            m_lastError = "Report is empty. Please open report file";
            return false;
        }

        auto detail = m_report->getDetail();
        if( detail.isNull() )
        {
            m_lastError = "Report->Detail is empty. Please open report file";
            return false;
        }

        for( auto && band : detail->getBands() )
        {
            for( auto && textField : band->getTextFields() )
            {
                auto text = textField->getText();
                text = text.replace( "\n", "" ).replace( "\r", "" ).replace( " ", "" );
                if( text.startsWith( "$P{" ) && text.contains( "}" ) )
                {
                    auto name = text.split( "{" ).at( 1 ).split( "}" ).at( 0 );
                    textField->setText( map[ name ] );
                }
            }
        }

        return true;
    }

    bool	Engine::setConnection( const QSqlDatabase & connection )
    {
        if( !connection.isOpen() )
        {
            m_lastError = "Connection not open";
            return false;
        }

        if( m_report.isNull() )
        {
            m_lastError = "Report is empty. Please open report file";
            return false;
        }

        m_dbConnection = connection;
        m_connectionIsSet = true;

        if( !prepareDB() )
        {
            m_lastError = "Error in prepareDB: " + m_lastError;
            return false;
        }

        m_report->setRowCount( m_processedDB.getMaxRowCount() );

        for( auto && field : m_report->getFields() )
        {
            QVector < QVariant > tmp_vec;
            if( m_processedDB.getColumn( field->getName(), tmp_vec ) )
            {
                m_report->setFieldData( field->getName(), tmp_vec );
            }
        }

        return true;
    }

    bool    Engine::setDataSource( const QMap< QString, QVector< QVariant > > & source )
    {
        //Need check parameters
        //m_dataSource = columnsSet;
        m_dataSourceIsSet = true;

        prepareDataSource( source );

        m_report->setRowCount( m_processedDB.getMaxRowCount() );

        for( auto && field : m_report->getFields() )
        {
            QVector < QVariant > tmp_vec;
            if( m_processedDB.getColumn( field->getName(), tmp_vec ) )
            {
                m_report->setFieldData( field->getName(), tmp_vec );
            }
        }

        return true;
    }

    bool    Engine::setQuery( const QString & query )
    {
        //Need check parameters
        auto queries = query.split( ";", QString::SkipEmptyParts );
        executeQueries( queries );

        m_lastError = query;
        return true;
    }

    bool    Engine::addScript( const QString & script )
    {
        //Need check parameters
        m_scripts.append( script );

        return true;
    }

    bool    Engine::setDataModel( const QAbstractItemModel & model )
    {
        //Need check parameters
        Q_UNUSED( model )
        return true;
    }

    bool	Engine::createPDF( const QString & path )
    {
        if( m_report.isNull() )
        {
            m_lastError = "Report is empty. Please open report file";
            return false;
        }

        detail::ConverterToPDF converter( m_report );
        auto result = converter.convert( path );
        if( !result )
        {
            m_lastError = converter.getLastError();
            return false;
        }

        return true;
    }

    bool	Engine::createHTML( const QString & path )
    {
        if( m_report.isNull() )
        {
            m_lastError = "Report is empty. Please open report file";
            return false;
        }

        detail::ConverterToHTML converter( m_report );
        auto result = converter.convert( path );
        if( !result )
        {
            m_lastError = converter.getLastError();
            return false;
        }

        return true;
    }

    const QWidgetPtr	Engine::createWidget()
    {
        if( m_report.isNull() )
        {
            m_lastError = "Report is empty. Please open report file";
            return QWidgetPtr();
        }

        detail::ConverterToQWidget converter( m_report );
        auto result = converter.convert( detail::ConverterToQWidget::WidgetType::Report );
        if( !result )
        {
            m_lastError = converter.getLastError();
            return QWidgetPtr();
        }

        return converter.getQWidget();
    }

    const QWidgetPtr	Engine::createLayout()
    {
        if( m_report.isNull() )
        {
            m_lastError = "Report is empty. Please open report file";
            return QWidgetPtr();
        }

        detail::ConverterToQWidget converter( m_report );
        auto result = converter.convert( detail::ConverterToQWidget::WidgetType::Layout );
        if( !result )
        {
            m_lastError = converter.getLastError();
            return QWidgetPtr();
        }

        return converter.getQWidget();
    }

    bool	Engine::print()
    {
        QPrinter printer;

        m_printedWidget = createWidget();
        if( m_printedWidget.isNull() )
        {
            m_lastError = "Cannot create widget. Error: " + m_lastError;
            return false;
        }

        m_printedWidget->resize( 595, 595 );

        //Magic
        m_printedWidget->show();
        m_printedWidget->hide();

        QPrintPreviewDialog preview( &printer );
        connect(
            &preview, &QPrintPreviewDialog::paintRequested,
            this, &Engine::drawPreview
            );
        preview.exec();

        m_printedWidget.clear();

        return true;
    }

    void	Engine::drawPreview( QPrinter * printer )
    {
        if( m_printedWidget.isNull() )
        {
            return;
        }

        QRectF rect = printer->pageRect();
        QPainter painter( printer );
        qreal scale = rect.width() / m_printedWidget->width();

        m_printedWidget->resize( m_printedWidget->width(), rect.height() / scale );
        painter.scale( scale, scale );

        auto height = m_printedWidget->height() * scale;
        auto count = static_cast< int >( std::ceil( height / rect.height() ) );
        for( int i = 0; i < count; ++i )
        {
            i != 0 ? printer->newPage() : 0;
            m_printedWidget->render( &painter, QPoint( 0, -i * rect.height() / scale ) );
        }
    }

    bool    Engine::prepareDB() {
        return setQuery( m_report->getQuery() );
    }

    void    Engine::prepareDataSource( const QMap< QString, QVector< QVariant > > & source )
    {
        QMapIterator <QString, QVector <QVariant> > iterator( source );
        while( iterator.hasNext() )
        {
            iterator.next();
            //m_processedDB.addFieldData( iterator.key(), iterator.value() );
            auto field = m_report->getField( iterator.key() );
            if( field.isNull() )
            {
                continue;
            }

            field->setData( iterator.value() );
        }
    }

    void    Engine::fillColumnsFromReport()
    {
        QMap <QString, detail::FieldPtr> fieldMap = m_report->getFields();
        QMapIterator <QString, detail::FieldPtr> fieldIterator( fieldMap );
        while( fieldIterator.hasNext() )
        {
            fieldIterator.next();
            m_processedDB.addColumn( fieldIterator.key() );
        }

        /*for( auto && field : m_report->getFields() )
        {
            m_processedDB.addColumn( field->getName() );
        }*/
    }

    void    Engine::executeQueries( const QStringList & queries )
    {
        /*
        QStringListIterator iterator(m_queriesList);
        while(iterator.hasNext()) {
            QString query = iterator.next();
            QSqlQueryModel * model = new QSqlQueryModel();
        */
        for( auto && query : queries )
        {
            auto model = new QSqlQueryModel();
            model->setQuery( query, m_dbConnection );
            for( int row = 0; row < model->rowCount(); row++ )
            {
                QSqlRecord rec = model->record( row );
                for( int col = 0; col < rec.count(); col++ )
                {
                    m_processedDB.addFieldData( rec.fieldName( col ), rec.field( col ).value() );
                }
            }
        }
    }

    bool    Engine::isOpened() const
    {
        return m_isOpened;
    }

    const QString   Engine::getLastError() const
    {
        return m_lastError;
    }

}
<|endoftext|>


<commit_before>#include <ir/index_manager/index/SkipListReader.h>
#include <ir/index_manager/utility/system.h>

//#define SKIP_DEBUG

NS_IZENELIB_IR_BEGIN

namespace indexmanager{

SkipListReader::SkipListReader(IndexInput* pSkipInput, int skipInterval, int numSkipLevels)
        : loaded_(false)
        , defaultSkipInterval_(skipInterval)
        , numSkipLevels_(numSkipLevels)
        , numSkipped_(0)
        , totalSkipped_(0)
        , lastDoc_(0)
        , lastSkipInterval_(0)
        , lastChildPointer_(0)
{
    init();
    skipStream_[0] = pSkipInput->clone();
}

SkipListReader::SkipListReader(VariantDataPool** pSkipLevels, int skipInterval, int numSkipLevels)
	: loaded_(false)
	, defaultSkipInterval_(skipInterval)
	, numSkipLevels_(numSkipLevels)
	, numSkipped_(0)
	, totalSkipped_(0)
	, lastDoc_(0)
	, lastSkipInterval_(0)
	, lastChildPointer_(0)
{
    init();
    for(int i = 0;i < numSkipLevels_;i++)
	skipStream_[i] = new VariantDataPoolInput(pSkipLevels[i]);
}

SkipListReader::~SkipListReader()
{
    std::vector<IndexInput*>::iterator iter =skipStream_.begin();
    for( ; iter != skipStream_.end(); ++iter)
        if(*iter)
            delete *iter;
}

docid_t SkipListReader::skipTo(docid_t target)
{
    if (!loaded_)
    {
        loadSkipLevels();
        loaded_ = true;
    }
    /// walk up the levels until highest level is found that has a skip for this target
    int level = 0;
    while (level < (numSkipLevels_-1) && target > skipDoc_[level + 1])
    {
        level++;
    }

    while (level >= 0)
    {
        if (target > skipDoc_[level])
        {
#ifdef SKIP_DEBUG
        cout<<"in level "<<level<<":";
#endif
            if (!loadNextSkip(level))
                continue;
        }
        else
        {
            /// no more skips on this level, go down one level
            if (level > 0 && lastChildPointer_ > skipStream_[level - 1]->getFilePointer())
            {
                seekChild(level - 1);
            }
            level--;
        }
    }
#ifdef SKIP_DEBUG
    cout<<"skipto result: doc "<<lastDoc_<<" totalskipped "<<totalSkipped_<<endl;
#endif
    return lastDoc_;
}

bool SkipListReader::nextSkip(docid_t docID)
{
    if (!loaded_)
    {
        loadSkipLevels();
        loaded_ = true;
    }
    if(skipDoc_[0] == 0)
    {
        if(!loadNextSkip(0))
            return false;
    }
    if(skipDoc_[0] <= docID)
    {
        loadNextSkip(0);
        return true;
    }
    return false;
}

void SkipListReader::seekChild(int level)
{
    skipStream_[level]->seek(lastChildPointer_);
    skipDoc_[level] = lastDoc_;
    offsets_[level] = lastOffset_;
    pOffsets_[level] = lastPOffset_;
    numSkipped_[level] = totalSkipped_;
    if (level > 0)
    {
        childPointer_[level] = skipStream_[level]->readVLong() + skipPointer_[level - 1];
    }
}

bool SkipListReader::loadNextSkip(int level)
{
    lastDoc_ = skipDoc_[level];
    lastSkipInterval_ = skipInterval_[level];
    lastChildPointer_ = childPointer_[level];
    lastOffset_ = offsets_[level];
    lastPOffset_ = pOffsets_[level];
    totalSkipped_ = numSkipped_[level];
#ifdef SKIP_DEBUG
    cout<<"lastdoc "<<lastDoc_<<" totalskipped "<<totalSkipped_<<",";
#endif
    if (skipStream_[level]->isEof())
    {
        /// this skip list is exhausted
        skipDoc_[level] = BAD_DOCID;
        return false;
    }

    /// read next skip entry
    readSkipPoint(level, skipStream_[level]);
    return true;
}

void SkipListReader::readSkipPoint(int level,IndexInput* pLevelInput)
{
    docid_t nDocDelta = pLevelInput->readVInt();
    if( (nDocDelta & 1) == 1)
        skipInterval_[level] = pLevelInput->readVInt();
    else
        skipInterval_[level] = getLevelSkipInterval(level);

    skipDoc_[level] += (nDocDelta >> 1);//pLevelInput->readVInt();
    offsets_[level] += pLevelInput->readVLong();
    pOffsets_[level] += pLevelInput->readVLong();
    numSkipped_[level] += skipInterval_[level];
#ifdef SKIP_DEBUG
    cout<<"doc "<<skipDoc_[level]<<" numSkipped_[level] "<<numSkipped_[level]<<",";
#endif
    if (level > 0)
    {
        /// read the child pointer if we are not on the leaf level
        childPointer_[level] = pLevelInput->readVLong() + skipPointer_[level- 1];
    }
}

void SkipListReader::loadSkipLevels()
{
    for (int i = numSkipLevels_-1; i >= 0; i--)
    {
        fileoffset_t length = skipStream_[0]->readVLong();
        skipPointer_[i] = skipStream_[0]->getFilePointer();
        if(i > 0)
        {
            skipStream_[i] = skipStream_[0]->clone();
        }
        skipStream_[i]->setlength(skipStream_[0]->getFilePointer() + length);
        if(i > 0)
        {
            skipStream_[0]->seek(skipStream_[0]->getFilePointer() + length);
        }
    }
}

}
NS_IZENELIB_IR_END

<commit_msg>in code review, fix potential bug in SkipListReader::skipTo(), it should load next skip point when the target equals to current point.<commit_after>#include <ir/index_manager/index/SkipListReader.h>
#include <ir/index_manager/utility/system.h>

//#define SKIP_DEBUG

NS_IZENELIB_IR_BEGIN

namespace indexmanager{

SkipListReader::SkipListReader(IndexInput* pSkipInput, int skipInterval, int numSkipLevels)
        : loaded_(false)
        , defaultSkipInterval_(skipInterval)
        , numSkipLevels_(numSkipLevels)
        , numSkipped_(0)
        , totalSkipped_(0)
        , lastDoc_(0)
        , lastSkipInterval_(0)
        , lastChildPointer_(0)
{
    init();
    skipStream_[0] = pSkipInput->clone();
}

SkipListReader::SkipListReader(VariantDataPool** pSkipLevels, int skipInterval, int numSkipLevels)
	: loaded_(false)
	, defaultSkipInterval_(skipInterval)
	, numSkipLevels_(numSkipLevels)
	, numSkipped_(0)
	, totalSkipped_(0)
	, lastDoc_(0)
	, lastSkipInterval_(0)
	, lastChildPointer_(0)
{
    init();
    for(int i = 0;i < numSkipLevels_;i++)
	skipStream_[i] = new VariantDataPoolInput(pSkipLevels[i]);
}

SkipListReader::~SkipListReader()
{
    std::vector<IndexInput*>::iterator iter =skipStream_.begin();
    for( ; iter != skipStream_.end(); ++iter)
        if(*iter)
            delete *iter;
}

docid_t SkipListReader::skipTo(docid_t target)
{
    if (!loaded_)
    {
        loadSkipLevels();
        loaded_ = true;
    }
    /// walk up the levels until highest level is found that has a skip for this target
    int level = 0;
    while (level < (numSkipLevels_-1) && target > skipDoc_[level + 1])
    {
        level++;
    }

    while (level >= 0)
    {
        if (target >= skipDoc_[level])
        {
#ifdef SKIP_DEBUG
        cout<<"in level "<<level<<":";
#endif
            if (!loadNextSkip(level))
                continue;
        }
        else
        {
            /// no more skips on this level, go down one level
            if (level > 0 && lastChildPointer_ > skipStream_[level - 1]->getFilePointer())
            {
                seekChild(level - 1);
            }
            level--;
        }
    }
#ifdef SKIP_DEBUG
    cout<<"skipto result: doc "<<lastDoc_<<" totalskipped "<<totalSkipped_<<endl;
#endif
    return lastDoc_;
}

bool SkipListReader::nextSkip(docid_t docID)
{
    if (!loaded_)
    {
        loadSkipLevels();
        loaded_ = true;
    }
    if(skipDoc_[0] == 0)
    {
        if(!loadNextSkip(0))
            return false;
    }
    if(skipDoc_[0] <= docID)
    {
        loadNextSkip(0);
        return true;
    }
    return false;
}

void SkipListReader::seekChild(int level)
{
    skipStream_[level]->seek(lastChildPointer_);
    skipDoc_[level] = lastDoc_;
    offsets_[level] = lastOffset_;
    pOffsets_[level] = lastPOffset_;
    numSkipped_[level] = totalSkipped_;
    if (level > 0)
    {
        childPointer_[level] = skipStream_[level]->readVLong() + skipPointer_[level - 1];
    }
}

bool SkipListReader::loadNextSkip(int level)
{
    lastDoc_ = skipDoc_[level];
    lastSkipInterval_ = skipInterval_[level];
    lastChildPointer_ = childPointer_[level];
    lastOffset_ = offsets_[level];
    lastPOffset_ = pOffsets_[level];
    totalSkipped_ = numSkipped_[level];
#ifdef SKIP_DEBUG
    cout<<"lastdoc "<<lastDoc_<<" totalskipped "<<totalSkipped_<<",";
#endif
    if (skipStream_[level]->isEof())
    {
        /// this skip list is exhausted
        skipDoc_[level] = BAD_DOCID;
        return false;
    }

    /// read next skip entry
    readSkipPoint(level, skipStream_[level]);
    return true;
}

void SkipListReader::readSkipPoint(int level,IndexInput* pLevelInput)
{
    docid_t nDocDelta = pLevelInput->readVInt();
    if( (nDocDelta & 1) == 1)
        skipInterval_[level] = pLevelInput->readVInt();
    else
        skipInterval_[level] = getLevelSkipInterval(level);

    skipDoc_[level] += (nDocDelta >> 1);//pLevelInput->readVInt();
    offsets_[level] += pLevelInput->readVLong();
    pOffsets_[level] += pLevelInput->readVLong();
    numSkipped_[level] += skipInterval_[level];
#ifdef SKIP_DEBUG
    cout<<"doc "<<skipDoc_[level]<<" numSkipped_[level] "<<numSkipped_[level]<<",";
#endif
    if (level > 0)
    {
        /// read the child pointer if we are not on the leaf level
        childPointer_[level] = pLevelInput->readVLong() + skipPointer_[level- 1];
    }
}

void SkipListReader::loadSkipLevels()
{
    for (int i = numSkipLevels_-1; i >= 0; i--)
    {
        fileoffset_t length = skipStream_[0]->readVLong();
        skipPointer_[i] = skipStream_[0]->getFilePointer();
        if(i > 0)
        {
            skipStream_[i] = skipStream_[0]->clone();
        }
        skipStream_[i]->setlength(skipStream_[0]->getFilePointer() + length);
        if(i > 0)
        {
            skipStream_[0]->seek(skipStream_[0]->getFilePointer() + length);
        }
    }
}

}
NS_IZENELIB_IR_END

<|endoftext|>


<commit_before>#include "Game.h"
#include "Renderer.h"
#include <algorithm>

Game::Game(Field f, std::vector<Player *> p)
{
	GameField = f;
	Players = p;
	CurrentFrame = 0;
	PacmanLives = 3;
	GameOver = 0;
	Paused = 0;

	for (std::size_t i = 0; i < FIELD_WIDTH; i++)
	{
		for (std::size_t j = 0; j < FIELD_HEIGHT; j++)
		{
			if ((f.Tiles[i][j] & Field::Pellet) == Field::Pellet)
			{
				AllPellets.Eat(i, j);
			}
		}
	}
}

Game::Game(const Game &other)
{
	GameField = other.GameField;
	AllPellets = other.AllPellets;
	Pellets = other.Pellets;
	CurrentFrame = other.CurrentFrame;
	PacmanLives = other.PacmanLives;
	GameOver = other.GameOver;
	Paused = other.Paused;
	Players = std::vector<Player *>();
	for (std::size_t i = 0, size = other.Players.size(); i < size; i++)
	{
		Players.push_back(other.Players[i]->Clone());
	}
}

Game::~Game()
{
	for (std::size_t i = 0, size = Players.size(); i < size; i++)
	{
		delete Players[i];
	}
}

Game& Game::operator=(const Game& rhs)
{
	GameField = rhs.GameField;
	AllPellets = rhs.AllPellets;
	Pellets = rhs.Pellets;
	CurrentFrame = rhs.CurrentFrame;
	PacmanLives = rhs.PacmanLives;
	GameOver = rhs.GameOver;
	Paused = rhs.Paused;
	for (std::size_t i = 0, size = Players.size(); i < size; i++)
	{
		delete Players[i];
	}
	Players = std::vector<Player *>();
	for (std::size_t i = 0, size = rhs.Players.size(); i < size; i++)
	{
		Players.push_back(rhs.Players[i]->Clone());
	}
	return *this;
}

bool Game::update()
{
	if (Paused > 0)
	{
		Paused--;
		CurrentFrame++;
		return true;
	}

	if (GameOver > 0)
	{
		GameOver--;
		CurrentFrame++;
		if (GameOver == 0)
		{
			return false;
		}
		return true;
	}
	else if (GameOver < 0)
	{
		GameOver++;
		CurrentFrame++;
		if (GameOver == 0)
		{
			return false;
		}
		return true;
	}

	Player::Event event = Player::None;
	for (std::size_t i = 0, size = Players.size(); i < size; i++)
	{
		Player *p = Players[i];
		event = (Player::Event)(event | p->Move(&GameField, Pellets));
	}
	for (unsigned int i = 0, size = Players.size(); i < size; i++)
	{
		for (unsigned int j = 0; j < size; j++)
		{
			Position difference =
				Players[i]->CurrentPos + (Players[j]->CurrentPos * -1);
			if (i != j
					&& difference.X > -8 && difference.X < 8
					&& difference.Y > -8 && difference.Y < 8)
			{
				Player::Event e;
				Player *clone_i = Players[i]->Clone();
				Player *clone_j = Players[j]->Clone();
				event = (Player::Event)(event | Players[i]->CollideWith(clone_j));
				event = (Player::Event)(event | Players[j]->CollideWith(clone_i));
				delete clone_i;
				delete clone_j;
			}
		}
	}
	if (event != Player::None)
	{
		if (event & Player::PacmanRespawned)
		{
			PacmanLives--;
		}
		if (event & Player::GhostDied)
		{
			Paused += 30;
		}
		for (std::size_t i = 0, size = Players.size(); i < size; i++)
		{
			Players[i]->ProcessEvent(event);
		}
	}

	if (Pellets == AllPellets)
	{
		GameOver = 180;
	}
	else if (PacmanLives == 0)
	{
		GameOver = -180;
	}
	CurrentFrame++;
	return true;
}

void Game::draw() const
{
	for (std::size_t i = 0, size = Players.size(); i < size; i++)
	{
		Players[i]->Draw();
	}
	if (GameOver > 0)
	{
		Renderer::DrawText("Pac-Man wins!", 24, 228, 444);
	}
	else if (GameOver < 0)
	{
		Renderer::DrawText("Ghosts win!", 24, 252, 444);
	}
}
<commit_msg>Removed unused variable<commit_after>#include "Game.h"
#include "Renderer.h"
#include <algorithm>

Game::Game(Field f, std::vector<Player *> p)
{
	GameField = f;
	Players = p;
	CurrentFrame = 0;
	PacmanLives = 3;
	GameOver = 0;
	Paused = 0;

	for (std::size_t i = 0; i < FIELD_WIDTH; i++)
	{
		for (std::size_t j = 0; j < FIELD_HEIGHT; j++)
		{
			if ((f.Tiles[i][j] & Field::Pellet) == Field::Pellet)
			{
				AllPellets.Eat(i, j);
			}
		}
	}
}

Game::Game(const Game &other)
{
	GameField = other.GameField;
	AllPellets = other.AllPellets;
	Pellets = other.Pellets;
	CurrentFrame = other.CurrentFrame;
	PacmanLives = other.PacmanLives;
	GameOver = other.GameOver;
	Paused = other.Paused;
	Players = std::vector<Player *>();
	for (std::size_t i = 0, size = other.Players.size(); i < size; i++)
	{
		Players.push_back(other.Players[i]->Clone());
	}
}

Game::~Game()
{
	for (std::size_t i = 0, size = Players.size(); i < size; i++)
	{
		delete Players[i];
	}
}

Game& Game::operator=(const Game& rhs)
{
	GameField = rhs.GameField;
	AllPellets = rhs.AllPellets;
	Pellets = rhs.Pellets;
	CurrentFrame = rhs.CurrentFrame;
	PacmanLives = rhs.PacmanLives;
	GameOver = rhs.GameOver;
	Paused = rhs.Paused;
	for (std::size_t i = 0, size = Players.size(); i < size; i++)
	{
		delete Players[i];
	}
	Players = std::vector<Player *>();
	for (std::size_t i = 0, size = rhs.Players.size(); i < size; i++)
	{
		Players.push_back(rhs.Players[i]->Clone());
	}
	return *this;
}

bool Game::update()
{
	if (Paused > 0)
	{
		Paused--;
		CurrentFrame++;
		return true;
	}

	if (GameOver > 0)
	{
		GameOver--;
		CurrentFrame++;
		if (GameOver == 0)
		{
			return false;
		}
		return true;
	}
	else if (GameOver < 0)
	{
		GameOver++;
		CurrentFrame++;
		if (GameOver == 0)
		{
			return false;
		}
		return true;
	}

	Player::Event event = Player::None;
	for (std::size_t i = 0, size = Players.size(); i < size; i++)
	{
		Player *p = Players[i];
		event = (Player::Event)(event | p->Move(&GameField, Pellets));
	}
	for (unsigned int i = 0, size = Players.size(); i < size; i++)
	{
		for (unsigned int j = 0; j < size; j++)
		{
			Position difference =
				Players[i]->CurrentPos + (Players[j]->CurrentPos * -1);
			if (i != j
					&& difference.X > -8 && difference.X < 8
					&& difference.Y > -8 && difference.Y < 8)
			{
				Player *clone_i = Players[i]->Clone();
				Player *clone_j = Players[j]->Clone();
				event = (Player::Event)(event | Players[i]->CollideWith(clone_j));
				event = (Player::Event)(event | Players[j]->CollideWith(clone_i));
				delete clone_i;
				delete clone_j;
			}
		}
	}
	if (event != Player::None)
	{
		if (event & Player::PacmanRespawned)
		{
			PacmanLives--;
		}
		if (event & Player::GhostDied)
		{
			Paused += 30;
		}
		for (std::size_t i = 0, size = Players.size(); i < size; i++)
		{
			Players[i]->ProcessEvent(event);
		}
	}

	if (Pellets == AllPellets)
	{
		GameOver = 180;
	}
	else if (PacmanLives == 0)
	{
		GameOver = -180;
	}
	CurrentFrame++;
	return true;
}

void Game::draw() const
{
	for (std::size_t i = 0, size = Players.size(); i < size; i++)
	{
		Players[i]->Draw();
	}
	if (GameOver > 0)
	{
		Renderer::DrawText("Pac-Man wins!", 24, 228, 444);
	}
	else if (GameOver < 0)
	{
		Renderer::DrawText("Ghosts win!", 24, 252, 444);
	}
}
<|endoftext|>


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

  Program:   Visualization Toolkit
  Module:    vtkImageWriter.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

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

=========================================================================*/
#include "vtkImageWriter.h"

#include "vtkCommand.h"
#include "vtkErrorCode.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"
#include "vtkPointData.h"
#include "vtkStreamingDemandDrivenPipeline.h"
#include "vtkImageData.h"

#if !defined(_WIN32) || defined(__CYGWIN__)
# include <unistd.h> /* unlink */
#else
# include <io.h> /* unlink */
#endif

vtkCxxRevisionMacro(vtkImageWriter, "1.60");
vtkStandardNewMacro(vtkImageWriter);

#ifdef write
#undef write
#endif

#ifdef close
#undef close
#endif

//----------------------------------------------------------------------------
vtkImageWriter::vtkImageWriter()
{
  this->FilePrefix = NULL;
  this->FilePattern = NULL;
  this->FileName = NULL;
  this->InternalFileName = NULL;
  this->FileNumber = 0;
  this->FileDimensionality = 2;

  this->FilePattern = new char[strlen("%s.%d") + 1];
  strcpy(this->FilePattern, "%s.%d");

  this->FileLowerLeft = 0;

  this->MinimumFileNumber = this->MaximumFileNumber = 0;
  this->FilesDeleted = 0;
  this->SetNumberOfOutputPorts(0);
}

//----------------------------------------------------------------------------
vtkImageWriter::~vtkImageWriter()
{
  // get rid of memory allocated for file names
  if (this->FilePrefix)
    {
    delete [] this->FilePrefix;
    this->FilePrefix = NULL;
    }
  if (this->FilePattern)
    {
    delete [] this->FilePattern;
    this->FilePattern = NULL;
    }
  if (this->FileName)
    {
    delete [] this->FileName;
    this->FileName = NULL;
    }
}

//----------------------------------------------------------------------------
void vtkImageWriter::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);

  os << indent << "FileName: " <<
    (this->FileName ? this->FileName : "(none)") << "\n";
  os << indent << "FilePrefix: " <<
    (this->FilePrefix ? this->FilePrefix : "(none)") << "\n";
  os << indent << "FilePattern: " <<
    (this->FilePattern ? this->FilePattern : "(none)") << "\n";

  os << indent << "FileDimensionality: " << this->FileDimensionality << "\n";
}

//----------------------------------------------------------------------------
vtkImageData *vtkImageWriter::GetInput()
{
  if (this->GetNumberOfInputConnections(0) < 1)
    {
    return 0;
    }
  return vtkImageData::SafeDownCast(
    this->GetExecutive()->GetInputData(0, 0));
}
//----------------------------------------------------------------------------

int vtkImageWriter::RequestData(
  vtkInformation* vtkNotUsed( request ),
  vtkInformationVector** inputVector,
  vtkInformationVector* vtkNotUsed( outputVector) )
{
  this->SetErrorCode(vtkErrorCode::NoError);

  vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
  vtkImageData *input =
    vtkImageData::SafeDownCast(inInfo->Get(vtkDataObject::DATA_OBJECT()));

  // Error checking
  if (input == NULL )
    {
    vtkErrorMacro(<<"Write:Please specify an input!");
    return 0;
    }
  if ( !this->FileName && !this->FilePattern)
    {
    vtkErrorMacro(<<"Write:Please specify either a FileName or a file prefix and pattern");
    this->SetErrorCode(vtkErrorCode::NoFileNameError);
    return 0;
    }

  // Make sure the file name is allocated
  this->InternalFileName =
    new char[(this->FileName ? strlen(this->FileName) : 1) +
            (this->FilePrefix ? strlen(this->FilePrefix) : 1) +
            (this->FilePattern ? strlen(this->FilePattern) : 1) + 10];

  // Fill in image information.
  int *wExt = inInfo->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT());
  this->FileNumber = wExt[4];
  this->MinimumFileNumber = this->MaximumFileNumber = this->FileNumber;
  this->FilesDeleted = 0;

  // Write
  this->InvokeEvent(vtkCommand::StartEvent);
  this->UpdateProgress(0.0);
  this->RecursiveWrite(2, input, NULL);

  if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
    {
    this->DeleteFiles();
    }

  this->UpdateProgress(1.0);
  this->InvokeEvent(vtkCommand::EndEvent);

  delete [] this->InternalFileName;
  this->InternalFileName = NULL;

  return 1;
}

//----------------------------------------------------------------------------
// Writes all the data from the input.
void vtkImageWriter::Write()
{
  // we always write, even if nothing has changed, so send a modified
  this->Modified();
  this->UpdateInformation();
  this->GetInput()->SetUpdateExtent(this->GetInput()->GetWholeExtent());
  this->Update();
}

//----------------------------------------------------------------------------
// Breaks region into pieces with correct dimensionality.
void vtkImageWriter::RecursiveWrite(int axis, vtkImageData *cache,
                                    ofstream *file)
{
  vtkImageData    *data;
  int             fileOpenedHere = 0;
  int             *ext;

  // if we need to open another slice, do it
  if (!file && (axis + 1) == this->FileDimensionality)
    {
    // determine the name
    if (this->FileName)
      {
      sprintf(this->InternalFileName,"%s",this->FileName);
      }
    else
      {
      if (this->FilePrefix)
        {
        sprintf(this->InternalFileName, this->FilePattern,
                this->FilePrefix, this->FileNumber);
        }
      else
        {
        sprintf(this->InternalFileName, this->FilePattern,this->FileNumber);
        }
      if (this->FileNumber < this->MinimumFileNumber)
        {
        this->MinimumFileNumber = this->FileNumber;
        }
      else if (this->FileNumber > this->MaximumFileNumber)
        {
        this->MaximumFileNumber = this->FileNumber;
        }
      }
    // Open the file
#ifdef _WIN32
    file = new ofstream(this->InternalFileName, ios::out | ios::binary);
#else
    file = new ofstream(this->InternalFileName, ios::out);
#endif
    fileOpenedHere = 1;
    if (file->fail())
      {
      vtkErrorMacro("RecursiveWrite: Could not open file " <<
                    this->InternalFileName);
      this->SetErrorCode(vtkErrorCode::CannotOpenFileError);
      delete file;
      return;
      }

    // Subclasses can write a header with this method call.
    this->WriteFileHeader(file, cache);
    file->flush();
    if (file->fail())
      {
      file->close();
      delete file;
      this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
      return;
      }
    ++this->FileNumber;
    }

  // Propagate the update extent so we can determine pipeline size
  this->GetInput()->PropagateUpdateExtent();

  // just get the data and write it out
  ext = cache->GetUpdateExtent();
  vtkDebugMacro("Getting input extent: " << ext[0] << ", " <<
                ext[1] << ", " << ext[2] << ", " << ext[3] << ", " <<
                ext[4] << ", " << ext[5] << endl);
  cache->Update();
  data = cache;
  this->RecursiveWrite(axis,cache,data,file);
  if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
    {
    this->DeleteFiles();
    return;
    }
  if (file && fileOpenedHere)
    {
    this->WriteFileTrailer(file,cache);
    file->flush();
    if (file->fail())
      {
      this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
      }
    file->close();
    delete file;
    }
  return;
}

//----------------------------------------------------------------------------
// same idea as the previous method, but it knows that the data is ready
void vtkImageWriter::RecursiveWrite(int axis, vtkImageData *cache,
                                    vtkImageData *data, ofstream *file)
{
  int idx, min, max;

  // if the file is already open then just write to it
  if (file)
    {
    this->WriteFile(file,data,cache->GetUpdateExtent());
    file->flush();
    if (file->fail())
      {
      file->close();
      delete file;
      this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
      }
    return;
    }

  // if we need to open another slice, do it
  if (!file && (axis + 1) == this->FileDimensionality)
    {
    // determine the name
    if (this->FileName)
      {
      sprintf(this->InternalFileName,"%s",this->FileName);
      }
    else
      {
      if (this->FilePrefix)
        {
        sprintf(this->InternalFileName, this->FilePattern,
                this->FilePrefix, this->FileNumber);
        }
      else
        {
        sprintf(this->InternalFileName, this->FilePattern,this->FileNumber);
        }
      if (this->FileNumber < this->MinimumFileNumber)
        {
        this->MinimumFileNumber = this->FileNumber;
        }
      else if (this->FileNumber > this->MaximumFileNumber)
        {
        this->MaximumFileNumber = this->FileNumber;
        }
      }
    // Open the file
#ifdef _WIN32
    file = new ofstream(this->InternalFileName, ios::out | ios::binary);
#else
    file = new ofstream(this->InternalFileName, ios::out);
#endif
    if (file->fail())
      {
      vtkErrorMacro("RecursiveWrite: Could not open file " <<
                    this->InternalFileName);
      this->SetErrorCode(vtkErrorCode::CannotOpenFileError);
      delete file;
      return;
      }

    // Subclasses can write a header with this method call.
    this->WriteFileHeader(file, cache);
    file->flush();
    if (file->fail())
      {
      file->close();
      delete file;
      this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
      return;
      }
    this->WriteFile(file,data,cache->GetUpdateExtent());
    file->flush();
    if (file->fail())
      {
      file->close();
      delete file;
      this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
      return;
      }
    ++this->FileNumber;
    this->WriteFileTrailer(file,cache);
    file->flush();
    if (file->fail())
      {
      this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
      }
    file->close();
    delete file;
    return;
    }

  // if the current region is too high a dimension forthe file
  // the we will split the current axis
  cache->GetAxisUpdateExtent(axis, min, max);

  // if it is the y axis then flip by default
  if (axis == 1 && !this->FileLowerLeft)
    {
    for(idx = max; idx >= min; idx--)
      {
      cache->SetAxisUpdateExtent(axis, idx, idx);
      if (this->ErrorCode != vtkErrorCode::OutOfDiskSpaceError)
        {
        this->RecursiveWrite(axis - 1, cache, data, file);
        }
      else
        {
        this->DeleteFiles();
        }
      }
    }
  else
    {
    for(idx = min; idx <= max; idx++)
      {
      cache->SetAxisUpdateExtent(axis, idx, idx);
      if (this->ErrorCode != vtkErrorCode::OutOfDiskSpaceError)
        {
        this->RecursiveWrite(axis - 1, cache, data, file);
        }
      else
        {
        this->DeleteFiles();
        }
      }
    }

  // restore original extent
  cache->SetAxisUpdateExtent(axis, min, max);
}

//----------------------------------------------------------------------------
template <class T>
unsigned long vtkImageWriterGetSize(T*)
{
  return sizeof(T);
}

//----------------------------------------------------------------------------
// Writes a region in a file.  Subclasses can override this method
// to produce a header. This method only hanldes 3d data (plus components).
void vtkImageWriter::WriteFile(ofstream *file, vtkImageData *data,
                               int extent[6])
{
  int idxY, idxZ;
  int rowLength; // in bytes
  void *ptr;
  unsigned long count = 0;
  unsigned long target;
  float progress = this->Progress;
  float area;
  int *wExtent;

  // Make sure we actually have data.
  if ( !data->GetPointData()->GetScalars())
    {
    vtkErrorMacro(<< "Could not get data from input.");
    return;
    }

  // take into consideration the scalar type
  switch (data->GetScalarType())
    {
    vtkTemplateMacro(
      rowLength = vtkImageWriterGetSize(static_cast<VTK_TT*>(0))
      );
    default:
      vtkErrorMacro(<< "Execute: Unknown output ScalarType");
      return;
    }
  rowLength *= data->GetNumberOfScalarComponents();
  rowLength *= (extent[1] - extent[0] + 1);

  wExtent = this->GetInput()->GetWholeExtent();
  area = (float) ((extent[5] - extent[4] + 1)*
                  (extent[3] - extent[2] + 1)*
                  (extent[1] - extent[0] + 1)) /
         (float) ((wExtent[5] -wExtent[4] + 1)*
                  (wExtent[3] -wExtent[2] + 1)*
                  (wExtent[1] -wExtent[0] + 1));

  target = (unsigned long)((extent[5]-extent[4]+1)*
                           (extent[3]-extent[2]+1)/(50.0*area));
  target++;

  int ystart = extent[3];
  int yend = extent[2] - 1;
  int yinc = -1;
  if (this->FileLowerLeft)
    {
    ystart = extent[2];
    yend = extent[3]+1;
    yinc = 1;
    }

  for (idxZ = extent[4]; idxZ <= extent[5]; ++idxZ)
    {
    for (idxY = ystart; idxY != yend; idxY = idxY + yinc)
      {
      if (!(count%target))
        {
        this->UpdateProgress(progress + count/(50.0*target));
        }
      count++;
      ptr = data->GetScalarPointer(extent[0], idxY, idxZ);
      if ( ! file->write((char *)ptr, rowLength))
        {
        return;
        }
      }
    }
}

void vtkImageWriter::DeleteFiles()
{
  if (this->FilesDeleted)
    {
    return;
    }
  int i;
  char *fileName;

  vtkErrorMacro("Ran out of disk space; deleting file(s) already written");

  if (this->FileName)
    {
    unlink(this->FileName);
    }
  else
    {
    if (this->FilePrefix)
      {
      fileName =
        new char[strlen(this->FilePrefix) + strlen(this->FilePattern) + 10];

      for (i = this->MinimumFileNumber; i <= this->MaximumFileNumber; i++)
        {
        sprintf(fileName, this->FilePattern, this->FilePrefix, i);
        unlink(fileName);
        }
      delete [] fileName;
      }
    else
      {
      fileName = new char[strlen(this->FilePattern) + 10];

      for (i = this->MinimumFileNumber; i <= this->MaximumFileNumber; i++)
        {
        sprintf(fileName, this->FilePattern, i);
        unlink(fileName);
        }
      delete [] fileName;
      }
    }
  this->FilesDeleted = 1;
}
<commit_msg>ENH: more robust way to remove file on win32<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkImageWriter.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

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

=========================================================================*/
#include "vtkImageWriter.h"

#include "vtkCommand.h"
#include "vtkErrorCode.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"
#include "vtkPointData.h"
#include "vtkStreamingDemandDrivenPipeline.h"
#include "vtkImageData.h"

#include <vtksys/SystemTools.hxx>

vtkCxxRevisionMacro(vtkImageWriter, "1.61");
vtkStandardNewMacro(vtkImageWriter);

//----------------------------------------------------------------------------
vtkImageWriter::vtkImageWriter()
{
  this->FilePrefix = NULL;
  this->FilePattern = NULL;
  this->FileName = NULL;
  this->InternalFileName = NULL;
  this->FileNumber = 0;
  this->FileDimensionality = 2;

  this->FilePattern = new char[strlen("%s.%d") + 1];
  strcpy(this->FilePattern, "%s.%d");

  this->FileLowerLeft = 0;

  this->MinimumFileNumber = this->MaximumFileNumber = 0;
  this->FilesDeleted = 0;
  this->SetNumberOfOutputPorts(0);
}

//----------------------------------------------------------------------------
vtkImageWriter::~vtkImageWriter()
{
  // get rid of memory allocated for file names
  if (this->FilePrefix)
    {
    delete [] this->FilePrefix;
    this->FilePrefix = NULL;
    }
  if (this->FilePattern)
    {
    delete [] this->FilePattern;
    this->FilePattern = NULL;
    }
  if (this->FileName)
    {
    delete [] this->FileName;
    this->FileName = NULL;
    }
}

//----------------------------------------------------------------------------
void vtkImageWriter::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);

  os << indent << "FileName: " <<
    (this->FileName ? this->FileName : "(none)") << "\n";
  os << indent << "FilePrefix: " <<
    (this->FilePrefix ? this->FilePrefix : "(none)") << "\n";
  os << indent << "FilePattern: " <<
    (this->FilePattern ? this->FilePattern : "(none)") << "\n";

  os << indent << "FileDimensionality: " << this->FileDimensionality << "\n";
}

//----------------------------------------------------------------------------
vtkImageData *vtkImageWriter::GetInput()
{
  if (this->GetNumberOfInputConnections(0) < 1)
    {
    return 0;
    }
  return vtkImageData::SafeDownCast(
    this->GetExecutive()->GetInputData(0, 0));
}
//----------------------------------------------------------------------------

int vtkImageWriter::RequestData(
  vtkInformation* vtkNotUsed( request ),
  vtkInformationVector** inputVector,
  vtkInformationVector* vtkNotUsed( outputVector) )
{
  this->SetErrorCode(vtkErrorCode::NoError);

  vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
  vtkImageData *input =
    vtkImageData::SafeDownCast(inInfo->Get(vtkDataObject::DATA_OBJECT()));

  // Error checking
  if (input == NULL )
    {
    vtkErrorMacro(<<"Write:Please specify an input!");
    return 0;
    }
  if ( !this->FileName && !this->FilePattern)
    {
    vtkErrorMacro(<<"Write:Please specify either a FileName or a file prefix and pattern");
    this->SetErrorCode(vtkErrorCode::NoFileNameError);
    return 0;
    }

  // Make sure the file name is allocated
  this->InternalFileName =
    new char[(this->FileName ? strlen(this->FileName) : 1) +
            (this->FilePrefix ? strlen(this->FilePrefix) : 1) +
            (this->FilePattern ? strlen(this->FilePattern) : 1) + 10];

  // Fill in image information.
  int *wExt = inInfo->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT());
  this->FileNumber = wExt[4];
  this->MinimumFileNumber = this->MaximumFileNumber = this->FileNumber;
  this->FilesDeleted = 0;

  // Write
  this->InvokeEvent(vtkCommand::StartEvent);
  this->UpdateProgress(0.0);
  this->RecursiveWrite(2, input, NULL);

  if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
    {
    this->DeleteFiles();
    }

  this->UpdateProgress(1.0);
  this->InvokeEvent(vtkCommand::EndEvent);

  delete [] this->InternalFileName;
  this->InternalFileName = NULL;

  return 1;
}

//----------------------------------------------------------------------------
// Writes all the data from the input.
void vtkImageWriter::Write()
{
  // we always write, even if nothing has changed, so send a modified
  this->Modified();
  this->UpdateInformation();
  this->GetInput()->SetUpdateExtent(this->GetInput()->GetWholeExtent());
  this->Update();
}

//----------------------------------------------------------------------------
// Breaks region into pieces with correct dimensionality.
void vtkImageWriter::RecursiveWrite(int axis, vtkImageData *cache,
                                    ofstream *file)
{
  vtkImageData    *data;
  int             fileOpenedHere = 0;
  int             *ext;

  // if we need to open another slice, do it
  if (!file && (axis + 1) == this->FileDimensionality)
    {
    // determine the name
    if (this->FileName)
      {
      sprintf(this->InternalFileName,"%s",this->FileName);
      }
    else
      {
      if (this->FilePrefix)
        {
        sprintf(this->InternalFileName, this->FilePattern,
                this->FilePrefix, this->FileNumber);
        }
      else
        {
        sprintf(this->InternalFileName, this->FilePattern,this->FileNumber);
        }
      if (this->FileNumber < this->MinimumFileNumber)
        {
        this->MinimumFileNumber = this->FileNumber;
        }
      else if (this->FileNumber > this->MaximumFileNumber)
        {
        this->MaximumFileNumber = this->FileNumber;
        }
      }
    // Open the file
#ifdef _WIN32
    file = new ofstream(this->InternalFileName, ios::out | ios::binary);
#else
    file = new ofstream(this->InternalFileName, ios::out);
#endif
    fileOpenedHere = 1;
    if (file->fail())
      {
      vtkErrorMacro("RecursiveWrite: Could not open file " <<
                    this->InternalFileName);
      this->SetErrorCode(vtkErrorCode::CannotOpenFileError);
      delete file;
      return;
      }

    // Subclasses can write a header with this method call.
    this->WriteFileHeader(file, cache);
    file->flush();
    if (file->fail())
      {
      file->close();
      delete file;
      this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
      return;
      }
    ++this->FileNumber;
    }

  // Propagate the update extent so we can determine pipeline size
  this->GetInput()->PropagateUpdateExtent();

  // just get the data and write it out
  ext = cache->GetUpdateExtent();
  vtkDebugMacro("Getting input extent: " << ext[0] << ", " <<
                ext[1] << ", " << ext[2] << ", " << ext[3] << ", " <<
                ext[4] << ", " << ext[5] << endl);
  cache->Update();
  data = cache;
  this->RecursiveWrite(axis,cache,data,file);
  if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError)
    {
    this->DeleteFiles();
    return;
    }
  if (file && fileOpenedHere)
    {
    this->WriteFileTrailer(file,cache);
    file->flush();
    if (file->fail())
      {
      this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
      }
    file->close();
    delete file;
    }
  return;
}

//----------------------------------------------------------------------------
// same idea as the previous method, but it knows that the data is ready
void vtkImageWriter::RecursiveWrite(int axis, vtkImageData *cache,
                                    vtkImageData *data, ofstream *file)
{
  int idx, min, max;

  // if the file is already open then just write to it
  if (file)
    {
    this->WriteFile(file,data,cache->GetUpdateExtent());
    file->flush();
    if (file->fail())
      {
      file->close();
      delete file;
      this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
      }
    return;
    }

  // if we need to open another slice, do it
  if (!file && (axis + 1) == this->FileDimensionality)
    {
    // determine the name
    if (this->FileName)
      {
      sprintf(this->InternalFileName,"%s",this->FileName);
      }
    else
      {
      if (this->FilePrefix)
        {
        sprintf(this->InternalFileName, this->FilePattern,
                this->FilePrefix, this->FileNumber);
        }
      else
        {
        sprintf(this->InternalFileName, this->FilePattern,this->FileNumber);
        }
      if (this->FileNumber < this->MinimumFileNumber)
        {
        this->MinimumFileNumber = this->FileNumber;
        }
      else if (this->FileNumber > this->MaximumFileNumber)
        {
        this->MaximumFileNumber = this->FileNumber;
        }
      }
    // Open the file
#ifdef _WIN32
    file = new ofstream(this->InternalFileName, ios::out | ios::binary);
#else
    file = new ofstream(this->InternalFileName, ios::out);
#endif
    if (file->fail())
      {
      vtkErrorMacro("RecursiveWrite: Could not open file " <<
                    this->InternalFileName);
      this->SetErrorCode(vtkErrorCode::CannotOpenFileError);
      delete file;
      return;
      }

    // Subclasses can write a header with this method call.
    this->WriteFileHeader(file, cache);
    file->flush();
    if (file->fail())
      {
      file->close();
      delete file;
      this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
      return;
      }
    this->WriteFile(file,data,cache->GetUpdateExtent());
    file->flush();
    if (file->fail())
      {
      file->close();
      delete file;
      this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
      return;
      }
    ++this->FileNumber;
    this->WriteFileTrailer(file,cache);
    file->flush();
    if (file->fail())
      {
      this->SetErrorCode(vtkErrorCode::OutOfDiskSpaceError);
      }
    file->close();
    delete file;
    return;
    }

  // if the current region is too high a dimension forthe file
  // the we will split the current axis
  cache->GetAxisUpdateExtent(axis, min, max);

  // if it is the y axis then flip by default
  if (axis == 1 && !this->FileLowerLeft)
    {
    for(idx = max; idx >= min; idx--)
      {
      cache->SetAxisUpdateExtent(axis, idx, idx);
      if (this->ErrorCode != vtkErrorCode::OutOfDiskSpaceError)
        {
        this->RecursiveWrite(axis - 1, cache, data, file);
        }
      else
        {
        this->DeleteFiles();
        }
      }
    }
  else
    {
    for(idx = min; idx <= max; idx++)
      {
      cache->SetAxisUpdateExtent(axis, idx, idx);
      if (this->ErrorCode != vtkErrorCode::OutOfDiskSpaceError)
        {
        this->RecursiveWrite(axis - 1, cache, data, file);
        }
      else
        {
        this->DeleteFiles();
        }
      }
    }

  // restore original extent
  cache->SetAxisUpdateExtent(axis, min, max);
}

//----------------------------------------------------------------------------
template <class T>
unsigned long vtkImageWriterGetSize(T*)
{
  return sizeof(T);
}

//----------------------------------------------------------------------------
// Writes a region in a file.  Subclasses can override this method
// to produce a header. This method only hanldes 3d data (plus components).
void vtkImageWriter::WriteFile(ofstream *file, vtkImageData *data,
                               int extent[6])
{
  int idxY, idxZ;
  int rowLength; // in bytes
  void *ptr;
  unsigned long count = 0;
  unsigned long target;
  float progress = this->Progress;
  float area;
  int *wExtent;

  // Make sure we actually have data.
  if ( !data->GetPointData()->GetScalars())
    {
    vtkErrorMacro(<< "Could not get data from input.");
    return;
    }

  // take into consideration the scalar type
  switch (data->GetScalarType())
    {
    vtkTemplateMacro(
      rowLength = vtkImageWriterGetSize(static_cast<VTK_TT*>(0))
      );
    default:
      vtkErrorMacro(<< "Execute: Unknown output ScalarType");
      return;
    }
  rowLength *= data->GetNumberOfScalarComponents();
  rowLength *= (extent[1] - extent[0] + 1);

  wExtent = this->GetInput()->GetWholeExtent();
  area = (float) ((extent[5] - extent[4] + 1)*
                  (extent[3] - extent[2] + 1)*
                  (extent[1] - extent[0] + 1)) /
         (float) ((wExtent[5] -wExtent[4] + 1)*
                  (wExtent[3] -wExtent[2] + 1)*
                  (wExtent[1] -wExtent[0] + 1));

  target = (unsigned long)((extent[5]-extent[4]+1)*
                           (extent[3]-extent[2]+1)/(50.0*area));
  target++;

  int ystart = extent[3];
  int yend = extent[2] - 1;
  int yinc = -1;
  if (this->FileLowerLeft)
    {
    ystart = extent[2];
    yend = extent[3]+1;
    yinc = 1;
    }

  for (idxZ = extent[4]; idxZ <= extent[5]; ++idxZ)
    {
    for (idxY = ystart; idxY != yend; idxY = idxY + yinc)
      {
      if (!(count%target))
        {
        this->UpdateProgress(progress + count/(50.0*target));
        }
      count++;
      ptr = data->GetScalarPointer(extent[0], idxY, idxZ);
      if ( ! file->write((char *)ptr, rowLength))
        {
        return;
        }
      }
    }
}

void vtkImageWriter::DeleteFiles()
{
  if (this->FilesDeleted)
    {
    return;
    }
  int i;
  char *fileName;

  vtkErrorMacro("Ran out of disk space; deleting file(s) already written");

  if (this->FileName)
    {
    vtksys::SystemTools::RemoveFile(this->FileName);
    }
  else
    {
    if (this->FilePrefix)
      {
      fileName =
        new char[strlen(this->FilePrefix) + strlen(this->FilePattern) + 10];

      for (i = this->MinimumFileNumber; i <= this->MaximumFileNumber; i++)
        {
        sprintf(fileName, this->FilePattern, this->FilePrefix, i);
        vtksys::SystemTools::RemoveFile(fileName);
        }
      delete [] fileName;
      }
    else
      {
      fileName = new char[strlen(this->FilePattern) + 10];

      for (i = this->MinimumFileNumber; i <= this->MaximumFileNumber; i++)
        {
        sprintf(fileName, this->FilePattern, i);
        vtksys::SystemTools::RemoveFile(fileName);
        }
      delete [] fileName;
      }
    }
  this->FilesDeleted = 1;
}
<|endoftext|>


<commit_before>
#include "ros/ros.h"
#include <iostream>
#include "std_msgs/String.h"
#include <sstream>
#include <thread>
#include "tortuga/imuapi.h"
#include "tortuga/sensorapi.h"

bool checkError(int, char*);

// This is the code used to open and publish all of the
// file descriptors for tortuga device boards

std::string imu_file = "/dev/magboom";
std::string sensor_file = "/dev/sensor";

int main(){

	//imu
	if(ros::param::has(imu_file)){
		ros::param::get("imu_device_file", imu_file);
	}else{
		ros::param::set("imu_device_file", imu_file);
	}

	int fd = openIMU(imu_file.c_str());
	checkError(fd, "IMU");

	ros::param::set("imu_file_descriptor", fd);

	//sensor board
	if(ros::param::has(sensor_file)){
		ros::param::get("sensor_board_file", sensor_file);
	}else{
		ros::param::set("sensor_board_file", sensor_file);
	}

	fd = openSensorBoard(sensor_file.c_str());
	checkError(fd, "Sensor Board");

	ros::param::set("sensor_board_file_descriptor", fd);

}

bool checkError(int e, char *name) {
    switch(e) {
    case SB_IOERROR:
      ROS_DEBUG("IO ERROR in %s", name);
      return true;
    case SB_BADCC:
      ROS_DEBUG("BAD CC ERROR in %s", name);
      return true;
    case SB_HWFAIL:
      ROS_DEBUG("HW FAILURE ERROR in %s", name);
      return true;
    case SB_ERROR:
      ROS_DEBUG("ERROR in %s", name);
      return true;
    default:
      return false;
    }
}<commit_msg>board opener works now<commit_after>
#include "ros/ros.h"
#include <iostream>
#include "std_msgs/String.h"
#include <sstream>
#include <thread>
#include "tortuga/imuapi.h"
#include "tortuga/sensorapi.h"

bool checkError(int, char*);

// This is the code used to open and publish all of the
// file descriptors for tortuga device boards

std::string imu_file = "/dev/magboom";
std::string sensor_file = "/dev/sensor";

int main(int argc, char **argv){

	ros::init(argc, argv, "board_opener");

	//imu
	if(ros::param::has(imu_file)){
		ros::param::get("imu_device_file", imu_file);
	}else{
		ros::param::set("imu_device_file", imu_file);
	}

	int fd = openIMU(imu_file.c_str());
	checkError(fd, "IMU");

	ros::param::set("imu_file_descriptor", fd);

	//sensor board
	if(ros::param::has(sensor_file)){
		ros::param::get("sensor_board_file", sensor_file);
	}else{
		ros::param::set("sensor_board_file", sensor_file);
	}

	fd = openSensorBoard(sensor_file.c_str());
	checkError(fd, "Sensor Board");

	ros::param::set("sensor_board_file_descriptor", fd);

}

bool checkError(int e, char *name) {
    switch(e) {
    case SB_IOERROR:
      ROS_DEBUG("IO ERROR in %s", name);
      return true;
    case SB_BADCC:
      ROS_DEBUG("BAD CC ERROR in %s", name);
      return true;
    case SB_HWFAIL:
      ROS_DEBUG("HW FAILURE ERROR in %s", name);
      return true;
    case SB_ERROR:
      ROS_DEBUG("ERROR in %s", name);
      return true;
    default:
      return false;
    }
}<|endoftext|>