<commit_before>/*
**  Copyright (C) 2012 Aldebaran Robotics
**  See COPYING for the license
*/
#include <map>
#include <qi/atomic.hpp>

#include <boost/thread/recursive_mutex.hpp>
#include <boost/make_shared.hpp>

#include <qitype/signal.hpp>
#include <qitype/anyvalue.hpp>
#include <qitype/anyobject.hpp>

#include "anyobject_p.hpp"
#include "signal_p.hpp"

qiLogCategory("qitype.signal");

namespace qi {

  SignalSubscriber::SignalSubscriber(qi::AnyObject target, unsigned int method)
  : threadingModel(MetaCallType_Direct),  target(new qi::ObjectWeakPtr(target)), method(method), enabled(true)
  { // The slot has its own threading model: be synchronous
  }

  SignalSubscriber::SignalSubscriber(AnyFunction func, MetaCallType model)
     : handler(func), threadingModel(model), target(0), method(0), enabled(true)
   {
   }

  SignalSubscriber::~SignalSubscriber()
  {
    delete target;
  }

  SignalSubscriber::SignalSubscriber(const SignalSubscriber& b)
  : target(0)
  {
    *this = b;
  }

  void SignalSubscriber::operator=(const SignalSubscriber& b)
  {
    source = b.source;
    linkId = b.linkId;
    handler = b.handler;
    threadingModel = b.threadingModel;
    target = b.target?new ObjectWeakPtr(*b.target):0;
    method = b.method;
    enabled = b.enabled;
  }

  static qi::Atomic<int> linkUid = 1;

  void SignalBase::setCallType(MetaCallType callType)
  {
    if (!_p)
    {
      _p = boost::make_shared<SignalBasePrivate>();
    }
    _p->defaultCallType = callType;
  }

  void SignalBase::operator()(
      qi::AutoAnyReference p1,
      qi::AutoAnyReference p2,
      qi::AutoAnyReference p3,
      qi::AutoAnyReference p4,
      qi::AutoAnyReference p5,
      qi::AutoAnyReference p6,
      qi::AutoAnyReference p7,
      qi::AutoAnyReference p8)
  {
    qi::AutoAnyReference* vals[8]= {&p1, &p2, &p3, &p4, &p5, &p6, &p7, &p8};
    std::vector<qi::AnyReference> params;
    for (unsigned i = 0; i < 8; ++i)
      if (vals[i]->value)
        params.push_back(*vals[i]);
    qi::Signature signature = qi::makeTupleSignature(params);

    if (signature != _p->signature)
    {
      qiLogError() << "Dropping emit: signature mismatch: " << signature.toString() <<" " << _p->signature.toString();
      return;
    }
    trigger(params, _p->defaultCallType);
  }

  void SignalBase::trigger(const GenericFunctionParameters& params, MetaCallType callType)
  {
    if (!_p)
      return;
    if (_p->triggerOverride)
      _p->triggerOverride(params, callType);
    else
      callSubscribers(params, callType);
  }

  void SignalBase::setTriggerOverride(Trigger t)
  {
    if (!_p)
      _p = boost::make_shared<SignalBasePrivate>();
    _p->triggerOverride = t;
  }

  void SignalBase::setOnSubscribers(OnSubscribers onSubscribers)
  {
    if (!_p)
      _p = boost::make_shared<SignalBasePrivate>();
    _p->onSubscribers = onSubscribers;
  }

  void SignalBase::callSubscribers(const GenericFunctionParameters& params, MetaCallType callType)
  {
    MetaCallType mct = callType;

    if (!_p)
      return;

    if (mct == qi::MetaCallType_Auto)
      mct = _p->defaultCallType;
    SignalSubscriberMap copy;
    {
      boost::recursive_mutex::scoped_lock sl(_p->mutex);
      copy = _p->subscriberMap;
    }
    qiLogDebug() << (void*)this << " Invoking signal subscribers: " << copy.size();
    SignalSubscriberMap::iterator i;
    for (i = copy.begin(); i != copy.end(); ++i)
    {
      qiLogDebug() << (void*)this << " Invoking signal subscriber";
      SignalSubscriberPtr s = i->second; // hold s alive
      s->call(params, mct);
    }
    qiLogDebug() << (void*)this << " done invoking signal subscribers";
  }

  class FunctorCall
  {
  public:
    FunctorCall(GenericFunctionParameters* params, SignalSubscriberPtr* sub)
    : params(params)
    , sub(sub)
    {
    }

    FunctorCall(const FunctorCall& b)
    {
      *this = b;
    }

    void operator=(const FunctorCall& b)
    {
      params = b.params;
      sub = b.sub;
    }

    void operator() ()
    {
      try
      {
        {
          SignalSubscriberPtr s;
          boost::mutex::scoped_lock sl((*sub)->mutex);
          // verify-enabled-then-register-active op must be locked
          if (!(*sub)->enabled)
          {
            s = *sub; // delay destruction until after we leave the scoped_lock
            delete sub;
            params->destroy();
            delete params;
            return;
          }
          (*sub)->addActive(false);
        } // end mutex-protected scope
        (*sub)->handler(*params);
      }
      catch(const std::exception& e)
      {
        qiLogWarning() << "Exception caught from signal subscriber: " << e.what();
      }
      catch (...) {
        qiLogWarning() << "Unknown exception caught from signal subscriber";
      }

      (*sub)->removeActive(true);
      params->destroy();
      delete params;
      delete sub;
    }

  public:
    GenericFunctionParameters* params;
    SignalSubscriberPtr*         sub;
  };

  void SignalSubscriber::call(const GenericFunctionParameters& args, MetaCallType callType)
  {
    // this is held alive by caller
    if (handler)
    {
      bool async = true;
      if (threadingModel != MetaCallType_Auto)
        async = (threadingModel == MetaCallType_Queued);
      else if (callType != MetaCallType_Auto)
        async = (callType == MetaCallType_Queued);

      qiLogDebug() << "subscriber call async=" << async <<" ct " << callType <<" tm " << threadingModel;
      if (async)
      {
        GenericFunctionParameters* copy = new GenericFunctionParameters(args.copy());
        // We will check enabled when we will be scheduled in the target
        // thread, and we hold this SignalSubscriber alive, so no need to
        // explicitly track the asynccall

        // courtesy-check of el, but it should be kept alive longuer than us
        qi::EventLoop* el = getDefaultThreadPoolEventLoop();
        if (!el) // this is an assert basicaly, no sense trying to do something clever.
          throw std::runtime_error("Event loop was destroyed");
        el->post(FunctorCall(copy, new SignalSubscriberPtr(shared_from_this())));
      }
      else
      {
        // verify-enabled-then-register-active op must be locked
        {
          boost::mutex::scoped_lock sl(mutex);
          if (!enabled)
            return;
          addActive(false);
        }
        //do not throw
        bool mustDisconnect = false;
        try
        {
          handler(args);
        }
        catch(const qi::PointerLockException&)
        {
          qiLogDebug() << "PointerLockFailure excepton, will disconnect";
          mustDisconnect = true;
        }
        catch(const std::exception& e)
        {
          qiLogWarning() << "Exception caught from signal subscriber: " << e.what();
        }
        catch (...)
        {
          qiLogWarning() << "Unknown exception caught from signal subscriber";
        }
        removeActive(true);
        if (mustDisconnect)
          source->disconnect(linkId);
      }
    }
    else if (target)
    {
      AnyObject lockedTarget = target->lock();
      if (!lockedTarget)
      {
        source->disconnect(linkId);
      }
      else // no need to keep anything locked, whatever happens this is not used
        lockedTarget->metaPost(method, args);
    }
  }

  //check if we are called from the same thread that triggered us.
  //in that case, do not wait.
  void SignalSubscriber::waitForInactive()
  {
    boost::thread::id tid = boost::this_thread::get_id();
    while (true)
    {
      {
        boost::mutex::scoped_lock sl(mutex);
        if (activeThreads.empty())
          return;
        // There cannot be two activeThreads entry for the same tid
        // because activeThreads is not set at the post() stage
        if (activeThreads.size() == 1
          && *activeThreads.begin() == tid)
        { // One active callback in this thread, means above us in call stack
          // So we cannot wait for it
          return;
        }
      }
      os::msleep(1); // FIXME too long use a condition
    }
  }

  void SignalSubscriber::addActive(bool acquireLock, boost::thread::id id)
  {
    if (acquireLock)
    {
      boost::mutex::scoped_lock sl(mutex);
      activeThreads.push_back(id);
    }
    else
      activeThreads.push_back(id);
  }

  void SignalSubscriber::removeActive(bool acquireLock, boost::thread::id id)
  {

    boost::mutex::scoped_lock sl(mutex, boost::defer_lock_t());
    if (acquireLock)
      sl.lock();

    for (unsigned i=0; i<activeThreads.size(); ++i)
    {
      if (activeThreads[i] == id)
      { // fast remove by swapping with last and then pop_back
        activeThreads[i] = activeThreads[activeThreads.size() - 1];
        activeThreads.pop_back();
      }
    }
  }

  SignalSubscriber& SignalBase::connect(qi::AnyObject o, unsigned int slot)
  {
    return connect(SignalSubscriber(o, slot));
  }

  SignalSubscriber& SignalBase::connect(const SignalSubscriber& src)
  {
    qiLogDebug() << (void*)this << " connecting new subscriber";
    static SignalSubscriber invalid;
    if (!_p)
    {
      _p = boost::make_shared<SignalBasePrivate>();
    }
    // Check arity. Does not require to acquire weakLock.
    int sigArity = Signature(signature()).begin().children().size();
    int subArity = -1;
    Signature subSignature;

    if (signature() == "m")
      goto proceed; // no check possible

    if (src.handler)
    {
      if (src.handler.functionType() == dynamicFunctionTypeInterface())
        goto proceed; // no arity checking is possible
      subArity = src.handler.argumentsType().size();
      subSignature = src.handler.parametersSignature();
    }
    else if (src.target)
    {
      AnyObject locked = src.target->lock();
      if (!locked)
      {
        qiLogVerbose() << "connecting a dead slot (weak ptr out)";
        return invalid;
      }
      const MetaMethod* ms = locked->metaObject().method(src.method);
      if (!ms)
      {
        qiLogWarning() << "Method " << src.method <<" not found, proceeding anyway";
        goto proceed;
      }
      else
      {
        subSignature = ms->parametersSignature();
        subArity = subSignature.size();
      }
    }
    if (sigArity != subArity)
    {
      qiLogWarning() << "Subscriber has incorrect arity (expected "
        << sigArity  << " , got " << subArity <<")";
      return invalid;
    }
    if (!signature().isConvertibleTo(subSignature))
    {
      qiLogWarning() << "Subscriber is not compatible to signal : "
       << signature().toString() << " vs " << subSignature.toString();
      return invalid;
    }
  proceed:
    boost::recursive_mutex::scoped_lock sl(_p->mutex);
    SignalLink res = ++linkUid;
    SignalSubscriberPtr s = boost::make_shared<SignalSubscriber>(src);
    s->linkId = res;
    s->source = this;
    bool first = _p->subscriberMap.empty();
    _p->subscriberMap[res] = s;
    if (first && _p->onSubscribers)
      _p->onSubscribers(true);
    return *s.get();
  }

  bool SignalBase::disconnectAll() {
    if (_p)
      return _p->reset();
    return false;
  }

  SignalBase::SignalBase(const qi::Signature& sig, OnSubscribers onSubscribers)
    : _p(new SignalBasePrivate)
  {
    _p->onSubscribers = onSubscribers;
    _p->signature = sig;
  }

  SignalBase::SignalBase(OnSubscribers onSubscribers)
  : _p(new SignalBasePrivate)
  {
    _p->onSubscribers = onSubscribers;
  }

  SignalBase::SignalBase(const SignalBase& b)
  {
    (*this) = b;
  }

  SignalBase& SignalBase::operator=(const SignalBase& b)
  {
    if (!b._p)
    {
      const_cast<SignalBase&>(b)._p = boost::make_shared<SignalBasePrivate>();
    }
    _p = b._p;
    return *this;
  }

  qi::Signature SignalBase::signature() const
  {
    return _p ? _p->signature : qi::Signature();
  }

  void SignalBase::_setSignature(const qi::Signature& s)
  {
    _p->signature = s;
  }

  bool SignalBasePrivate::disconnect(const SignalLink& l)
  {

    SignalSubscriberPtr s;
    // Acquire signal mutex
    boost::recursive_mutex::scoped_lock sigLock(mutex);
    SignalSubscriberMap::iterator it = subscriberMap.find(l);
    if (it == subscriberMap.end())
      return false;
    s = it->second;
    // Remove from map (but SignalSubscriber object still good)
    subscriberMap.erase(it);
    // Acquire subscriber mutex before releasing mutex
    boost::mutex::scoped_lock subLock(s->mutex);
    // Release signal mutex
    sigLock.release()->unlock();
    // Ensure no call on subscriber occurrs once this function returns
    s->enabled = false;
    if (subscriberMap.empty() && onSubscribers)
      onSubscribers(false);
    if ( s->activeThreads.empty()
         || (s->activeThreads.size() == 1
             && *s->activeThreads.begin() == boost::this_thread::get_id()))
    { // One active callback in this thread, means above us in call stack
      // So we cannot trash s right now
      return true;
    }
    // More than one active callback, or one in a state that prevent us
    // from knowing in which thread it will run
    subLock.release()->unlock();
    s->waitForInactive();
    return true;
  }

  bool SignalBase::disconnect(const SignalLink &link) {
    if (!_p)
      return false;
    else
      return _p->disconnect(link);
  }

  SignalBase::~SignalBase()
  {
    if (!_p)
      return;
    _p->onSubscribers = OnSubscribers();
    boost::shared_ptr<SignalBasePrivate> p(_p);
    _p.reset();
    SignalSubscriberMap::iterator i;
    std::vector<SignalLink> links;
    for (i = p->subscriberMap.begin(); i!= p->subscriberMap.end(); ++i)
    {
      links.push_back(i->first);
    }
    for (unsigned i=0; i<links.size(); ++i)
      p->disconnect(links[i]);
  }

  std::vector<SignalSubscriber> SignalBase::subscribers()
  {
    std::vector<SignalSubscriber> res;
    if (!_p)
      return res;
    boost::recursive_mutex::scoped_lock sl(_p->mutex);
    SignalSubscriberMap::iterator i;
    for (i = _p->subscriberMap.begin(); i!= _p->subscriberMap.end(); ++i)
      res.push_back(*i->second);
    return res;
  }

  bool SignalBase::hasSubscribers()
  {
    if (!_p)
      return false;
    boost::recursive_mutex::scoped_lock sl(_p->mutex);
    return !_p->subscriberMap.empty();
  }

  bool SignalBasePrivate::reset() {
    bool ret = true;
    boost::recursive_mutex::scoped_lock sl(mutex);
    SignalSubscriberMap::iterator it = subscriberMap.begin();
    while (it != subscriberMap.end()) {
      bool b = disconnect(it->first);
      if (!b)
        ret = false;
      it = subscriberMap.begin();
    }
    return ret;
  }

  SignalSubscriber& SignalBase::connect(AnyObject obj, const std::string& slot)
  {
    const MetaObject& mo = obj->metaObject();
    const MetaSignal* sig = mo.signal(slot);
    if (sig)
      return connect(SignalSubscriber(obj, sig->uid()));
    std::vector<MetaMethod> method = mo.findMethod(slot);
    if (method.empty())
      throw std::runtime_error("No match found for slot " + slot);
    if (method.size() > 1)
      throw std::runtime_error("Ambiguous slot name " + slot);
    return connect(SignalSubscriber(obj, method.front().uid()));
  }

  QITYPE_API const SignalLink SignalBase::invalidSignalLink = ((unsigned int)-1);

}
<commit_msg>signal: catch PointerLockException to hide an unwanted log<commit_after>/*
**  Copyright (C) 2012 Aldebaran Robotics
**  See COPYING for the license
*/
#include <map>
#include <qi/atomic.hpp>

#include <boost/thread/recursive_mutex.hpp>
#include <boost/make_shared.hpp>

#include <qitype/signal.hpp>
#include <qitype/anyvalue.hpp>
#include <qitype/anyobject.hpp>

#include "anyobject_p.hpp"
#include "signal_p.hpp"

qiLogCategory("qitype.signal");

namespace qi {

  SignalSubscriber::SignalSubscriber(qi::AnyObject target, unsigned int method)
  : threadingModel(MetaCallType_Direct),  target(new qi::ObjectWeakPtr(target)), method(method), enabled(true)
  { // The slot has its own threading model: be synchronous
  }

  SignalSubscriber::SignalSubscriber(AnyFunction func, MetaCallType model)
     : handler(func), threadingModel(model), target(0), method(0), enabled(true)
   {
   }

  SignalSubscriber::~SignalSubscriber()
  {
    delete target;
  }

  SignalSubscriber::SignalSubscriber(const SignalSubscriber& b)
  : target(0)
  {
    *this = b;
  }

  void SignalSubscriber::operator=(const SignalSubscriber& b)
  {
    source = b.source;
    linkId = b.linkId;
    handler = b.handler;
    threadingModel = b.threadingModel;
    target = b.target?new ObjectWeakPtr(*b.target):0;
    method = b.method;
    enabled = b.enabled;
  }

  static qi::Atomic<int> linkUid = 1;

  void SignalBase::setCallType(MetaCallType callType)
  {
    if (!_p)
    {
      _p = boost::make_shared<SignalBasePrivate>();
    }
    _p->defaultCallType = callType;
  }

  void SignalBase::operator()(
      qi::AutoAnyReference p1,
      qi::AutoAnyReference p2,
      qi::AutoAnyReference p3,
      qi::AutoAnyReference p4,
      qi::AutoAnyReference p5,
      qi::AutoAnyReference p6,
      qi::AutoAnyReference p7,
      qi::AutoAnyReference p8)
  {
    qi::AutoAnyReference* vals[8]= {&p1, &p2, &p3, &p4, &p5, &p6, &p7, &p8};
    std::vector<qi::AnyReference> params;
    for (unsigned i = 0; i < 8; ++i)
      if (vals[i]->value)
        params.push_back(*vals[i]);
    qi::Signature signature = qi::makeTupleSignature(params);

    if (signature != _p->signature)
    {
      qiLogError() << "Dropping emit: signature mismatch: " << signature.toString() <<" " << _p->signature.toString();
      return;
    }
    trigger(params, _p->defaultCallType);
  }

  void SignalBase::trigger(const GenericFunctionParameters& params, MetaCallType callType)
  {
    if (!_p)
      return;
    if (_p->triggerOverride)
      _p->triggerOverride(params, callType);
    else
      callSubscribers(params, callType);
  }

  void SignalBase::setTriggerOverride(Trigger t)
  {
    if (!_p)
      _p = boost::make_shared<SignalBasePrivate>();
    _p->triggerOverride = t;
  }

  void SignalBase::setOnSubscribers(OnSubscribers onSubscribers)
  {
    if (!_p)
      _p = boost::make_shared<SignalBasePrivate>();
    _p->onSubscribers = onSubscribers;
  }

  void SignalBase::callSubscribers(const GenericFunctionParameters& params, MetaCallType callType)
  {
    MetaCallType mct = callType;

    if (!_p)
      return;

    if (mct == qi::MetaCallType_Auto)
      mct = _p->defaultCallType;
    SignalSubscriberMap copy;
    {
      boost::recursive_mutex::scoped_lock sl(_p->mutex);
      copy = _p->subscriberMap;
    }
    qiLogDebug() << (void*)this << " Invoking signal subscribers: " << copy.size();
    SignalSubscriberMap::iterator i;
    for (i = copy.begin(); i != copy.end(); ++i)
    {
      qiLogDebug() << (void*)this << " Invoking signal subscriber";
      SignalSubscriberPtr s = i->second; // hold s alive
      s->call(params, mct);
    }
    qiLogDebug() << (void*)this << " done invoking signal subscribers";
  }

  class FunctorCall
  {
  public:
    FunctorCall(GenericFunctionParameters* params, SignalSubscriberPtr* sub)
    : params(params)
    , sub(sub)
    {
    }

    FunctorCall(const FunctorCall& b)
    {
      *this = b;
    }

    void operator=(const FunctorCall& b)
    {
      params = b.params;
      sub = b.sub;
    }

    void operator() ()
    {
      try
      {
        {
          SignalSubscriberPtr s;
          boost::mutex::scoped_lock sl((*sub)->mutex);
          // verify-enabled-then-register-active op must be locked
          if (!(*sub)->enabled)
          {
            s = *sub; // delay destruction until after we leave the scoped_lock
            delete sub;
            params->destroy();
            delete params;
            return;
          }
          (*sub)->addActive(false);
        } // end mutex-protected scope
        (*sub)->handler(*params);
      }
      catch(const qi::PointerLockException&)
      {
        qiLogDebug() << "PointerLockFailure excepton, will disconnect";
      }
      catch(const std::exception& e)
      {
        qiLogWarning() << "Exception caught from signal subscriber: " << e.what();
      }
      catch (...) {
        qiLogWarning() << "Unknown exception caught from signal subscriber";
      }

      (*sub)->removeActive(true);
      params->destroy();
      delete params;
      delete sub;
    }

  public:
    GenericFunctionParameters* params;
    SignalSubscriberPtr*         sub;
  };

  void SignalSubscriber::call(const GenericFunctionParameters& args, MetaCallType callType)
  {
    // this is held alive by caller
    if (handler)
    {
      bool async = true;
      if (threadingModel != MetaCallType_Auto)
        async = (threadingModel == MetaCallType_Queued);
      else if (callType != MetaCallType_Auto)
        async = (callType == MetaCallType_Queued);

      qiLogDebug() << "subscriber call async=" << async <<" ct " << callType <<" tm " << threadingModel;
      if (async)
      {
        GenericFunctionParameters* copy = new GenericFunctionParameters(args.copy());
        // We will check enabled when we will be scheduled in the target
        // thread, and we hold this SignalSubscriber alive, so no need to
        // explicitly track the asynccall

        // courtesy-check of el, but it should be kept alive longuer than us
        qi::EventLoop* el = getDefaultThreadPoolEventLoop();
        if (!el) // this is an assert basicaly, no sense trying to do something clever.
          throw std::runtime_error("Event loop was destroyed");
        el->post(FunctorCall(copy, new SignalSubscriberPtr(shared_from_this())));
      }
      else
      {
        // verify-enabled-then-register-active op must be locked
        {
          boost::mutex::scoped_lock sl(mutex);
          if (!enabled)
            return;
          addActive(false);
        }
        //do not throw
        bool mustDisconnect = false;
        try
        {
          handler(args);
        }
        catch(const qi::PointerLockException&)
        {
          qiLogDebug() << "PointerLockFailure excepton, will disconnect";
          mustDisconnect = true;
        }
        catch(const std::exception& e)
        {
          qiLogWarning() << "Exception caught from signal subscriber: " << e.what();
        }
        catch (...)
        {
          qiLogWarning() << "Unknown exception caught from signal subscriber";
        }
        removeActive(true);
        if (mustDisconnect)
          source->disconnect(linkId);
      }
    }
    else if (target)
    {
      AnyObject lockedTarget = target->lock();
      if (!lockedTarget)
      {
        source->disconnect(linkId);
      }
      else // no need to keep anything locked, whatever happens this is not used
        lockedTarget->metaPost(method, args);
    }
  }

  //check if we are called from the same thread that triggered us.
  //in that case, do not wait.
  void SignalSubscriber::waitForInactive()
  {
    boost::thread::id tid = boost::this_thread::get_id();
    while (true)
    {
      {
        boost::mutex::scoped_lock sl(mutex);
        if (activeThreads.empty())
          return;
        // There cannot be two activeThreads entry for the same tid
        // because activeThreads is not set at the post() stage
        if (activeThreads.size() == 1
          && *activeThreads.begin() == tid)
        { // One active callback in this thread, means above us in call stack
          // So we cannot wait for it
          return;
        }
      }
      os::msleep(1); // FIXME too long use a condition
    }
  }

  void SignalSubscriber::addActive(bool acquireLock, boost::thread::id id)
  {
    if (acquireLock)
    {
      boost::mutex::scoped_lock sl(mutex);
      activeThreads.push_back(id);
    }
    else
      activeThreads.push_back(id);
  }

  void SignalSubscriber::removeActive(bool acquireLock, boost::thread::id id)
  {

    boost::mutex::scoped_lock sl(mutex, boost::defer_lock_t());
    if (acquireLock)
      sl.lock();

    for (unsigned i=0; i<activeThreads.size(); ++i)
    {
      if (activeThreads[i] == id)
      { // fast remove by swapping with last and then pop_back
        activeThreads[i] = activeThreads[activeThreads.size() - 1];
        activeThreads.pop_back();
      }
    }
  }

  SignalSubscriber& SignalBase::connect(qi::AnyObject o, unsigned int slot)
  {
    return connect(SignalSubscriber(o, slot));
  }

  SignalSubscriber& SignalBase::connect(const SignalSubscriber& src)
  {
    qiLogDebug() << (void*)this << " connecting new subscriber";
    static SignalSubscriber invalid;
    if (!_p)
    {
      _p = boost::make_shared<SignalBasePrivate>();
    }
    // Check arity. Does not require to acquire weakLock.
    int sigArity = Signature(signature()).begin().children().size();
    int subArity = -1;
    Signature subSignature;

    if (signature() == "m")
      goto proceed; // no check possible

    if (src.handler)
    {
      if (src.handler.functionType() == dynamicFunctionTypeInterface())
        goto proceed; // no arity checking is possible
      subArity = src.handler.argumentsType().size();
      subSignature = src.handler.parametersSignature();
    }
    else if (src.target)
    {
      AnyObject locked = src.target->lock();
      if (!locked)
      {
        qiLogVerbose() << "connecting a dead slot (weak ptr out)";
        return invalid;
      }
      const MetaMethod* ms = locked->metaObject().method(src.method);
      if (!ms)
      {
        qiLogWarning() << "Method " << src.method <<" not found, proceeding anyway";
        goto proceed;
      }
      else
      {
        subSignature = ms->parametersSignature();
        subArity = subSignature.size();
      }
    }
    if (sigArity != subArity)
    {
      qiLogWarning() << "Subscriber has incorrect arity (expected "
        << sigArity  << " , got " << subArity <<")";
      return invalid;
    }
    if (!signature().isConvertibleTo(subSignature))
    {
      qiLogWarning() << "Subscriber is not compatible to signal : "
       << signature().toString() << " vs " << subSignature.toString();
      return invalid;
    }
  proceed:
    boost::recursive_mutex::scoped_lock sl(_p->mutex);
    SignalLink res = ++linkUid;
    SignalSubscriberPtr s = boost::make_shared<SignalSubscriber>(src);
    s->linkId = res;
    s->source = this;
    bool first = _p->subscriberMap.empty();
    _p->subscriberMap[res] = s;
    if (first && _p->onSubscribers)
      _p->onSubscribers(true);
    return *s.get();
  }

  bool SignalBase::disconnectAll() {
    if (_p)
      return _p->reset();
    return false;
  }

  SignalBase::SignalBase(const qi::Signature& sig, OnSubscribers onSubscribers)
    : _p(new SignalBasePrivate)
  {
    _p->onSubscribers = onSubscribers;
    _p->signature = sig;
  }

  SignalBase::SignalBase(OnSubscribers onSubscribers)
  : _p(new SignalBasePrivate)
  {
    _p->onSubscribers = onSubscribers;
  }

  SignalBase::SignalBase(const SignalBase& b)
  {
    (*this) = b;
  }

  SignalBase& SignalBase::operator=(const SignalBase& b)
  {
    if (!b._p)
    {
      const_cast<SignalBase&>(b)._p = boost::make_shared<SignalBasePrivate>();
    }
    _p = b._p;
    return *this;
  }

  qi::Signature SignalBase::signature() const
  {
    return _p ? _p->signature : qi::Signature();
  }

  void SignalBase::_setSignature(const qi::Signature& s)
  {
    _p->signature = s;
  }

  bool SignalBasePrivate::disconnect(const SignalLink& l)
  {

    SignalSubscriberPtr s;
    // Acquire signal mutex
    boost::recursive_mutex::scoped_lock sigLock(mutex);
    SignalSubscriberMap::iterator it = subscriberMap.find(l);
    if (it == subscriberMap.end())
      return false;
    s = it->second;
    // Remove from map (but SignalSubscriber object still good)
    subscriberMap.erase(it);
    // Acquire subscriber mutex before releasing mutex
    boost::mutex::scoped_lock subLock(s->mutex);
    // Release signal mutex
    sigLock.release()->unlock();
    // Ensure no call on subscriber occurrs once this function returns
    s->enabled = false;
    if (subscriberMap.empty() && onSubscribers)
      onSubscribers(false);
    if ( s->activeThreads.empty()
         || (s->activeThreads.size() == 1
             && *s->activeThreads.begin() == boost::this_thread::get_id()))
    { // One active callback in this thread, means above us in call stack
      // So we cannot trash s right now
      return true;
    }
    // More than one active callback, or one in a state that prevent us
    // from knowing in which thread it will run
    subLock.release()->unlock();
    s->waitForInactive();
    return true;
  }

  bool SignalBase::disconnect(const SignalLink &link) {
    if (!_p)
      return false;
    else
      return _p->disconnect(link);
  }

  SignalBase::~SignalBase()
  {
    if (!_p)
      return;
    _p->onSubscribers = OnSubscribers();
    boost::shared_ptr<SignalBasePrivate> p(_p);
    _p.reset();
    SignalSubscriberMap::iterator i;
    std::vector<SignalLink> links;
    for (i = p->subscriberMap.begin(); i!= p->subscriberMap.end(); ++i)
    {
      links.push_back(i->first);
    }
    for (unsigned i=0; i<links.size(); ++i)
      p->disconnect(links[i]);
  }

  std::vector<SignalSubscriber> SignalBase::subscribers()
  {
    std::vector<SignalSubscriber> res;
    if (!_p)
      return res;
    boost::recursive_mutex::scoped_lock sl(_p->mutex);
    SignalSubscriberMap::iterator i;
    for (i = _p->subscriberMap.begin(); i!= _p->subscriberMap.end(); ++i)
      res.push_back(*i->second);
    return res;
  }

  bool SignalBase::hasSubscribers()
  {
    if (!_p)
      return false;
    boost::recursive_mutex::scoped_lock sl(_p->mutex);
    return !_p->subscriberMap.empty();
  }

  bool SignalBasePrivate::reset() {
    bool ret = true;
    boost::recursive_mutex::scoped_lock sl(mutex);
    SignalSubscriberMap::iterator it = subscriberMap.begin();
    while (it != subscriberMap.end()) {
      bool b = disconnect(it->first);
      if (!b)
        ret = false;
      it = subscriberMap.begin();
    }
    return ret;
  }

  SignalSubscriber& SignalBase::connect(AnyObject obj, const std::string& slot)
  {
    const MetaObject& mo = obj->metaObject();
    const MetaSignal* sig = mo.signal(slot);
    if (sig)
      return connect(SignalSubscriber(obj, sig->uid()));
    std::vector<MetaMethod> method = mo.findMethod(slot);
    if (method.empty())
      throw std::runtime_error("No match found for slot " + slot);
    if (method.size() > 1)
      throw std::runtime_error("Ambiguous slot name " + slot);
    return connect(SignalSubscriber(obj, method.front().uid()));
  }

  QITYPE_API const SignalLink SignalBase::invalidSignalLink = ((unsigned int)-1);

}
<|endoftext|>


<commit_before>#include <configure/bind.hpp>

#include <configure/lua/State.hpp>
#include <configure/lua/Type.hpp>

#include <boost/filesystem/path.hpp>

namespace fs = boost::filesystem;

namespace configure {

	static int Path_new(lua_State* state)
	{
		if (lua_isnil(state, -1))
			lua::Converter<fs::path>::push(state);
		else if (char const* path = lua_tostring(state, -1))
			lua::Converter<fs::path>::push(state, path);
		else if (lua::Converter<fs::path>::extract_ptr(state, -1) != nullptr)
		{ /* Already a path instance */ }
		else
			throw std::runtime_error("Expected string to construct a path");
		return 1;
	}

	static int Path_concat(lua_State* state)
	{
		fs::path p1, p2;
		if (lua_isstring(state, -2))
			p1 = lua_tostring(state, -2);
		else
			p1 = lua::Converter<fs::path>::extract(state, -2);

		if (lua_isstring(state, -1))
			p2 = lua_tostring(state, -1);
		else
			p2 = lua::Converter<fs::path>::extract(state, -1);

		lua::Converter<fs::path>::push(state, p1 / p2);
		return 1;
	}

	static int Path_add(lua_State* state)
	{
		auto& self = lua::Converter<fs::path>::extract(state, 1);
		auto ext = lua::Converter<std::string>::extract(state, 2);
		lua::Converter<fs::path>::push(state, self.string() + ext);
		return 1;
	}

	static int Path_tostring(lua_State* state)
	{
		auto& self = lua::Converter<fs::path>::extract(state, 1);
		lua_pushstring(state, self.string().c_str());
		return 1;
	}

	void bind_path(lua::State& state)
	{
		/// Store a filesystem path.
		// @classmod Path
		lua::Type<fs::path>(state, "Path")
			/// Create a new @{Path} instance
			// @function Path:new
			//
			// @tparam string|Path|nil value Path to store
			// @treturn Path New instance.
			// @usage
			// local p = Path:new() -- equivalent to "."
			// local p = Paht:new('a')
			// local p = Path:new(Path:new('b'))
			.def("new", &Path_new)

			/// Convert to a string
			// @function Path:__tostring
			.def("__tostring", &Path_tostring)

			/// Concatenate paths.
			// @function Path:__div
			// @tparam Path|string component Path to append
			// @treturn Path Concatenated paths
			// @usage
			// -- Concatenate a Path and a string
			// local p = Path:new("a") / "b" -- p == "a/b"
			// -- Or a string and a Path
			// local p = "a" / Path:new("b") -- p == "a/b"
			// -- Or two Paths
			// local p = Path:new("a") / Path:new("b") -- p == "a/b"
			//
			.def("__div", &Path_concat)

			/// Add string to the last component.
			// @function Path:__add
			// @string suffix String to append
			// @treturn Path Path with the new suffix
			// @usage
			// local p = Path:new("path/to/file") + '.extension'
			// -- p == "path/to/file.extension"
			//
			.def("__add", &Path_add)

			/// Last component of a path.
			// @function Path:filename
			// @usage local f = Path:new("a/b/c"):filename()
			// -- f == "c"
			//
			.def("filename", &fs::path::filename)

			/// Parent path
			// @function Path:parent_path
			// @usage local f = Path:new("a/b/c"):parent_path()
			// -- f == "a/b"
			.def("parent_path", &fs::path::parent_path)

			/// Check if a path is absolute.
			/// @function Path:is_absolute
			/// @treturn bool True when the path is absolute
			.def("is_absolute", &fs::path::is_absolute)

			/// Filename without the extension (if any)
			// @function Path:stem
			// @treturn Path
			.def("stem", &fs::path::stem)

			/// Extension of the filename
			// @function Path:extension
			// @treturn Path
			.def("extension", &fs::path::extension)

			/// Extension of the filename
			// @function Path:ext
			// @treturn Path
			.def("ext", &fs::path::extension)

			/// True when the path is empty
			// @function Path:empty
			// @treturn bool
			.def("ext", &fs::path::extension)
		;
	}

}

<commit_msg>Path: Add `is_directory` method.<commit_after>#include <configure/bind.hpp>

#include <configure/lua/State.hpp>
#include <configure/lua/Type.hpp>

#include <boost/filesystem.hpp>

namespace fs = boost::filesystem;

namespace configure {

	static int Path_new(lua_State* state)
	{
		if (lua_isnil(state, -1))
			lua::Converter<fs::path>::push(state);
		else if (char const* path = lua_tostring(state, -1))
			lua::Converter<fs::path>::push(state, path);
		else if (lua::Converter<fs::path>::extract_ptr(state, -1) != nullptr)
		{ /* Already a path instance */ }
		else
			throw std::runtime_error("Expected string to construct a path");
		return 1;
	}

	static int Path_concat(lua_State* state)
	{
		fs::path p1, p2;
		if (lua_isstring(state, -2))
			p1 = lua_tostring(state, -2);
		else
			p1 = lua::Converter<fs::path>::extract(state, -2);

		if (lua_isstring(state, -1))
			p2 = lua_tostring(state, -1);
		else
			p2 = lua::Converter<fs::path>::extract(state, -1);

		lua::Converter<fs::path>::push(state, p1 / p2);
		return 1;
	}

	static int Path_add(lua_State* state)
	{
		auto& self = lua::Converter<fs::path>::extract(state, 1);
		auto ext = lua::Converter<std::string>::extract(state, 2);
		lua::Converter<fs::path>::push(state, self.string() + ext);
		return 1;
	}

	static int Path_is_directory(lua_State* state)
	{
		auto& self = lua::Converter<fs::path>::extract(state, 1);
		lua_pushboolean(state, fs::is_directory(self));
		return 1;
	}

	static int Path_tostring(lua_State* state)
	{
		auto& self = lua::Converter<fs::path>::extract(state, 1);
		lua_pushstring(state, self.string().c_str());
		return 1;
	}

	void bind_path(lua::State& state)
	{
		/// Store a filesystem path.
		// @classmod Path
		lua::Type<fs::path>(state, "Path")
			/// Create a new @{Path} instance
			// @function Path:new
			//
			// @tparam string|Path|nil value Path to store
			// @treturn Path New instance.
			// @usage
			// local p = Path:new() -- equivalent to "."
			// local p = Paht:new('a')
			// local p = Path:new(Path:new('b'))
			.def("new", &Path_new)

			/// Convert to a string
			// @function Path:__tostring
			.def("__tostring", &Path_tostring)

			/// Concatenate paths.
			// @function Path:__div
			// @tparam Path|string component Path to append
			// @treturn Path Concatenated paths
			// @usage
			// -- Concatenate a Path and a string
			// local p = Path:new("a") / "b" -- p == "a/b"
			// -- Or a string and a Path
			// local p = "a" / Path:new("b") -- p == "a/b"
			// -- Or two Paths
			// local p = Path:new("a") / Path:new("b") -- p == "a/b"
			//
			.def("__div", &Path_concat)

			/// Add string to the last component.
			// @function Path:__add
			// @string suffix String to append
			// @treturn Path Path with the new suffix
			// @usage
			// local p = Path:new("path/to/file") + '.extension'
			// -- p == "path/to/file.extension"
			//
			.def("__add", &Path_add)

			/// Last component of a path.
			// @function Path:filename
			// @usage local f = Path:new("a/b/c"):filename()
			// -- f == "c"
			//
			.def("filename", &fs::path::filename)

			/// Parent path
			// @function Path:parent_path
			// @usage local f = Path:new("a/b/c"):parent_path()
			// -- f == "a/b"
			.def("parent_path", &fs::path::parent_path)

			/// Check if a path is absolute.
			/// @function Path:is_absolute
			/// @treturn bool True when the path is absolute
			.def("is_absolute", &fs::path::is_absolute)

			/// True when a path refers to a directory
			// @function Path:is_directory
			// @treturn bool
			.def("is_directory", &Path_is_directory)

			/// Filename without the extension (if any)
			// @function Path:stem
			// @treturn Path
			.def("stem", &fs::path::stem)

			/// Extension of the filename
			// @function Path:extension
			// @treturn Path
			.def("extension", &fs::path::extension)

			/// Extension of the filename
			// @function Path:ext
			// @treturn Path
			.def("ext", &fs::path::extension)

			/// True when the path is empty
			// @function Path:empty
			// @treturn bool
			.def("ext", &fs::path::extension)
		;
	}

}

<|endoftext|>


<commit_before>/*************************************************************************
 *
 * REALM CONFIDENTIAL
 * __________________
 *
 *  [2011] - [2015] Realm Inc
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of Realm Incorporated and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to Realm Incorporated
 * and its suppliers and may be covered by U.S. and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from Realm Incorporated.
 *
 **************************************************************************/
#ifndef REALM_UTIL_MISCELLANEOUS_HPP
#define REALM_UTIL_MISCELLANEOUS_HPP

namespace realm {
namespace util {

template <class T>
const T& as_const(const T& v)
{
    return v;
}

} // namespace util
} // namespace realm

#endif // REALM_UTIL_MISCELLANEOUS_HPP
<commit_msg>Add noexcept declaration to util::as_const<commit_after>/*************************************************************************
 *
 * REALM CONFIDENTIAL
 * __________________
 *
 *  [2011] - [2015] Realm Inc
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of Realm Incorporated and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to Realm Incorporated
 * and its suppliers and may be covered by U.S. and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from Realm Incorporated.
 *
 **************************************************************************/
#ifndef REALM_UTIL_MISCELLANEOUS_HPP
#define REALM_UTIL_MISCELLANEOUS_HPP

namespace realm {
namespace util {

// FIXME: Replace this with std::as_const when we switch over to C++17 by
// default.
template <class T>
const T& as_const(const T& v) noexcept
{
    return v;
}

} // namespace util
} // namespace realm

#endif // REALM_UTIL_MISCELLANEOUS_HPP
<|endoftext|>


<commit_before>
#include <stanza.h>

JID Stanza::from() {
	return JID( tag->getAttribute("from", "") );
}

JID Stanza::to() {
	return JID( tag->getAttribute("to", "") );
}

std::string Stanza::type() {
	return tag->getAttribute("type", "");
}

std::string Stanza::id() {
	return tag->getAttribute("id", "");
}

void Stanza::setFrom(JID &jid) {
	tag->setAttribute("from", jid.full());
}

Stanza Stanza::badRequest(JID server, JID reply_to, std::string id) {
	// <iq from="admin@underjabber.net.ru" type="error" xml:lang="ru-RU" to="admin@underjabber.net.ru/home" >
	// <error type="modify" code="400" >
	//	<bad-request xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/>
	//	</error>
	// </iq>
	ATXmlTag *iq = new ATXmlTag("iq");
	return iq; // тег будет удалён в деструкторе станзы
}

Stanza Stanza::serverVersion(JID server, JID reply_to, std::string id) {
	Stanza iq = new ATXmlTag("iq");
	iq->setAttribute("from", server.bare());
	iq->setAttribute("to", reply_to.full());
	iq->setAttribute("type", "result");
	if( !id.empty() ) iq->setAttribute("id", id);

	TagHelper query = iq["query"];
		query->setDefaultNameSpaceAttribute("jabber:iq:version");
		query["name"] = "@}->--";
		query["version"] = "development branch";
		query["os"] = "Linux";

	return iq;
}

Stanza Stanza::presence(JID from, JID to, ClientPresence p) {
	Stanza presence = new ATXmlTag("presence");
	presence->setAttribute("from", from.full());
	presence->setAttribute("to", to.full());
	presence["show"] = p.show;
	presence["priority"] = p.getPriority();
	presence["status"] = p.status_text;
	return presence;
}

/**
* Stream errors (RFC 3920, 4.7)
* @param condition имя тега ошибки
* @param message поясняющий текст
* @param lang язык
* @return сформированная станза
*/
Stanza Stanza::streamError(const std::string &condition, const std::string &message, const std::string &lang)
{
	Stanza error = new ATXmlTag("stream:error");
	error->setDefaultNameSpaceAttribute("urn:ietf:params:xml:ns:xmpp-streams");
	error[condition];

	if ( message != "" ) {
		error["text"] = message;
		if ( lang != "" ) error["text"]->setAttribute("xml:lang", lang);
	}

	return error;
}

/**
* IQ error
* @param stanza станза вызвавшая ошибку
* @param condition имя тега ошибки
* @param type тип (cancel, continue, modify, auth, wait)
* @param message поясняющий текст
* @param lang язык
* @return сформированная станза
*/
Stanza Stanza::iqError(Stanza stanza, const std::string &condition, const std::string &type, const std::string &message, const std::string &lang)
{
	Stanza iq = new ATXmlTag("iq");
	iq->setAttribute("from", stanza.to().full());
	iq->setAttribute("to", stanza.from().full());
	iq->setAttribute("type", "error");
	iq->setAttribute("id", stanza->getAttribute("id", ""));
	//iq += (ATXmlTag*)stanza;

	TagHelper error = iq["error"];
	error->setAttribute("type", type);
	error[condition]->setDefaultNameSpaceAttribute("urn:ietf:params:xml:ns:xmpp-stanzas");

	return iq;
}

/**
* Presence error
* @param stanza станза вызвавшая ошибку
* @param condition имя тега ошибки
* @param type тип (cancel, continue, modify, auth, wait)
* @param message поясняющий текст
* @param lang язык
* @return сформированная станза
*/
Stanza Stanza::presenceError(Stanza stanza, const std::string &condition, const std::string &type, const std::string &message, const std::string &lang)
{
	Stanza iq = new ATXmlTag("presence");
	iq->setAttribute("from", stanza.to().full());
	iq->setAttribute("to", stanza.from().full());
	iq->setAttribute("type", "error");
	if ( stanza->hasAttribute("id") ) iq->setAttribute("id", stanza->getAttribute("id", ""));
	//iq += (ATXmlTag*)stanza;

	TagHelper error = iq["error"];
	error->setAttribute("type", type);
	error[condition]->setDefaultNameSpaceAttribute("urn:ietf:params:xml:ns:xmpp-stanzas");

	return iq;
}
<commit_msg>Just a little joke :)<commit_after>
#include <stanza.h>

JID Stanza::from() {
	return JID( tag->getAttribute("from", "") );
}

JID Stanza::to() {
	return JID( tag->getAttribute("to", "") );
}

std::string Stanza::type() {
	return tag->getAttribute("type", "");
}

std::string Stanza::id() {
	return tag->getAttribute("id", "");
}

void Stanza::setFrom(JID &jid) {
	tag->setAttribute("from", jid.full());
}

Stanza Stanza::badRequest(JID server, JID reply_to, std::string id) {
	// <iq from="admin@underjabber.net.ru" type="error" xml:lang="ru-RU" to="admin@underjabber.net.ru/home" >
	// <error type="modify" code="400" >
	//	<bad-request xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/>
	//	</error>
	// </iq>
	ATXmlTag *iq = new ATXmlTag("iq");
	return iq; // тег будет удалён в деструкторе станзы
}

Stanza Stanza::serverVersion(JID server, JID reply_to, std::string id) {
	Stanza iq = new ATXmlTag("iq");
	iq->setAttribute("from", server.bare());
	iq->setAttribute("to", reply_to.full());
	iq->setAttribute("type", "result");
	if( !id.empty() ) iq->setAttribute("id", id);

	TagHelper query = iq["query"];
		query->setDefaultNameSpaceAttribute("jabber:iq:version");
		query["name"] = "@}->--"; // TODO: макросы с версией и именем сервера
		query["version"] = "development branch";
		query["os"] = ":-*";

	return iq;
}

Stanza Stanza::presence(JID from, JID to, ClientPresence p) {
	Stanza presence = new ATXmlTag("presence");
	presence->setAttribute("from", from.full());
	presence->setAttribute("to", to.full());
	presence["show"] = p.show;
	presence["priority"] = p.getPriority();
	presence["status"] = p.status_text;
	return presence;
}

/**
* Stream errors (RFC 3920, 4.7)
* @param condition имя тега ошибки
* @param message поясняющий текст
* @param lang язык
* @return сформированная станза
*/
Stanza Stanza::streamError(const std::string &condition, const std::string &message, const std::string &lang)
{
	Stanza error = new ATXmlTag("stream:error");
	error->setDefaultNameSpaceAttribute("urn:ietf:params:xml:ns:xmpp-streams");
	error[condition];

	if ( message != "" ) {
		error["text"] = message;
		if ( lang != "" ) error["text"]->setAttribute("xml:lang", lang);
	}

	return error;
}

/**
* IQ error
* @param stanza станза вызвавшая ошибку
* @param condition имя тега ошибки
* @param type тип (cancel, continue, modify, auth, wait)
* @param message поясняющий текст
* @param lang язык
* @return сформированная станза
*/
Stanza Stanza::iqError(Stanza stanza, const std::string &condition, const std::string &type, const std::string &message, const std::string &lang)
{
	Stanza iq = new ATXmlTag("iq");
	iq->setAttribute("from", stanza.to().full());
	iq->setAttribute("to", stanza.from().full());
	iq->setAttribute("type", "error");
	iq->setAttribute("id", stanza->getAttribute("id", ""));
	//iq += (ATXmlTag*)stanza;

	TagHelper error = iq["error"];
	error->setAttribute("type", type);
	error[condition]->setDefaultNameSpaceAttribute("urn:ietf:params:xml:ns:xmpp-stanzas");

	return iq;
}

/**
* Presence error
* @param stanza станза вызвавшая ошибку
* @param condition имя тега ошибки
* @param type тип (cancel, continue, modify, auth, wait)
* @param message поясняющий текст
* @param lang язык
* @return сформированная станза
*/
Stanza Stanza::presenceError(Stanza stanza, const std::string &condition, const std::string &type, const std::string &message, const std::string &lang)
{
	Stanza iq = new ATXmlTag("presence");
	iq->setAttribute("from", stanza.to().full());
	iq->setAttribute("to", stanza.from().full());
	iq->setAttribute("type", "error");
	if ( stanza->hasAttribute("id") ) iq->setAttribute("id", stanza->getAttribute("id", ""));
	//iq += (ATXmlTag*)stanza;

	TagHelper error = iq["error"];
	error->setAttribute("type", type);
	error[condition]->setDefaultNameSpaceAttribute("urn:ietf:params:xml:ns:xmpp-stanzas");

	return iq;
}
<|endoftext|>


<commit_before>/*
  Copyright (c) 2016, Antonio SJ Musumeci <trapexit@spawn.link>

  Permission to use, copy, modify, and/or distribute this software for any
  purpose with or without fee is hereby granted, provided that the above
  copyright notice and this permission notice appear in all copies.

  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#include <fuse.h>

#include <algorithm>
#include <climits>
#include <map>
#include <string>
#include <vector>

#include "config.hpp"
#include "errno.hpp"
#include "fs_base_stat.hpp"
#include "fs_base_statvfs.hpp"
#include "rwlock.hpp"
#include "success_fail.hpp"
#include "ugid.hpp"

using std::string;
using std::map;
using std::vector;

static
void
_normalize_statvfs(struct statvfs      *fsstat,
                   const unsigned long  min_bsize,
                   const unsigned long  min_frsize,
                   const unsigned long  min_namemax)
{
  fsstat->f_blocks  = (fsblkcnt_t)((fsstat->f_blocks * fsstat->f_frsize) / min_frsize);
  fsstat->f_bfree   = (fsblkcnt_t)((fsstat->f_bfree * fsstat->f_frsize) / min_frsize);
  fsstat->f_bavail  = (fsblkcnt_t)((fsstat->f_bavail * fsstat->f_frsize) / min_frsize);
  fsstat->f_bsize   = min_bsize;
  fsstat->f_frsize  = min_frsize;
  fsstat->f_namemax = min_namemax;
}

static
void
_merge_statvfs(struct statvfs       * const out,
               const struct statvfs * const in)
{
  out->f_blocks += in->f_blocks;
  out->f_bfree  += in->f_bfree;
  out->f_bavail += in->f_bavail;

  out->f_files  += in->f_files;
  out->f_ffree  += in->f_ffree;
  out->f_favail += in->f_favail;
}

static
void
_statfs_core(const char                *srcmount,
             unsigned long             &min_bsize,
             unsigned long             &min_frsize,
             unsigned long             &min_namemax,
             map<dev_t,struct statvfs> &fsstats)
{
  int rv;
  struct stat st;
  struct statvfs fsstat;

  rv = fs::statvfs(srcmount,fsstat);
  if(STATVFS_FAILED(rv))
    return;

  rv = fs::stat(srcmount,st);
  if(STAT_FAILED(rv))
    return;

  if(min_bsize > fsstat.f_bsize)
    min_bsize = fsstat.f_bsize;
  if(min_frsize > fsstat.f_frsize)
    min_frsize = fsstat.f_frsize;
  if(min_namemax > fsstat.f_namemax)
    min_namemax = fsstat.f_namemax;

  fsstats.insert(std::make_pair(st.st_dev,fsstat));
}

static
int
_statfs(const vector<string> &srcmounts,
        struct statvfs       &fsstat)
{
  map<dev_t,struct statvfs> fsstats;
  unsigned long min_bsize   = ULONG_MAX;
  unsigned long min_frsize  = ULONG_MAX;
  unsigned long min_namemax = ULONG_MAX;

  for(size_t i = 0, ei = srcmounts.size(); i < ei; i++)
    {
      _statfs_core(srcmounts[i].c_str(),min_bsize,min_frsize,min_namemax,fsstats);
    }

  map<dev_t,struct statvfs>::iterator iter    = fsstats.begin();
  map<dev_t,struct statvfs>::iterator enditer = fsstats.end();
  if(iter != enditer)
    {
      fsstat = iter->second;
      _normalize_statvfs(&fsstat,min_bsize,min_frsize,min_namemax);

      for(++iter; iter != enditer; ++iter)
        {
          _normalize_statvfs(&iter->second,min_bsize,min_frsize,min_namemax);
          _merge_statvfs(&fsstat,&iter->second);
        }
    }

  return 0;
}

namespace mergerfs
{
  namespace fuse
  {
    int
    statfs(const char     *fusepath,
           struct statvfs *stat)
    {
      const fuse_context      *fc     = fuse_get_context();
      const Config            &config = Config::get(fc);
      const ugid::Set          ugid(fc->uid,fc->gid);
      const rwlock::ReadGuard  readlock(&config.srcmountslock);

      return _statfs(config.srcmounts,
                     *stat);
    }
  }
}
<commit_msg>ignore filesystems which return zeros for statfs. closes #335<commit_after>/*
  Copyright (c) 2016, Antonio SJ Musumeci <trapexit@spawn.link>

  Permission to use, copy, modify, and/or distribute this software for any
  purpose with or without fee is hereby granted, provided that the above
  copyright notice and this permission notice appear in all copies.

  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#include <fuse.h>

#include <algorithm>
#include <climits>
#include <map>
#include <string>
#include <vector>

#include "config.hpp"
#include "errno.hpp"
#include "fs_base_stat.hpp"
#include "fs_base_statvfs.hpp"
#include "rwlock.hpp"
#include "success_fail.hpp"
#include "ugid.hpp"

using std::string;
using std::map;
using std::vector;

static
void
_normalize_statvfs(struct statvfs      *fsstat,
                   const unsigned long  min_bsize,
                   const unsigned long  min_frsize,
                   const unsigned long  min_namemax)
{
  fsstat->f_blocks  = (fsblkcnt_t)((fsstat->f_blocks * fsstat->f_frsize) / min_frsize);
  fsstat->f_bfree   = (fsblkcnt_t)((fsstat->f_bfree * fsstat->f_frsize) / min_frsize);
  fsstat->f_bavail  = (fsblkcnt_t)((fsstat->f_bavail * fsstat->f_frsize) / min_frsize);
  fsstat->f_bsize   = min_bsize;
  fsstat->f_frsize  = min_frsize;
  fsstat->f_namemax = min_namemax;
}

static
void
_merge_statvfs(struct statvfs       * const out,
               const struct statvfs * const in)
{
  out->f_blocks += in->f_blocks;
  out->f_bfree  += in->f_bfree;
  out->f_bavail += in->f_bavail;

  out->f_files  += in->f_files;
  out->f_ffree  += in->f_ffree;
  out->f_favail += in->f_favail;
}

static
void
_statfs_core(const char                *srcmount,
             unsigned long             &min_bsize,
             unsigned long             &min_frsize,
             unsigned long             &min_namemax,
             map<dev_t,struct statvfs> &fsstats)
{
  int rv;
  struct stat st;
  struct statvfs fsstat;

  rv = fs::statvfs(srcmount,fsstat);
  if(STATVFS_FAILED(rv))
    return;

  rv = fs::stat(srcmount,st);
  if(STAT_FAILED(rv))
    return;

  if(fsstat.f_bsize   && (min_bsize > fsstat.f_bsize))
    min_bsize = fsstat.f_bsize;
  if(fsstat.f_frsize  && (min_frsize > fsstat.f_frsize))
    min_frsize = fsstat.f_frsize;
  if(fsstat.f_namemax && (min_namemax > fsstat.f_namemax))
    min_namemax = fsstat.f_namemax;

  fsstats.insert(std::make_pair(st.st_dev,fsstat));
}

static
int
_statfs(const vector<string> &srcmounts,
        struct statvfs       &fsstat)
{
  map<dev_t,struct statvfs> fsstats;
  unsigned long min_bsize   = ULONG_MAX;
  unsigned long min_frsize  = ULONG_MAX;
  unsigned long min_namemax = ULONG_MAX;

  for(size_t i = 0, ei = srcmounts.size(); i < ei; i++)
    {
      _statfs_core(srcmounts[i].c_str(),min_bsize,min_frsize,min_namemax,fsstats);
    }

  map<dev_t,struct statvfs>::iterator iter    = fsstats.begin();
  map<dev_t,struct statvfs>::iterator enditer = fsstats.end();
  if(iter != enditer)
    {
      fsstat = iter->second;
      _normalize_statvfs(&fsstat,min_bsize,min_frsize,min_namemax);

      for(++iter; iter != enditer; ++iter)
        {
          _normalize_statvfs(&iter->second,min_bsize,min_frsize,min_namemax);
          _merge_statvfs(&fsstat,&iter->second);
        }
    }

  return 0;
}

namespace mergerfs
{
  namespace fuse
  {
    int
    statfs(const char     *fusepath,
           struct statvfs *stat)
    {
      const fuse_context      *fc     = fuse_get_context();
      const Config            &config = Config::get(fc);
      const ugid::Set          ugid(fc->uid,fc->gid);
      const rwlock::ReadGuard  readlock(&config.srcmountslock);

      return _statfs(config.srcmounts,
                     *stat);
    }
  }
}
<|endoftext|>


<commit_before>//===------------------------- string.cpp ---------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "string"
#include "charconv"
#include "cstdlib"
#include "cwchar"
#include "cerrno"
#include "limits"
#include "stdexcept"
#include <stdio.h>
#include "__debug"

_LIBCPP_BEGIN_NAMESPACE_STD

template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __basic_string_common<true>;

template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_string<char>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_string<wchar_t>;

template
    string
    operator+<char, char_traits<char>, allocator<char> >(char const*, string const&);

namespace
{

template<typename T>
inline
void throw_helper( const string& msg )
{
#ifndef _LIBCPP_NO_EXCEPTIONS
    throw T( msg );
#else
    fprintf(stderr, "%s\n", msg.c_str());
    _VSTD::abort();
#endif
}

inline
void throw_from_string_out_of_range( const string& func )
{
    throw_helper<out_of_range>(func + ": out of range");
}

inline
void throw_from_string_invalid_arg( const string& func )
{
    throw_helper<invalid_argument>(func + ": no conversion");
}

// as_integer

template<typename V, typename S, typename F>
inline
V
as_integer_helper(const string& func, const S& str, size_t* idx, int base, F f)
{
    typename S::value_type* ptr = nullptr;
    const typename S::value_type* const p = str.c_str();
    typename remove_reference<decltype(errno)>::type errno_save = errno;
    errno = 0;
    V r = f(p, &ptr, base);
    swap(errno, errno_save);
    if (errno_save == ERANGE)
        throw_from_string_out_of_range(func);
    if (ptr == p)
        throw_from_string_invalid_arg(func);
    if (idx)
        *idx = static_cast<size_t>(ptr - p);
    return r;
}

template<typename V, typename S>
inline
V
as_integer(const string& func, const S& s, size_t* idx, int base);

// string
template<>
inline
int
as_integer(const string& func, const string& s, size_t* idx, int base )
{
    // Use long as no Standard string to integer exists.
    long r = as_integer_helper<long>( func, s, idx, base, strtol );
    if (r < numeric_limits<int>::min() || numeric_limits<int>::max() < r)
        throw_from_string_out_of_range(func);
    return static_cast<int>(r);
}

template<>
inline
long
as_integer(const string& func, const string& s, size_t* idx, int base )
{
    return as_integer_helper<long>( func, s, idx, base, strtol );
}

template<>
inline
unsigned long
as_integer( const string& func, const string& s, size_t* idx, int base )
{
    return as_integer_helper<unsigned long>( func, s, idx, base, strtoul );
}

template<>
inline
long long
as_integer( const string& func, const string& s, size_t* idx, int base )
{
    return as_integer_helper<long long>( func, s, idx, base, strtoll );
}

template<>
inline
unsigned long long
as_integer( const string& func, const string& s, size_t* idx, int base )
{
    return as_integer_helper<unsigned long long>( func, s, idx, base, strtoull );
}

// wstring
template<>
inline
int
as_integer( const string& func, const wstring& s, size_t* idx, int base )
{
    // Use long as no Stantard string to integer exists.
    long r = as_integer_helper<long>( func, s, idx, base, wcstol );
    if (r < numeric_limits<int>::min() || numeric_limits<int>::max() < r)
        throw_from_string_out_of_range(func);
    return static_cast<int>(r);
}

template<>
inline
long
as_integer( const string& func, const wstring& s, size_t* idx, int base )
{
    return as_integer_helper<long>( func, s, idx, base, wcstol );
}

template<>
inline
unsigned long
as_integer( const string& func, const wstring& s, size_t* idx, int base )
{
    return as_integer_helper<unsigned long>( func, s, idx, base, wcstoul );
}

template<>
inline
long long
as_integer( const string& func, const wstring& s, size_t* idx, int base )
{
    return as_integer_helper<long long>( func, s, idx, base, wcstoll );
}

template<>
inline
unsigned long long
as_integer( const string& func, const wstring& s, size_t* idx, int base )
{
    return as_integer_helper<unsigned long long>( func, s, idx, base, wcstoull );
}

// as_float

template<typename V, typename S, typename F>
inline
V
as_float_helper(const string& func, const S& str, size_t* idx, F f )
{
    typename S::value_type* ptr = nullptr;
    const typename S::value_type* const p = str.c_str();
    typename remove_reference<decltype(errno)>::type errno_save = errno;
    errno = 0;
    V r = f(p, &ptr);
    swap(errno, errno_save);
    if (errno_save == ERANGE)
        throw_from_string_out_of_range(func);
    if (ptr == p)
        throw_from_string_invalid_arg(func);
    if (idx)
        *idx = static_cast<size_t>(ptr - p);
    return r;
}

template<typename V, typename S>
inline
V as_float( const string& func, const S& s, size_t* idx = nullptr );

template<>
inline
float
as_float( const string& func, const string& s, size_t* idx )
{
    return as_float_helper<float>( func, s, idx, strtof );
}

template<>
inline
double
as_float(const string& func, const string& s, size_t* idx )
{
    return as_float_helper<double>( func, s, idx, strtod );
}

template<>
inline
long double
as_float( const string& func, const string& s, size_t* idx )
{
    return as_float_helper<long double>( func, s, idx, strtold );
}

template<>
inline
float
as_float( const string& func, const wstring& s, size_t* idx )
{
    return as_float_helper<float>( func, s, idx, wcstof );
}

template<>
inline
double
as_float( const string& func, const wstring& s, size_t* idx )
{
    return as_float_helper<double>( func, s, idx, wcstod );
}

template<>
inline
long double
as_float( const string& func, const wstring& s, size_t* idx )
{
    return as_float_helper<long double>( func, s, idx, wcstold );
}

}  // unnamed namespace

int
stoi(const string& str, size_t* idx, int base)
{
    return as_integer<int>( "stoi", str, idx, base );
}

int
stoi(const wstring& str, size_t* idx, int base)
{
    return as_integer<int>( "stoi", str, idx, base );
}

long
stol(const string& str, size_t* idx, int base)
{
    return as_integer<long>( "stol", str, idx, base );
}

long
stol(const wstring& str, size_t* idx, int base)
{
    return as_integer<long>( "stol", str, idx, base );
}

unsigned long
stoul(const string& str, size_t* idx, int base)
{
    return as_integer<unsigned long>( "stoul", str, idx, base );
}

unsigned long
stoul(const wstring& str, size_t* idx, int base)
{
    return as_integer<unsigned long>( "stoul", str, idx, base );
}

long long
stoll(const string& str, size_t* idx, int base)
{
    return as_integer<long long>( "stoll", str, idx, base );
}

long long
stoll(const wstring& str, size_t* idx, int base)
{
    return as_integer<long long>( "stoll", str, idx, base );
}

unsigned long long
stoull(const string& str, size_t* idx, int base)
{
    return as_integer<unsigned long long>( "stoull", str, idx, base );
}

unsigned long long
stoull(const wstring& str, size_t* idx, int base)
{
    return as_integer<unsigned long long>( "stoull", str, idx, base );
}

float
stof(const string& str, size_t* idx)
{
    return as_float<float>( "stof", str, idx );
}

float
stof(const wstring& str, size_t* idx)
{
    return as_float<float>( "stof", str, idx );
}

double
stod(const string& str, size_t* idx)
{
    return as_float<double>( "stod", str, idx );
}

double
stod(const wstring& str, size_t* idx)
{
    return as_float<double>( "stod", str, idx );
}

long double
stold(const string& str, size_t* idx)
{
    return as_float<long double>( "stold", str, idx );
}

long double
stold(const wstring& str, size_t* idx)
{
    return as_float<long double>( "stold", str, idx );
}

// to_string

namespace
{

// as_string

template<typename S, typename P, typename V >
inline
S
as_string(P sprintf_like, S s, const typename S::value_type* fmt, V a)
{
    typedef typename S::size_type size_type;
    size_type available = s.size();
    while (true)
    {
        int status = sprintf_like(&s[0], available + 1, fmt, a);
        if ( status >= 0 )
        {
            size_type used = static_cast<size_type>(status);
            if ( used <= available )
            {
                s.resize( used );
                break;
            }
            available = used; // Assume this is advice of how much space we need.
        }
        else
            available = available * 2 + 1;
        s.resize(available);
    }
    return s;
}

template <class S>
struct initial_string;

template <>
struct initial_string<string>
{
    string
    operator()() const
    {
        string s;
        s.resize(s.capacity());
        return s;
    }
};

template <>
struct initial_string<wstring>
{
    wstring
    operator()() const
    {
        wstring s(20, wchar_t());
        s.resize(s.capacity());
        return s;
    }
};

typedef int (*wide_printf)(wchar_t* __restrict, size_t, const wchar_t*__restrict, ...);

inline
wide_printf
get_swprintf()
{
#ifndef _LIBCPP_MSVCRT
    return swprintf;
#else
    return static_cast<int (__cdecl*)(wchar_t* __restrict, size_t, const wchar_t*__restrict, ...)>(_snwprintf);
#endif
}

template <typename S, typename V>
S i_to_string(const V v)
{
//  numeric_limits::digits10 returns value less on 1 than desired for unsigned numbers.
//  For example, for 1-byte unsigned value digits10 is 2 (999 can not be represented),
//  so we need +1 here.
    constexpr size_t bufsize = numeric_limits<V>::digits10 + 2;  // +1 for minus, +1 for digits10
    char buf[bufsize];
    const auto res = to_chars(buf, buf + bufsize, v);
    _LIBCPP_ASSERT(res.ec == errc(), "bufsize must be large enough to accomodate the value");
    return S(buf, res.ptr);
}

}  // unnamed namespace

string  to_string (int val)                { return i_to_string< string>(val); }
string  to_string (long val)               { return i_to_string< string>(val); }
string  to_string (long long val)          { return i_to_string< string>(val); }
string  to_string (unsigned val)           { return i_to_string< string>(val); }
string  to_string (unsigned long val)      { return i_to_string< string>(val); }
string  to_string (unsigned long long val) { return i_to_string< string>(val); }

wstring to_wstring(int val)                { return i_to_string<wstring>(val); }
wstring to_wstring(long val)               { return i_to_string<wstring>(val); }
wstring to_wstring(long long val)          { return i_to_string<wstring>(val); }
wstring to_wstring(unsigned val)           { return i_to_string<wstring>(val); }
wstring to_wstring(unsigned long val)      { return i_to_string<wstring>(val); }
wstring to_wstring(unsigned long long val) { return i_to_string<wstring>(val); }

string  to_string (float val)       { return as_string(snprintf,       initial_string< string>()(),   "%f", val); }
string  to_string (double val)      { return as_string(snprintf,       initial_string< string>()(),   "%f", val); }
string  to_string (long double val) { return as_string(snprintf,       initial_string< string>()(),  "%Lf", val); }

wstring to_wstring(float val)       { return as_string(get_swprintf(), initial_string<wstring>()(),  L"%f", val); }
wstring to_wstring(double val)      { return as_string(get_swprintf(), initial_string<wstring>()(),  L"%f", val); }
wstring to_wstring(long double val) { return as_string(get_swprintf(), initial_string<wstring>()(), L"%Lf", val); }

_LIBCPP_END_NAMESPACE_STD
<commit_msg>Revert "Speedup to_string and to_wstring for integers using stack buffer and SSO."<commit_after>//===------------------------- string.cpp ---------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "string"
#include "cstdlib"
#include "cwchar"
#include "cerrno"
#include "limits"
#include "stdexcept"
#include <stdio.h>

_LIBCPP_BEGIN_NAMESPACE_STD

template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __basic_string_common<true>;

template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_string<char>;
template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_string<wchar_t>;

template
    string
    operator+<char, char_traits<char>, allocator<char> >(char const*, string const&);

namespace
{

template<typename T>
inline
void throw_helper( const string& msg )
{
#ifndef _LIBCPP_NO_EXCEPTIONS
    throw T( msg );
#else
    fprintf(stderr, "%s\n", msg.c_str());
    _VSTD::abort();
#endif
}

inline
void throw_from_string_out_of_range( const string& func )
{
    throw_helper<out_of_range>(func + ": out of range");
}

inline
void throw_from_string_invalid_arg( const string& func )
{
    throw_helper<invalid_argument>(func + ": no conversion");
}

// as_integer

template<typename V, typename S, typename F>
inline
V
as_integer_helper(const string& func, const S& str, size_t* idx, int base, F f)
{
    typename S::value_type* ptr = nullptr;
    const typename S::value_type* const p = str.c_str();
    typename remove_reference<decltype(errno)>::type errno_save = errno;
    errno = 0;
    V r = f(p, &ptr, base);
    swap(errno, errno_save);
    if (errno_save == ERANGE)
        throw_from_string_out_of_range(func);
    if (ptr == p)
        throw_from_string_invalid_arg(func);
    if (idx)
        *idx = static_cast<size_t>(ptr - p);
    return r;
}

template<typename V, typename S>
inline
V
as_integer(const string& func, const S& s, size_t* idx, int base);

// string
template<>
inline
int
as_integer(const string& func, const string& s, size_t* idx, int base )
{
    // Use long as no Standard string to integer exists.
    long r = as_integer_helper<long>( func, s, idx, base, strtol );
    if (r < numeric_limits<int>::min() || numeric_limits<int>::max() < r)
        throw_from_string_out_of_range(func);
    return static_cast<int>(r);
}

template<>
inline
long
as_integer(const string& func, const string& s, size_t* idx, int base )
{
    return as_integer_helper<long>( func, s, idx, base, strtol );
}

template<>
inline
unsigned long
as_integer( const string& func, const string& s, size_t* idx, int base )
{
    return as_integer_helper<unsigned long>( func, s, idx, base, strtoul );
}

template<>
inline
long long
as_integer( const string& func, const string& s, size_t* idx, int base )
{
    return as_integer_helper<long long>( func, s, idx, base, strtoll );
}

template<>
inline
unsigned long long
as_integer( const string& func, const string& s, size_t* idx, int base )
{
    return as_integer_helper<unsigned long long>( func, s, idx, base, strtoull );
}

// wstring
template<>
inline
int
as_integer( const string& func, const wstring& s, size_t* idx, int base )
{
    // Use long as no Stantard string to integer exists.
    long r = as_integer_helper<long>( func, s, idx, base, wcstol );
    if (r < numeric_limits<int>::min() || numeric_limits<int>::max() < r)
        throw_from_string_out_of_range(func);
    return static_cast<int>(r);
}

template<>
inline
long
as_integer( const string& func, const wstring& s, size_t* idx, int base )
{
    return as_integer_helper<long>( func, s, idx, base, wcstol );
}

template<>
inline
unsigned long
as_integer( const string& func, const wstring& s, size_t* idx, int base )
{
    return as_integer_helper<unsigned long>( func, s, idx, base, wcstoul );
}

template<>
inline
long long
as_integer( const string& func, const wstring& s, size_t* idx, int base )
{
    return as_integer_helper<long long>( func, s, idx, base, wcstoll );
}

template<>
inline
unsigned long long
as_integer( const string& func, const wstring& s, size_t* idx, int base )
{
    return as_integer_helper<unsigned long long>( func, s, idx, base, wcstoull );
}

// as_float

template<typename V, typename S, typename F>
inline
V
as_float_helper(const string& func, const S& str, size_t* idx, F f )
{
    typename S::value_type* ptr = nullptr;
    const typename S::value_type* const p = str.c_str();
    typename remove_reference<decltype(errno)>::type errno_save = errno;
    errno = 0;
    V r = f(p, &ptr);
    swap(errno, errno_save);
    if (errno_save == ERANGE)
        throw_from_string_out_of_range(func);
    if (ptr == p)
        throw_from_string_invalid_arg(func);
    if (idx)
        *idx = static_cast<size_t>(ptr - p);
    return r;
}

template<typename V, typename S>
inline
V as_float( const string& func, const S& s, size_t* idx = nullptr );

template<>
inline
float
as_float( const string& func, const string& s, size_t* idx )
{
    return as_float_helper<float>( func, s, idx, strtof );
}

template<>
inline
double
as_float(const string& func, const string& s, size_t* idx )
{
    return as_float_helper<double>( func, s, idx, strtod );
}

template<>
inline
long double
as_float( const string& func, const string& s, size_t* idx )
{
    return as_float_helper<long double>( func, s, idx, strtold );
}

template<>
inline
float
as_float( const string& func, const wstring& s, size_t* idx )
{
    return as_float_helper<float>( func, s, idx, wcstof );
}

template<>
inline
double
as_float( const string& func, const wstring& s, size_t* idx )
{
    return as_float_helper<double>( func, s, idx, wcstod );
}

template<>
inline
long double
as_float( const string& func, const wstring& s, size_t* idx )
{
    return as_float_helper<long double>( func, s, idx, wcstold );
}

}  // unnamed namespace

int
stoi(const string& str, size_t* idx, int base)
{
    return as_integer<int>( "stoi", str, idx, base );
}

int
stoi(const wstring& str, size_t* idx, int base)
{
    return as_integer<int>( "stoi", str, idx, base );
}

long
stol(const string& str, size_t* idx, int base)
{
    return as_integer<long>( "stol", str, idx, base );
}

long
stol(const wstring& str, size_t* idx, int base)
{
    return as_integer<long>( "stol", str, idx, base );
}

unsigned long
stoul(const string& str, size_t* idx, int base)
{
    return as_integer<unsigned long>( "stoul", str, idx, base );
}

unsigned long
stoul(const wstring& str, size_t* idx, int base)
{
    return as_integer<unsigned long>( "stoul", str, idx, base );
}

long long
stoll(const string& str, size_t* idx, int base)
{
    return as_integer<long long>( "stoll", str, idx, base );
}

long long
stoll(const wstring& str, size_t* idx, int base)
{
    return as_integer<long long>( "stoll", str, idx, base );
}

unsigned long long
stoull(const string& str, size_t* idx, int base)
{
    return as_integer<unsigned long long>( "stoull", str, idx, base );
}

unsigned long long
stoull(const wstring& str, size_t* idx, int base)
{
    return as_integer<unsigned long long>( "stoull", str, idx, base );
}

float
stof(const string& str, size_t* idx)
{
    return as_float<float>( "stof", str, idx );
}

float
stof(const wstring& str, size_t* idx)
{
    return as_float<float>( "stof", str, idx );
}

double
stod(const string& str, size_t* idx)
{
    return as_float<double>( "stod", str, idx );
}

double
stod(const wstring& str, size_t* idx)
{
    return as_float<double>( "stod", str, idx );
}

long double
stold(const string& str, size_t* idx)
{
    return as_float<long double>( "stold", str, idx );
}

long double
stold(const wstring& str, size_t* idx)
{
    return as_float<long double>( "stold", str, idx );
}

// to_string

namespace
{

// as_string

template<typename S, typename P, typename V >
inline
S
as_string(P sprintf_like, S s, const typename S::value_type* fmt, V a)
{
    typedef typename S::size_type size_type;
    size_type available = s.size();
    while (true)
    {
        int status = sprintf_like(&s[0], available + 1, fmt, a);
        if ( status >= 0 )
        {
            size_type used = static_cast<size_type>(status);
            if ( used <= available )
            {
                s.resize( used );
                break;
            }
            available = used; // Assume this is advice of how much space we need.
        }
        else
            available = available * 2 + 1;
        s.resize(available);
    }
    return s;
}

template <class S, class V, bool = is_floating_point<V>::value>
struct initial_string;

template <class V, bool b>
struct initial_string<string, V, b>
{
    string
    operator()() const
    {
        string s;
        s.resize(s.capacity());
        return s;
    }
};

template <class V>
struct initial_string<wstring, V, false>
{
    wstring
    operator()() const
    {
        const size_t n = (numeric_limits<unsigned long long>::digits / 3)
          + ((numeric_limits<unsigned long long>::digits % 3) != 0)
          + 1;
        wstring s(n, wchar_t());
        s.resize(s.capacity());
        return s;
    }
};

template <class V>
struct initial_string<wstring, V, true>
{
    wstring
    operator()() const
    {
        wstring s(20, wchar_t());
        s.resize(s.capacity());
        return s;
    }
};

typedef int (*wide_printf)(wchar_t* __restrict, size_t, const wchar_t*__restrict, ...);

inline
wide_printf
get_swprintf()
{
#ifndef _LIBCPP_MSVCRT
    return swprintf;
#else
    return static_cast<int (__cdecl*)(wchar_t* __restrict, size_t, const wchar_t*__restrict, ...)>(_snwprintf);
#endif
}

}  // unnamed namespace

string to_string(int val)
{
    return as_string(snprintf, initial_string<string, int>()(), "%d", val);
}

string to_string(unsigned val)
{
    return as_string(snprintf, initial_string<string, unsigned>()(), "%u", val);
}

string to_string(long val)
{
    return as_string(snprintf, initial_string<string, long>()(), "%ld", val);
}

string to_string(unsigned long val)
{
    return as_string(snprintf, initial_string<string, unsigned long>()(), "%lu", val);
}

string to_string(long long val)
{
    return as_string(snprintf, initial_string<string, long long>()(), "%lld", val);
}

string to_string(unsigned long long val)
{
    return as_string(snprintf, initial_string<string, unsigned long long>()(), "%llu", val);
}

string to_string(float val)
{
    return as_string(snprintf, initial_string<string, float>()(), "%f", val);
}

string to_string(double val)
{
    return as_string(snprintf, initial_string<string, double>()(), "%f", val);
}

string to_string(long double val)
{
    return as_string(snprintf, initial_string<string, long double>()(), "%Lf", val);
}

wstring to_wstring(int val)
{
    return as_string(get_swprintf(), initial_string<wstring, int>()(), L"%d", val);
}

wstring to_wstring(unsigned val)
{
    return as_string(get_swprintf(), initial_string<wstring, unsigned>()(), L"%u", val);
}

wstring to_wstring(long val)
{
    return as_string(get_swprintf(), initial_string<wstring, long>()(), L"%ld", val);
}

wstring to_wstring(unsigned long val)
{
    return as_string(get_swprintf(), initial_string<wstring, unsigned long>()(), L"%lu", val);
}

wstring to_wstring(long long val)
{
    return as_string(get_swprintf(), initial_string<wstring, long long>()(), L"%lld", val);
}

wstring to_wstring(unsigned long long val)
{
    return as_string(get_swprintf(), initial_string<wstring, unsigned long long>()(), L"%llu", val);
}

wstring to_wstring(float val)
{
    return as_string(get_swprintf(), initial_string<wstring, float>()(), L"%f", val);
}

wstring to_wstring(double val)
{
    return as_string(get_swprintf(), initial_string<wstring, double>()(), L"%f", val);
}

wstring to_wstring(long double val)
{
    return as_string(get_swprintf(), initial_string<wstring, long double>()(), L"%Lf", val);
}
_LIBCPP_END_NAMESPACE_STD
<|endoftext|>