<commit_before>/*
**
** Author(s):
**  - <NAME> <<EMAIL>>
**
** Copyright (C) 2013 Aldebaran Robotics
*/
#include "pysignal.hpp"
#include <boost/python.hpp>
#include <boost/python/raw_function.hpp>
#include <qitype/signal.hpp>
#include <qitype/anyobject.hpp>
#include "gil.hpp"
#include "error.hpp"
#include "pyfuture.hpp"
#include "pythreadsafeobject.hpp"

qiLogCategory("py.signal");

namespace qi { namespace py {

    static qi::AnyReference pysignalCb(const std::vector<qi::AnyReference>& cargs, const PyThreadSafeObject& callable) {
      GILScopedLock _lock;
      boost::python::list   args;
      boost::python::object ret;

      std::vector<qi::AnyReference>::const_iterator it;
      for (it = cargs.begin(); it != cargs.end(); ++it) {
        args.append(it->to<boost::python::object>());
      }
      PY_CATCH_ERROR(ret = callable.object()(*boost::python::tuple(args)));
      return qi::AnyReference(ret).clone();
    }

    class PySignal {
    public:
      PySignal(const qi::Signature &signature = "m")
        : _sig(new qi::SignalBase(signature))
      {
      }

      PySignal(const PySignal& rhs)
        : _sig(new qi::SignalBase(qi::Signature("m")))
      {

        *_sig = *rhs._sig;
      }

      PySignal &operator=(const PySignal& rhs) {
        *_sig = *rhs._sig;
        return *this;
      }

      ~PySignal() {
        //the dtor can lock waiting for callback ends
        GILScopedUnlock _unlock;
        delete _sig;
      }

      boost::python::object connect(boost::python::object callable, bool _async = false) {
        PyThreadSafeObject obj(callable);
        qi::uint64_t r;
        {
          GILScopedUnlock _unlock;
          //no need to store a ptr on ourself. (this exist if the callback is triggered)
          r = _sig->connect(qi::AnyFunction::fromDynamicFunction(boost::bind(pysignalCb, _1, obj)));
        }
        if (_async)
        {
          return boost::python::object(toPyFuture(qi::Future<qi::uint64_t>(r)));
        }

        return boost::python::object(r);
      }

      boost::python::object disconnect(qi::uint64_t id, bool _async = false) {
        GILScopedUnlock _unlock;
        bool r = _sig->disconnect(id);
        GILScopedLock _lock;
        if (_async)
        {
          return boost::python::object(toPyFuture(qi::Future<bool>(r)));
        }

        return boost::python::object(r);
      }

      boost::python::object disconnectAll(bool _async = false) {
        GILScopedUnlock _unlock;
        bool r = _sig->disconnectAll();
        GILScopedLock _lock;
        if (_async)
        {
          return boost::python::object(toPyFuture(qi::Future<bool>(r)));
        }
        return boost::python::object(r);
      }

      //this function is named trigger in the qi.Signal object,
      //the python wrapper add a __call__ method bound to this one. (see qi/__init__.py)
      void trig(boost::python::tuple args, boost::python::dict kwargs) {
        GILScopedUnlock _unlock;
        _sig->trigger(qi::AnyReference(args).asDynamic().asTupleValuePtr());
      }

    public:
      qi::SignalBase *_sig;
    };

    class PyProxySignal {
    public:
      PyProxySignal(qi::AnyObject obj, const qi::MetaSignal &signal)
        : _obj(obj)
        , _sigid(signal.uid()){
      }

      boost::python::object connect(boost::python::object callable, bool _async = false) {
        PyThreadSafeObject obj(callable);
        qi::Future<SignalLink> f;
        {
          GILScopedUnlock _unlock;
          //no need to store a ptr on ourself. (this exist if the callback is triggered)
          f = _obj->connect(_sigid, qi::AnyFunction::fromDynamicFunction(boost::bind(pysignalCb, _1, obj)));
        }
        return toPyFutureAsync(f, _async);
      }

      boost::python::object disconnect(qi::uint64_t id, bool _async = false) {
        GILScopedUnlock _unlock;
        qi::FutureSync<void> f = _obj->disconnect(id);
        GILScopedLock _lock;
        if (_async)
        {
          return boost::python::object(toPyFuture(f));
        }

        return boost::python::object(f.value());
      }

      //this function is named trigger in the qi.Signal object,
      //the python wrapper add a __call__ method bound to this one. (see qi/__init__.py)
      void trig(boost::python::tuple args, boost::python::dict kwargs) {
        GILScopedUnlock _unlock;
        _obj->metaPost(_sigid, qi::AnyReference(args).asDynamic().asTupleValuePtr());
      }

    private:
      qi::AnyObject _obj;
      unsigned int  _sigid;
    };

    qi::SignalBase *getSignal(boost::python::object obj) {
      PySignal* sig = boost::python::extract<PySignal*>(obj);
      if (!sig)
        return 0;
      return sig->_sig;
    }

    boost::python::object makePySignal(const std::string &signature) {
      GILScopedLock _lock;<commit_msg>python: signal: remove unneeded scopedlock<commit_after>/*
**
** Author(s):
**  - <NAME> <<EMAIL>>
**
** Copyright (C) 2013 Aldebaran Robotics
*/
#include "pysignal.hpp"
#include <boost/python.hpp>
#include <boost/python/raw_function.hpp>
#include <qitype/signal.hpp>
#include <qitype/anyobject.hpp>
#include "gil.hpp"
#include "error.hpp"
#include "pyfuture.hpp"
#include "pythreadsafeobject.hpp"

qiLogCategory("py.signal");

namespace qi { namespace py {

    static qi::AnyReference pysignalCb(const std::vector<qi::AnyReference>& cargs, const PyThreadSafeObject& callable) {
      GILScopedLock _lock;
      boost::python::list   args;
      boost::python::object ret;

      std::vector<qi::AnyReference>::const_iterator it;
      for (it = cargs.begin(); it != cargs.end(); ++it) {
        args.append(it->to<boost::python::object>());
      }
      PY_CATCH_ERROR(ret = callable.object()(*boost::python::tuple(args)));
      return qi::AnyReference(ret).clone();
    }

    class PySignal {
    public:
      PySignal(const qi::Signature &signature = "m")
        : _sig(new qi::SignalBase(signature))
      {
      }

      PySignal(const PySignal& rhs)
        : _sig(new qi::SignalBase(qi::Signature("m")))
      {

        *_sig = *rhs._sig;
      }

      PySignal &operator=(const PySignal& rhs) {
        *_sig = *rhs._sig;
        return *this;
      }

      ~PySignal() {
        //the dtor can lock waiting for callback ends
        GILScopedUnlock _unlock;
        delete _sig;
      }

      boost::python::object connect(boost::python::object callable, bool _async = false) {
        PyThreadSafeObject obj(callable);
        qi::uint64_t r;
        {
          GILScopedUnlock _unlock;
          //no need to store a ptr on ourself. (this exist if the callback is triggered)
          r = _sig->connect(qi::AnyFunction::fromDynamicFunction(boost::bind(pysignalCb, _1, obj)));
        }
        if (_async)
        {
          return boost::python::object(toPyFuture(qi::Future<qi::uint64_t>(r)));
        }
        return boost::python::object(r);
      }

      boost::python::object disconnect(qi::uint64_t id, bool _async = false) {
        bool r;
        {
          GILScopedUnlock _unlock;
          r = _sig->disconnect(id);
        }
        if (_async)
        {
          return boost::python::object(toPyFuture(qi::Future<bool>(r)));
        }

        return boost::python::object(r);
      }

      boost::python::object disconnectAll(bool _async = false) {
        bool r;
        {
          GILScopedUnlock _unlock;
          r = _sig->disconnectAll();
        }
        if (_async)
        {
          return boost::python::object(toPyFuture(qi::Future<bool>(r)));
        }
        return boost::python::object(r);
      }

      //this function is named trigger in the qi.Signal object,
      //the python wrapper add a __call__ method bound to this one. (see qi/__init__.py)
      void trig(boost::python::tuple args, boost::python::dict kwargs) {
        GILScopedUnlock _unlock;
        _sig->trigger(qi::AnyReference(args).asDynamic().asTupleValuePtr());
      }

    public:
      qi::SignalBase *_sig;
    };

    class PyProxySignal {
    public:
      PyProxySignal(qi::AnyObject obj, const qi::MetaSignal &signal)
        : _obj(obj)
        , _sigid(signal.uid()){
      }

      boost::python::object connect(boost::python::object callable, bool _async = false) {
        PyThreadSafeObject obj(callable);
        qi::Future<SignalLink> f;
        {
          GILScopedUnlock _unlock;
          //no need to store a ptr on ourself. (this exist if the callback is triggered)
          f = _obj->connect(_sigid, qi::AnyFunction::fromDynamicFunction(boost::bind(pysignalCb, _1, obj)));
        }
        return toPyFutureAsync(f, _async);
      }

      boost::python::object disconnect(qi::uint64_t id, bool _async = false) {
        qi::Future<void> f;
        {
          GILScopedUnlock _unlock;
          f = _obj->disconnect(id);
        }
        return toPyFutureAsync(f, _async);
      }

      //this function is named trigger in the qi.Signal object,
      //the python wrapper add a __call__ method bound to this one. (see qi/__init__.py)
      void trig(boost::python::tuple args, boost::python::dict kwargs) {
        GILScopedUnlock _unlock;
        _obj->metaPost(_sigid, qi::AnyReference(args).asDynamic().asTupleValuePtr());
      }

    private:
      qi::AnyObject _obj;
      unsigned int  _sigid;
    };

    qi::SignalBase *getSignal(boost::python::object obj) {
      PySignal* sig = boost::python::extract<PySignal*>(obj);
      if (!sig)
        return 0;
      return sig->_sig;
    }

    boost::python::object makePySignal(const std::string &signature) {
      GILScopedLock _lock;
{'fraction_non_alphanumeric': 0.13514923815487373, 'fraction_numerical': 0.0031308703819661866, 'mean_word_length': 2.621693121693122, 'pattern_counts': {'":': 0, '<': 35, '<?xml version=': 0, '>': 53, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6165445', 'n_tokens_mistral': 3075, 'n_tokens_neox': 2966, 'n_words': 639}