<commit_before>/*
**  Copyright (C) 2012, 2013 Aldebaran Robotics
**  See COPYING for the license
*/
#include <iostream>

#include <qitype/genericobject.hpp>
#include "staticobjecttype.hpp"
#include "object_p.hpp"

qiLogCategory("qitype.object");

namespace qi {

  GenericObject::GenericObject(ObjectType *type, void *value)
  : type(type)
  , value(value)
  {
  }

  GenericObject::~GenericObject() {
  }

  ManageablePrivate::ManageablePrivate()
  : objectMutex(new boost::timed_mutex)
  , statsEnabled(false)
  , traceEnabled(false)
  {
  }

  Manageable::Manageable()
  : traceObject(boost::bind(&Manageable::enableTrace, this, _1))
  {
    _p = new ManageablePrivate();
    _p->eventLoop = 0;
    _p->dying = false;
  }

  Manageable::Manageable(const Manageable& b)
  : traceObject(boost::bind(&Manageable::enableTrace, this, _1))
  {
    _p = new ManageablePrivate();
    _p->eventLoop = b._p->eventLoop;
    _p->dying = false;
  }

  void Manageable::operator = (const Manageable& b)
  {
    this->~Manageable();
    _p = new ManageablePrivate();
    _p->eventLoop = b._p->eventLoop;
    _p->dying = false;
  }

  Manageable::~Manageable()
  {
    _p->dying = true;
    std::vector<SignalSubscriber> copy;
    {
      boost::mutex::scoped_lock sl(_p->registrationsMutex);
      copy = _p->registrations;
    }
    for (unsigned i = 0; i < copy.size(); ++i)
    {
      copy[i].source->disconnect(copy[i].linkId);
    }
    delete _p;
  }

  void Manageable::forceEventLoop(EventLoop* el)
  {
    _p->eventLoop = el;
  }

  EventLoop* Manageable::eventLoop() const
  {
    return _p->eventLoop;
  }

  Manageable::TimedMutexPtr Manageable::mutex()
  {
    return _p->objectMutex;
  }

  bool Manageable::isStatsEnabled() const
  {
    return _p->statsEnabled;
  }

  void Manageable::enableStats(bool state)
  {
    _p->statsEnabled = state;
  }

  void Manageable::pushStats(int slotId, float value)
  {
    boost::mutex::scoped_lock(_p->registrationsMutex);
    MethodStatistics& ms = _p->stats[slotId];
    ms.cumulatedTime += value;
    if (!ms.count)
    {
      ms.minTime = value;
      ms.maxTime = value;
    }
    else
    {
      ms.minTime = std::min(ms.minTime, value);
      ms.maxTime = std::max(ms.maxTime, value);
    }
    ++ms.count;
  }

  ObjectStatistics Manageable::stats() const
  {
    boost::mutex::scoped_lock(_p->registrationsMutex);
    return _p->stats;
  }

  void Manageable::clearStats()
  {
    boost::mutex::scoped_lock(_p->registrationsMutex);
    _p->stats.clear();
  }

  bool Manageable::isTraceEnabled() const
  {
    return _p->traceEnabled;
  }

  void Manageable::enableTrace(bool state)
  {
    _p->traceEnabled = state;
  }

  int Manageable::_nextTraceId()
  {
    return ++_p->traceId;
  }

  const MetaObject &GenericObject::metaObject() {
    if (!type || !value) {
      static qi::MetaObject fail;
      qiLogWarning() << "Operating on invalid GenericObject..";
      return fail;
    }
    return type->metaObject(value);
  }

  qi::Future<GenericValuePtr>
  GenericObject::metaCall(unsigned int method, const GenericFunctionParameters& params, MetaCallType callType)
  {
    qi::Promise<GenericValuePtr> out;
    if (!type || !value) {
      qiLogWarning() << "Operating on invalid GenericObject..";
      out.setError("Invalid object");
      return out.future();
    }
    try {
      return type->metaCall(value, this, method, params, callType);
    } catch (const std::exception &e) {
      out.setError(e.what());
      return out.future();
    }
    catch (...)
    {
      out.setError("Unknown exception caught");
      return out.future();
    }
  }

  void GenericObject::metaPost(unsigned int event, const GenericFunctionParameters& args)
  {
    if (!type || !value) {
      qiLogWarning() << "Operating on invalid GenericObject..";
      return;
    }
    type->metaPost(value, this, event, args);
  }

  static std::string generateErrorString(const std::string &signature,
                                         const std::vector<MetaObject::CompatibleMethod> &candidates,
                                         bool logError = true)
  {
    std::stringstream                           ss;
    std::vector<MetaObject::CompatibleMethod>::const_iterator it;

    if (candidates.size() == 0) {
      ss << "Can't find method: " << signature << std::endl;
      return ss.str();
    }

    ss << "Ambiguous overload for " << signature << ":" << std::endl
       << "  Candidate(s):" << std::endl;
    for (it = candidates.begin(); it != candidates.end(); ++it) {
      const qi::MetaMethod       &mm = it->first;
      ss << "  " << mm.toString() << " (" << it->second << ')' << std::endl;
    }
    if (logError)
      qiLogError() << ss.str();
    return ss.str();
  }

  struct less_pair_second
  {
    template<typename T> bool operator()(const T& a, const T& b) const
    {
      return a.second < b.second;
    }
  };

  unsigned int GenericObject::findMethod(const std::string& nameWithOptionalSignature, const GenericFunctionParameters& args)
  {
    typedef std::vector<MetaObject::CompatibleMethod> Methods;
    const MetaObject& mo = metaObject();
    if (nameWithOptionalSignature.find(':') != nameWithOptionalSignature.npos)
      return mo.methodId(nameWithOptionalSignature);
    for (unsigned dyn = 0; dyn<2; ++dyn)
    {
      std::string resolvedSig = args.signature(dyn==1).toString();
      std::string fullSig = nameWithOptionalSignature + "::" + resolvedSig;
      qiLogDebug() << "Finding method for resolved signature " << fullSig;
      // First try an exact match, wich is much faster if we're lucky.
      int methodId = mo.methodId(fullSig);
      if (methodId >= 0)
        return methodId;
      Methods mml = mo.findCompatibleMethod(fullSig);
      if (mml.empty())
        continue;
      if (mml.size() == 1)
        return mml.front().first.uid();
      // get best match
      Methods::iterator it = std::max_element(mml.begin(), mml.end(), less_pair_second());
      int count = 0;
      for (unsigned i=0; i<mml.size(); ++i)
      {
        if (mml[i].second == it->second)
          ++count;
      }
      assert(count);
      if (count > 1)
        qiLogVerbose() << generateErrorString(nameWithOptionalSignature, mml, false);
      else
        return it->first.uid();
    }
    return -1;
  }

  qi::Future<GenericValuePtr>
  GenericObject::metaCall(const std::string &nameWithOptionalSignature, const GenericFunctionParameters& args, MetaCallType callType)
  {
    qi::Promise<GenericValuePtr> out;
    if (!type || !value) {
      qiLogWarning() << "Operating on invalid GenericObject..";
      out.setError("Invalid object");
      return out.future();
    }
    int methodId = findMethod(nameWithOptionalSignature, args);
    if (methodId < 0) {
      return makeFutureError<GenericValuePtr>(generateErrorString(nameWithOptionalSignature, metaObject().findCompatibleMethod(nameWithOptionalSignature), false));
    }
    return metaCall(methodId, args, callType);
  }<commit_msg>Object: better error message when method not found<commit_after>/*
**  Copyright (C) 2012, 2013 Aldebaran Robotics
**  See COPYING for the license
*/
#include <iostream>

#include <qitype/genericobject.hpp>
#include "staticobjecttype.hpp"
#include "object_p.hpp"

qiLogCategory("qitype.object");

namespace qi {

  GenericObject::GenericObject(ObjectType *type, void *value)
  : type(type)
  , value(value)
  {
  }

  GenericObject::~GenericObject() {
  }

  ManageablePrivate::ManageablePrivate()
  : objectMutex(new boost::timed_mutex)
  , statsEnabled(false)
  , traceEnabled(false)
  {
  }

  Manageable::Manageable()
  : traceObject(boost::bind(&Manageable::enableTrace, this, _1))
  {
    _p = new ManageablePrivate();
    _p->eventLoop = 0;
    _p->dying = false;
  }

  Manageable::Manageable(const Manageable& b)
  : traceObject(boost::bind(&Manageable::enableTrace, this, _1))
  {
    _p = new ManageablePrivate();
    _p->eventLoop = b._p->eventLoop;
    _p->dying = false;
  }

  void Manageable::operator = (const Manageable& b)
  {
    this->~Manageable();
    _p = new ManageablePrivate();
    _p->eventLoop = b._p->eventLoop;
    _p->dying = false;
  }

  Manageable::~Manageable()
  {
    _p->dying = true;
    std::vector<SignalSubscriber> copy;
    {
      boost::mutex::scoped_lock sl(_p->registrationsMutex);
      copy = _p->registrations;
    }
    for (unsigned i = 0; i < copy.size(); ++i)
    {
      copy[i].source->disconnect(copy[i].linkId);
    }
    delete _p;
  }

  void Manageable::forceEventLoop(EventLoop* el)
  {
    _p->eventLoop = el;
  }

  EventLoop* Manageable::eventLoop() const
  {
    return _p->eventLoop;
  }

  Manageable::TimedMutexPtr Manageable::mutex()
  {
    return _p->objectMutex;
  }

  bool Manageable::isStatsEnabled() const
  {
    return _p->statsEnabled;
  }

  void Manageable::enableStats(bool state)
  {
    _p->statsEnabled = state;
  }

  void Manageable::pushStats(int slotId, float value)
  {
    boost::mutex::scoped_lock(_p->registrationsMutex);
    MethodStatistics& ms = _p->stats[slotId];
    ms.cumulatedTime += value;
    if (!ms.count)
    {
      ms.minTime = value;
      ms.maxTime = value;
    }
    else
    {
      ms.minTime = std::min(ms.minTime, value);
      ms.maxTime = std::max(ms.maxTime, value);
    }
    ++ms.count;
  }

  ObjectStatistics Manageable::stats() const
  {
    boost::mutex::scoped_lock(_p->registrationsMutex);
    return _p->stats;
  }

  void Manageable::clearStats()
  {
    boost::mutex::scoped_lock(_p->registrationsMutex);
    _p->stats.clear();
  }

  bool Manageable::isTraceEnabled() const
  {
    return _p->traceEnabled;
  }

  void Manageable::enableTrace(bool state)
  {
    _p->traceEnabled = state;
  }

  int Manageable::_nextTraceId()
  {
    return ++_p->traceId;
  }

  const MetaObject &GenericObject::metaObject() {
    if (!type || !value) {
      static qi::MetaObject fail;
      qiLogWarning() << "Operating on invalid GenericObject..";
      return fail;
    }
    return type->metaObject(value);
  }

  qi::Future<GenericValuePtr>
  GenericObject::metaCall(unsigned int method, const GenericFunctionParameters& params, MetaCallType callType)
  {
    qi::Promise<GenericValuePtr> out;
    if (!type || !value) {
      qiLogWarning() << "Operating on invalid GenericObject..";
      out.setError("Invalid object");
      return out.future();
    }
    try {
      return type->metaCall(value, this, method, params, callType);
    } catch (const std::exception &e) {
      out.setError(e.what());
      return out.future();
    }
    catch (...)
    {
      out.setError("Unknown exception caught");
      return out.future();
    }
  }

  void GenericObject::metaPost(unsigned int event, const GenericFunctionParameters& args)
  {
    if (!type || !value) {
      qiLogWarning() << "Operating on invalid GenericObject..";
      return;
    }
    type->metaPost(value, this, event, args);
  }

  static std::string generateErrorString(const std::string &signature,
                                         const std::vector<MetaObject::CompatibleMethod> &candidates,
                                         bool logError = true)
  {
    std::stringstream                           ss;
    std::vector<MetaObject::CompatibleMethod>::const_iterator it;

    if (candidates.size() == 0) {
      ss << "Can't find method: " << signature << std::endl;
      return ss.str();
    }

    if (candidates.size() == 1) {
      ss << "Arguments types did not match for " << signature << ":" << std::endl
         << "  Candidate:" << std::endl;
    } else {
      ss << "Ambiguous overload for " << signature << ":" << std::endl
         << "  Candidate(s):" << std::endl;
    }
    for (it = candidates.begin(); it != candidates.end(); ++it) {
      const qi::MetaMethod       &mm = it->first;
      ss << "  " << mm.toString() << " (" << it->second << ')' << std::endl;
    }
    if (logError)
      qiLogError() << ss.str();
    return ss.str();
  }

  struct less_pair_second
  {
    template<typename T> bool operator()(const T& a, const T& b) const
    {
      return a.second < b.second;
    }
  };

  unsigned int GenericObject::findMethod(const std::string& nameWithOptionalSignature, const GenericFunctionParameters& args)
  {
    typedef std::vector<MetaObject::CompatibleMethod> Methods;
    const MetaObject& mo = metaObject();
    if (nameWithOptionalSignature.find(':') != nameWithOptionalSignature.npos)
      return mo.methodId(nameWithOptionalSignature);
    for (unsigned dyn = 0; dyn<2; ++dyn)
    {
      std::string resolvedSig = args.signature(dyn==1).toString();
      std::string fullSig = nameWithOptionalSignature + "::" + resolvedSig;
      qiLogDebug() << "Finding method for resolved signature " << fullSig;
      // First try an exact match, wich is much faster if we're lucky.
      int methodId = mo.methodId(fullSig);
      if (methodId >= 0)
        return methodId;
      Methods mml = mo.findCompatibleMethod(fullSig);
      if (mml.empty())
        continue;
      if (mml.size() == 1)
        return mml.front().first.uid();
      // get best match
      Methods::iterator it = std::max_element(mml.begin(), mml.end(), less_pair_second());
      int count = 0;
      for (unsigned i=0; i<mml.size(); ++i)
      {
        if (mml[i].second == it->second)
          ++count;
      }
      assert(count);
      if (count > 1)
        qiLogVerbose() << generateErrorString(fullSig, mml, false);
      else
        return it->first.uid();
    }
    return -1;
  }

  qi::Future<GenericValuePtr>
  GenericObject::metaCall(const std::string &nameWithOptionalSignature, const GenericFunctionParameters& args, MetaCallType callType)
  {
    qi::Promise<GenericValuePtr> out;
    if (!type || !value) {
      qiLogWarning() << "Operating on invalid GenericObject..";
      out.setError("Invalid object");
      return out.future();
    }
    int methodId = findMethod(nameWithOptionalSignature, args);
    if (methodId < 0) {
      std::string resolvedSig = args.signature(true).toString();
      std::string fullSig = nameWithOptionalSignature + "::" + resolvedSig;
      return makeFutureError<GenericValuePtr>(generateErrorString(fullSig, metaObject().findCompatibleMethod(nameWithOptionalSignature), false));
    }
    return metaCall(methodId, args, callType);
  }
{'fraction_non_alphanumeric': 0.14380500069842156, 'fraction_numerical': 0.0032825813661125857, 'mean_word_length': 3.001956400223589, 'pattern_counts': {'":': 6, '<': 141, '<?xml version=': 0, '>': 99, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5781678', 'n_tokens_mistral': 4673, 'n_tokens_neox': 4558, 'n_words': 941}