<commit_before>#pragma once
/*
**  Copyright (C) 2012 Aldebaran Robotics
**  See COPYING for the license
*/

#ifndef _QITYPE_FUTURE_HPP_
#define _QITYPE_FUTURE_HPP_

#include <qi/api.hpp>
#include <vector>
#include <qi/atomic.hpp>
#include <qi/config.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <boost/thread/recursive_mutex.hpp>

#ifdef _MSC_VER
#  pragma warning( push )
#  pragma warning( disable: 4251 )
#  pragma warning( disable: 4275 ) //std::runtime_error: no dll interface
#endif

namespace qi {

  template<typename T>
  struct FutureType
  {
    typedef T type;
    typedef T typecast;
  };

  struct FutureHasNoValue {};
  // Hold a void* for Future<void>
  template<>
  struct FutureType<void>
  {
    typedef void* type;
    typedef FutureHasNoValue typecast;
  };

  template <typename T> class FutureInterface;
  template <typename T> class Future;
  template <typename T> class FutureSync;
  template <typename T> class Promise;

  namespace detail {
    template <typename T> class FutureBaseTyped;
  }

  /** State of the future.
   */
  enum FutureState {
    FutureState_None,               /// Future is not tied to a promise
    FutureState_Running,            /// Operation pending
    FutureState_Canceled,           /// The future has been canceled
    FutureState_FinishedWithError,  /// The operation is finished with an error
    FutureState_FinishedWithValue,  /// The operation is finished with a value
  };

  enum FutureTimeout {
    FutureTimeout_Infinite = ((int) 0x7fffffff),
    FutureTimeout_None     = 0,
  };

  /** base exception raised for all future error.
   */
  class QI_API FutureException : public std::runtime_error {
  public:
    enum ExceptionState {
      //No result ready
      ExceptionState_FutureTimeout,
      //The future has been canceled
      ExceptionState_FutureCanceled,
      //The future is not cancelable
      ExceptionState_FutureNotCancelable,
      //asked for error, but there is no error
      ExceptionState_FutureHasNoError,
      //real future error
      ExceptionState_FutureUserError,
      //when the promise is already set.
      ExceptionState_PromiseAlreadySet,
    };

    explicit FutureException(const ExceptionState &es, const std::string &str = std::string())
      : std::runtime_error(stateToString(es) + str)
      , _state(es)
    {}

    inline ExceptionState state() const { return _state; }

    std::string stateToString(const ExceptionState &es);

    virtual ~FutureException() throw()
    {}

  private:
    ExceptionState _state;
  };

  /** Exception inherited from FutureException
   *  This exception represent an error reported by the operation.
   */
  class QI_API FutureUserException : public FutureException {
  public:

    explicit FutureUserException(const std::string &str = std::string())
      : FutureException(ExceptionState_FutureUserError, str)
    {}

    virtual ~FutureUserException() throw()
    {}
  };

  template <typename T>
  class Future {
  public:
    typedef typename FutureType<T>::type     ValueType;
    typedef typename FutureType<T>::typecast ValueTypeCast;

  public:
    Future()
      : _p(boost::make_shared<detail::FutureBaseTyped<T> >())
    {
    }

    Future(const Future<T>& b)
    : _p(b._p)
    {}

    bool operator==(const Future<T> &other)
    {
      return _p.get() == other._p.get();
    }

    inline Future<T>& operator=(const Future<T>& b)
    {
      _p = b._p;
      return *this;
    }

    bool operator < (const Future<T>& b) const
    {
      return _p.get() < b._p.get();
    }
    explicit Future<T>(const ValueType& v)
    {
      Promise<T> promise;
      promise.setValue(v);
      *this = promise.future();
    }

    /**
     * @brief Return the value associated to a Future.
     * @param msecs timeout
     * @return the value
     *
     * This function can throw for many reason:
     *   - wait timeout
     *   - user error
     *   - future canceled
     *
     * if an error is set, then value throw a FutureUserException, others errors are FutureException.
     */
    inline const ValueType &value(int msecs = FutureTimeout_Infinite) const { return _p->value(msecs); }

    /** same as value() with an infinite timeout.
     */
    inline operator const ValueTypeCast&() const { return _p->value(FutureTimeout_Infinite); }

    /** Wait for future to contain a value or an error
     @param msecs: Maximum time to wait in milliseconds, 0 means forever and -1 means return immediately.
     @return true if future contains a value or an error, false if timeout was reached
     */
    inline FutureState wait(int msecs = FutureTimeout_Infinite) const          { return _p->wait(msecs); }

    /**
     * @brief isFinished
     * @return true if finished
     * do not throw
     */
    inline bool isFinished() const                                             { return _p->isFinished(); }

    /**
     * @brief isRunning
     * @return
     * do not throw
     */
    inline bool isRunning() const                                              { return _p->isRunning(); }

    /**
     * @brief isCanceled
     * @return
     * do not throw
     */
    inline bool isCanceled() const                                             { return _p->isCanceled(); }

    /**
     * @brief hasError
     * @param msecs timeout
     * @return true if the future has an error.
     * throw in the following case:
     *   - timeout
     */
    inline bool hasError(int msecs = FutureTimeout_Infinite) const             { return _p->hasError(msecs); }
    /**
     * @brief hasValue
     * @param msecs timeout
     * @return
     * true if the future has a value.
     * throw in the following case:
     *   - timeout
     */
    inline bool hasValue(int msecs = FutureTimeout_Infinite) const             { return _p->hasValue(msecs); }

    /**
     * @brief error
     * @param msecs
     * @return the error
     * throw on timeout
     * throw if the future do not have an actual error.
     */
    inline const std::string &error(int msecs = FutureTimeout_Infinite) const  { return _p->error(msecs); }

    inline FutureSync<T> sync()
    {
      return FutureSync<T>(*this);
    };

    /** cancel() the asynchronous operation if possible
    * Exact effect is controlled by the cancel implementation, but it is
    * expected to set a value or an error to the Future as fast as possible.
    * Note that cancelation may be asynchronous.
    * @throw ExceptionState_FutureNotCancelable if isCanceleable() is false.
    */
    void cancel()
    {
      _p->cancel();
    }

    /** return true if the future can be canceled. This does not mean that cancel will succeed.
     */
    bool isCanceleable() const
    {
      return _p->isCanceleable();
    }
  public: //Signals
    typedef boost::function<void (Future<T>) > Connection;
    inline void connect(const Connection& s) { _p->connect(*this, s);}

    // Our companion library libqitype requires a connect with same signature for all instantiations
    inline void _connect(const boost::function<void()>& s) { connect(boost::bind(s));}

  protected:
    // C4251 needs to have dll-interface to be used by clients of class 'qi::Future<T>'
    boost::shared_ptr< detail::FutureBaseTyped<T> > _p;
    friend class Promise<T>;
    friend class FutureSync<T>;
  };

  /** this class allow throwing on error and being synchronous
   *  when the future is not handled by the client.
   */
  template<typename T>
  class FutureSync
  {
  public:
    typedef typename Future<T>::ValueType ValueType;
    typedef typename Future<T>::ValueTypeCast ValueTypeCast;
    typedef typename Future<T>::Connection Connection;
    // This future cannot be set, so sync starts at false
    FutureSync() : _sync(false) {}

    FutureSync(const Future<T>& b)
    : _sync(true)
    {
      _future = b;
    }

    FutureSync(const FutureSync<T>& b)
    : _sync(true)
    {
      _future = b._future;
      b._sync = false;
    }

    explicit FutureSync<T>(const ValueType& v)
    : _sync(false)
    {
      Promise<T> promise;
      promise.setValue(v);
      _future = promise.future();
    }

    inline FutureSync<T>& operator=(const FutureSync<T>& b)
    {
      _future = b;
      _sync = true;
      b._sync = false;
      return *this;
    }

    inline FutureSync<T>& operator=(const Future<T>& b)
    {
      _future = b;
      _sync = true;
      return *this;
    }

    ~FutureSync()
    {
      if (_sync)
        _future.value();
    }

    operator Future<T>()
    {
      return async();
    }

    bool operator < (const FutureSync<T>& b) const
    {
      return _future._p.get() < b._future._p.get();
    }

    inline const ValueType &value() const                            { _sync = false; return _future.value(); }
    inline operator const typename Future<T>::ValueTypeCast&() const { _sync = false; return _future.value(); }
    inline FutureState wait(int msecs = FutureTimeout_Infinite) const { _sync = false; return _future.wait(msecs); }
    inline bool isRunning() const                                     { _sync = false; return _future.isRunning(); }
    inline bool isFinished() const                                    { _sync = false; return _future.isFinished(); }
    inline bool isCanceled() const                                    { _sync = false; return _future.isCanceled(); }
    inline bool hasError(int msecs = FutureTimeout_Infinite) const    { _sync = false; return _future.hasError(msecs); }
    inline bool hasValue(int msecs = FutureTimeout_Infinite) const    { _sync = false; return _future.hasValue(msecs); }

    inline const std::string &error() const                 { _sync = false; return _future.error(); }
    inline void cancel()                                    { _sync = false; _future.cancel(); }
    inline bool isCanceleable() const                       { _sync = false; return _future.isCanceleable(); }
    inline void connect(const Connection& s)                { _sync = false; _future.connect(s);}
    inline void _connect(const boost::function<void()>& s)  { _sync = false; _future._connect(s);}

    Future<T> async()
    {
      _sync = false;
      return _future;
    }

  protected:
    mutable bool _sync;
    Future<T> _future;
    friend class Future<T>;
  };

  template <typename T>
  class Promise {
  public:
    typedef typename FutureType<T>::type ValueType;

    Promise() {
      _f._p->reportStart();
    }

    /** Create a canceleable promise. If Future<T>::cancel is invoked,
     * onCancel() will be called. It is expected to call setValue(),
     * setError() or setCanceled() as quickly as possible, but can do so
     * in an asynchronous way.
     */
    Promise(boost::function<void (qi::Promise<T>)> cancelCallback)
    {
      _f._p->reportStart();
      _f._p->setOnCancel(boost::bind<void>(cancelCallback, *this));
    }

    /** notify all future that a value has been set.
     *  throw if state != running
     */
    void setValue(const ValueType &value) {
      _f._p->setValue(_f, value);
    }

    /** set the error, and notify all futures
     *  throw if state != running
     */
    void setError(const std::string &msg) {
      _f._p->setError(_f, msg);
    }

    /** set the cancel state, and notify all futures
     *  throw if state != running
     */
    void setCanceled() {
      _f._p->setCanceled(_f);
    }

    /* reset the promise and the future */
    void reset() {
      _f._p->reset();
    }

    /* get the future from the promise, you can call this function many times. */
    Future<T> future() { return _f; }

    /** Gives access to the underlying value for in-place modification.
     *  trigger() must be called after the value is written to trigger the promise.
    */
    ValueType& value() { return _f._p->_value;}
    /** Trigger the promise with the current value.
    */
    void trigger() { _f._p->set(_f);}
  protected:
    Future<T> _f;
  };

  template<typename T>
  class FutureBarrier {
  public:
    /// FutureBarrier constructor taking no argument.
    FutureBarrier()
      : _closed(false)
      , _count(0)
      , _futures()
      , _promise()
    {}

    /// Adds the future to the barrier.
    bool addFuture(qi::Future<T> fut) {
      // Can't add future from closed qi::FutureBarrier.
      if (this->_closed)
        return false;

      ++(this->_count);
      fut.connect(boost::bind<void>(&FutureBarrier::onFutureFinish, this));
      this->_futures.push_back(fut);
      return true;
    }

    /// Gets the future result for the barrier.
    Future< std::vector< Future<T> > > future() {
      this->close();
      return this->_promise.future();
    }

  protected:
    bool _closed;
    Atomic<int> _count;
    std::vector< Future<T> > _futures;
    Promise< std::vector< Future<T> > > _promise;

  private:
    void onFutureFinish() {
      if (--(this->_count) == 0 && this->_closed) {
        this->_promise.setValue(this->_futures);
      }
    }

    void close() {
      this->_closed = true;
      if (*(this->_count) == 0) {
        this->_promise.setValue(this->_futures);
      }
    }
  };

  template <typename T>
  qi::Future<T> makeFutureError(const std::string &value);

  /// Helper function to wait on a vector of futures.
  template <typename T>
  void waitForAll(std::vector< Future<T> >& vect);

  /// Helper function to wait for the first valid future.
  template <typename T>
  qi::FutureSync< qi::Future<T> > waitForFirst(std::vector< Future<T> >& vect);

  /// Specialize this struct to provide conversion between future values
  template<typename FT, typename PT>
  struct FutureValueConverter
  {
    void operator()(const FT& vIn, PT& vOut) { vOut = vIn;}
  };

  /** Feed a promise from a future of possibly different type.
   * Will monitor \p f, and bounce its state to \p p.
   * Error and canceled state are bounced as is.
   * Valued state is bounced through FutureValueConverter<FT, PT>::convert()
   */
  template<typename FT, typename PT>
  void adaptFuture(const Future<FT>& f, Promise<PT>& p);

  /// Similar to adaptFuture(f, p) but with a custom converter
  template<typename FT, typename PT, typename CONV>
  void adaptFuture(const Future<FT>& f, Promise<PT>& p, CONV converter);
}

#ifdef _MSC_VER
#  pragma warning( pop )
#endif

#include <qi/details/future.hxx>

#endif  // _QITYPE_FUTURE_HPP_
<commit_msg>FutureSync: remove inline, fix value and error. (default args)<commit_after>#pragma once
/*
**  Copyright (C) 2012 Aldebaran Robotics
**  See COPYING for the license
*/

#ifndef _QITYPE_FUTURE_HPP_
#define _QITYPE_FUTURE_HPP_

#include <qi/api.hpp>
#include <vector>
#include <qi/atomic.hpp>
#include <qi/config.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <boost/thread/recursive_mutex.hpp>

#ifdef _MSC_VER
#  pragma warning( push )
#  pragma warning( disable: 4251 )
#  pragma warning( disable: 4275 ) //std::runtime_error: no dll interface
#endif

namespace qi {

  template<typename T>
  struct FutureType
  {
    typedef T type;
    typedef T typecast;
  };

  struct FutureHasNoValue {};
  // Hold a void* for Future<void>
  template<>
  struct FutureType<void>
  {
    typedef void* type;
    typedef FutureHasNoValue typecast;
  };

  template <typename T> class FutureInterface;
  template <typename T> class Future;
  template <typename T> class FutureSync;
  template <typename T> class Promise;

  namespace detail {
    template <typename T> class FutureBaseTyped;
  }

  /** State of the future.
   */
  enum FutureState {
    FutureState_None,               /// Future is not tied to a promise
    FutureState_Running,            /// Operation pending
    FutureState_Canceled,           /// The future has been canceled
    FutureState_FinishedWithError,  /// The operation is finished with an error
    FutureState_FinishedWithValue,  /// The operation is finished with a value
  };

  enum FutureTimeout {
    FutureTimeout_Infinite = ((int) 0x7fffffff),
    FutureTimeout_None     = 0,
  };

  /** base exception raised for all future error.
   */
  class QI_API FutureException : public std::runtime_error {
  public:
    enum ExceptionState {
      //No result ready
      ExceptionState_FutureTimeout,
      //The future has been canceled
      ExceptionState_FutureCanceled,
      //The future is not cancelable
      ExceptionState_FutureNotCancelable,
      //asked for error, but there is no error
      ExceptionState_FutureHasNoError,
      //real future error
      ExceptionState_FutureUserError,
      //when the promise is already set.
      ExceptionState_PromiseAlreadySet,
    };

    explicit FutureException(const ExceptionState &es, const std::string &str = std::string())
      : std::runtime_error(stateToString(es) + str)
      , _state(es)
    {}

    inline ExceptionState state() const { return _state; }

    std::string stateToString(const ExceptionState &es);

    virtual ~FutureException() throw()
    {}

  private:
    ExceptionState _state;
  };

  /** Exception inherited from FutureException
   *  This exception represent an error reported by the operation.
   */
  class QI_API FutureUserException : public FutureException {
  public:

    explicit FutureUserException(const std::string &str = std::string())
      : FutureException(ExceptionState_FutureUserError, str)
    {}

    virtual ~FutureUserException() throw()
    {}
  };

  template <typename T>
  class Future {
  public:
    typedef typename FutureType<T>::type     ValueType;
    typedef typename FutureType<T>::typecast ValueTypeCast;

  public:
    Future()
      : _p(boost::make_shared<detail::FutureBaseTyped<T> >())
    {
    }

    Future(const Future<T>& b)
    : _p(b._p)
    {}

    bool operator==(const Future<T> &other)
    {
      return _p.get() == other._p.get();
    }

    inline Future<T>& operator=(const Future<T>& b)
    {
      _p = b._p;
      return *this;
    }

    bool operator < (const Future<T>& b) const
    {
      return _p.get() < b._p.get();
    }
    explicit Future<T>(const ValueType& v)
    {
      Promise<T> promise;
      promise.setValue(v);
      *this = promise.future();
    }

    /**
     * @brief Return the value associated to a Future.
     * @param msecs timeout
     * @return the value
     *
     * This function can throw for many reason:
     *   - wait timeout
     *   - user error
     *   - future canceled
     *
     * if an error is set, then value throw a FutureUserException, others errors are FutureException.
     */
    inline const ValueType &value(int msecs = FutureTimeout_Infinite) const { return _p->value(msecs); }

    /** same as value() with an infinite timeout.
     */
    inline operator const ValueTypeCast&() const { return _p->value(FutureTimeout_Infinite); }

    /** Wait for future to contain a value or an error
     @param msecs: Maximum time to wait in milliseconds, 0 means forever and -1 means return immediately.
     @return true if future contains a value or an error, false if timeout was reached
     */
    inline FutureState wait(int msecs = FutureTimeout_Infinite) const          { return _p->wait(msecs); }

    /**
     * @brief isFinished
     * @return true if finished
     * do not throw
     */
    inline bool isFinished() const                                             { return _p->isFinished(); }

    /**
     * @brief isRunning
     * @return
     * do not throw
     */
    inline bool isRunning() const                                              { return _p->isRunning(); }

    /**
     * @brief isCanceled
     * @return
     * do not throw
     */
    inline bool isCanceled() const                                             { return _p->isCanceled(); }

    /**
     * @brief hasError
     * @param msecs timeout
     * @return true if the future has an error.
     * throw in the following case:
     *   - timeout
     */
    inline bool hasError(int msecs = FutureTimeout_Infinite) const             { return _p->hasError(msecs); }
    /**
     * @brief hasValue
     * @param msecs timeout
     * @return
     * true if the future has a value.
     * throw in the following case:
     *   - timeout
     */
    inline bool hasValue(int msecs = FutureTimeout_Infinite) const             { return _p->hasValue(msecs); }

    /**
     * @brief error
     * @param msecs
     * @return the error
     * throw on timeout
     * throw if the future do not have an actual error.
     */
    inline const std::string &error(int msecs = FutureTimeout_Infinite) const  { return _p->error(msecs); }

    inline FutureSync<T> sync()
    {
      return FutureSync<T>(*this);
    };

    /** cancel() the asynchronous operation if possible
    * Exact effect is controlled by the cancel implementation, but it is
    * expected to set a value or an error to the Future as fast as possible.
    * Note that cancelation may be asynchronous.
    * @throw ExceptionState_FutureNotCancelable if isCanceleable() is false.
    */
    void cancel()
    {
      _p->cancel();
    }

    /** return true if the future can be canceled. This does not mean that cancel will succeed.
     */
    bool isCanceleable() const
    {
      return _p->isCanceleable();
    }
  public: //Signals
    typedef boost::function<void (Future<T>) > Connection;
    inline void connect(const Connection& s) { _p->connect(*this, s);}

    // Our companion library libqitype requires a connect with same signature for all instantiations
    inline void _connect(const boost::function<void()>& s) { connect(boost::bind(s));}

  protected:
    // C4251 needs to have dll-interface to be used by clients of class 'qi::Future<T>'
    boost::shared_ptr< detail::FutureBaseTyped<T> > _p;
    friend class Promise<T>;
    friend class FutureSync<T>;
  };

  /** this class allow throwing on error and being synchronous
   *  when the future is not handled by the client.
   */
  template<typename T>
  class FutureSync
  {
  public:
    typedef typename Future<T>::ValueType ValueType;
    typedef typename Future<T>::ValueTypeCast ValueTypeCast;
    typedef typename Future<T>::Connection Connection;
    // This future cannot be set, so sync starts at false
    FutureSync() : _sync(false) {}

    FutureSync(const Future<T>& b)
    : _sync(true)
    {
      _future = b;
    }

    FutureSync(const FutureSync<T>& b)
    : _sync(true)
    {
      _future = b._future;
      b._sync = false;
    }

    explicit FutureSync<T>(const ValueType& v)
    : _sync(false)
    {
      Promise<T> promise;
      promise.setValue(v);
      _future = promise.future();
    }

    inline FutureSync<T>& operator=(const FutureSync<T>& b)
    {
      _future = b;
      _sync = true;
      b._sync = false;
      return *this;
    }

    inline FutureSync<T>& operator=(const Future<T>& b)
    {
      _future = b;
      _sync = true;
      return *this;
    }

    ~FutureSync()
    {
      if (_sync)
        _future.value();
    }

    operator Future<T>()
    {
      return async();
    }

    bool operator < (const FutureSync<T>& b) const
    {
      return _future._p.get() < b._future._p.get();
    }

    const ValueType &value(int msecs = FutureTimeout_Infinite) const   { _sync = false; return _future.value(msecs); }
    operator const typename Future<T>::ValueTypeCast&() const          { _sync = false; return _future.value(); }
    FutureState wait(int msecs = FutureTimeout_Infinite) const         { _sync = false; return _future.wait(msecs); }
    bool isRunning() const                                             { _sync = false; return _future.isRunning(); }
    bool isFinished() const                                            { _sync = false; return _future.isFinished(); }
    bool isCanceled() const                                            { _sync = false; return _future.isCanceled(); }
    bool hasError(int msecs = FutureTimeout_Infinite) const            { _sync = false; return _future.hasError(msecs); }
    bool hasValue(int msecs = FutureTimeout_Infinite) const            { _sync = false; return _future.hasValue(msecs); }
    const std::string &error(int msecs = FutureTimeout_Infinite) const { _sync = false; return _future.error(msecs); }
    void cancel()                                                      { _sync = false; _future.cancel(); }
    bool isCanceleable() const                                         { _sync = false; return _future.isCanceleable(); }
    void connect(const Connection& s)                                  { _sync = false; _future.connect(s);}
    void _connect(const boost::function<void()>& s)                    { _sync = false; _future._connect(s);}

    Future<T> async()
    {
      _sync = false;
      return _future;
    }

  protected:
    mutable bool _sync;
    Future<T> _future;
    friend class Future<T>;
  };

  template <typename T>
  class Promise {
  public:
    typedef typename FutureType<T>::type ValueType;

    Promise() {
      _f._p->reportStart();
    }

    /** Create a canceleable promise. If Future<T>::cancel is invoked,
     * onCancel() will be called. It is expected to call setValue(),
     * setError() or setCanceled() as quickly as possible, but can do so
     * in an asynchronous way.
     */
    Promise(boost::function<void (qi::Promise<T>)> cancelCallback)
    {
      _f._p->reportStart();
      _f._p->setOnCancel(boost::bind<void>(cancelCallback, *this));
    }

    /** notify all future that a value has been set.
     *  throw if state != running
     */
    void setValue(const ValueType &value) {
      _f._p->setValue(_f, value);
    }

    /** set the error, and notify all futures
     *  throw if state != running
     */
    void setError(const std::string &msg) {
      _f._p->setError(_f, msg);
    }

    /** set the cancel state, and notify all futures
     *  throw if state != running
     */
    void setCanceled() {
      _f._p->setCanceled(_f);
    }

    /* reset the promise and the future */
    void reset() {
      _f._p->reset();
    }

    /* get the future from the promise, you can call this function many times. */
    Future<T> future() { return _f; }

    /** Gives access to the underlying value for in-place modification.
     *  trigger() must be called after the value is written to trigger the promise.
    */
    ValueType& value() { return _f._p->_value;}
    /** Trigger the promise with the current value.
    */
    void trigger() { _f._p->set(_f);}
  protected:
    Future<T> _f;
  };

  template<typename T>
  class FutureBarrier {
  public:
    /// FutureBarrier constructor taking no argument.
    FutureBarrier()
      : _closed(false)
      , _count(0)
      , _futures()
      , _promise()
    {}

    /// Adds the future to the barrier.
    bool addFuture(qi::Future<T> fut) {
      // Can't add future from closed qi::FutureBarrier.
      if (this->_closed)
        return false;

      ++(this->_count);
      fut.connect(boost::bind<void>(&FutureBarrier::onFutureFinish, this));
      this->_futures.push_back(fut);
      return true;
    }

    /// Gets the future result for the barrier.
    Future< std::vector< Future<T> > > future() {
      this->close();
      return this->_promise.future();
    }

  protected:
    bool _closed;
    Atomic<int> _count;
    std::vector< Future<T> > _futures;
    Promise< std::vector< Future<T> > > _promise;

  private:
    void onFutureFinish() {
      if (--(this->_count) == 0 && this->_closed) {
        this->_promise.setValue(this->_futures);
      }
    }

    void close() {
      this->_closed = true;
      if (*(this->_count) == 0) {
        this->_promise.setValue(this->_futures);
      }
    }
  };

  template <typename T>
  qi::Future<T> makeFutureError(const std::string &value);

  /// Helper function to wait on a vector of futures.
  template <typename T>
  void waitForAll(std::vector< Future<T> >& vect);

  /// Helper function to wait for the first valid future.
  template <typename T>
  qi::FutureSync< qi::Future<T> > waitForFirst(std::vector< Future<T> >& vect);

  /// Specialize this struct to provide conversion between future values
  template<typename FT, typename PT>
  struct FutureValueConverter
  {
    void operator()(const FT& vIn, PT& vOut) { vOut = vIn;}
  };

  /** Feed a promise from a future of possibly different type.
   * Will monitor \p f, and bounce its state to \p p.
   * Error and canceled state are bounced as is.
   * Valued state is bounced through FutureValueConverter<FT, PT>::convert()
   */
  template<typename FT, typename PT>
  void adaptFuture(const Future<FT>& f, Promise<PT>& p);

  /// Similar to adaptFuture(f, p) but with a custom converter
  template<typename FT, typename PT, typename CONV>
  void adaptFuture(const Future<FT>& f, Promise<PT>& p, CONV converter);
}

#ifdef _MSC_VER
#  pragma warning( pop )
#endif

#include <qi/details/future.hxx>

#endif  // _QITYPE_FUTURE_HPP_
<|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/views/ime/input_method_bridge.h"

#include "ui/base/ime/input_method.h"
#include "ui/base/ime/input_method_observer.h"
#include "ui/events/event.h"
#include "ui/gfx/rect.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"

namespace views {

// InputMethodBridge::HostObserver class ---------------------------------------

// An observer class for observing the host input method. When the host input
// method is destroyed, it will null out the |host_| field on the
// InputMethodBridge object.
class InputMethodBridge::HostObserver : public ui::InputMethodObserver {
 public:
  explicit HostObserver(InputMethodBridge* bridge);
  virtual ~HostObserver();

  virtual void OnTextInputTypeChanged(
      const ui::TextInputClient* client) OVERRIDE {}
  virtual void OnFocus() OVERRIDE {}
  virtual void OnBlur() OVERRIDE {}
  virtual void OnCaretBoundsChanged(
      const ui::TextInputClient* client) OVERRIDE {}
  virtual void OnTextInputStateChanged(
      const ui::TextInputClient* client) OVERRIDE {}
  virtual void OnInputMethodDestroyed(
      const ui::InputMethod* input_method) OVERRIDE;

 private:
  InputMethodBridge* bridge_;

  DISALLOW_COPY_AND_ASSIGN(HostObserver);
};

InputMethodBridge::HostObserver::HostObserver(InputMethodBridge* bridge)
    : bridge_(bridge) {
  bridge_->host_->AddObserver(this);
}

InputMethodBridge::HostObserver::~HostObserver() {
  if (bridge_->host_)
    bridge_->host_->RemoveObserver(this);
}

void InputMethodBridge::HostObserver::OnInputMethodDestroyed(
    const ui::InputMethod* input_method) {
  DCHECK_EQ(bridge_->host_, input_method);
  bridge_->host_->RemoveObserver(this);
  bridge_->host_ = NULL;
}

// InputMethodBridge class -----------------------------------------------------

InputMethodBridge::InputMethodBridge(internal::InputMethodDelegate* delegate,
                                     ui::InputMethod* host,
                                     bool shared_input_method)
    : host_(host),
      shared_input_method_(shared_input_method) {
  DCHECK(host_);
  SetDelegate(delegate);

  host_observer_.reset(new HostObserver(this));
}

InputMethodBridge::~InputMethodBridge() {
  // By the time we get here it's very likely |widget_|'s NativeWidget has been
  // destroyed. This means any calls to |widget_| that go to the NativeWidget,
  // such as IsActive(), will crash. SetFocusedTextInputClient() may callback to
  // this and go into |widget_|. NULL out |widget_| so we don't attempt to use
  // it.
  DetachFromWidget();

  // Host input method might have been destroyed at this point.
  if (host_)
    host_->DetachTextInputClient(this);
}

void InputMethodBridge::OnFocus() {
  DCHECK(host_);

  // Direct the shared IME to send TextInputClient messages to |this| object.
  if (shared_input_method_ || !host_->GetTextInputClient())
    host_->SetFocusedTextInputClient(this);

  // TODO(yusukes): We don't need to call OnTextInputTypeChanged() once we move
  // text input type tracker code to ui::InputMethodBase.
  if (GetFocusedView())
    OnTextInputTypeChanged(GetFocusedView());
}

void InputMethodBridge::OnBlur() {
  DCHECK(host_);

  if (HasCompositionText()) {
    ConfirmCompositionText();
    host_->CancelComposition(this);
  }

  if (host_->GetTextInputClient() == this)
    host_->SetFocusedTextInputClient(NULL);
}

bool InputMethodBridge::OnUntranslatedIMEMessage(const base::NativeEvent& event,
                                                 NativeEventResult* result) {
  DCHECK(host_);

  return host_->OnUntranslatedIMEMessage(event, result);
}

void InputMethodBridge::DispatchKeyEvent(const ui::KeyEvent& key) {
  DCHECK(key.type() == ui::ET_KEY_PRESSED || key.type() == ui::ET_KEY_RELEASED);

  // We can just dispatch the event here since the |key| is already processed by
  // the system-wide IME.
  DispatchKeyEventPostIME(key);
}

void InputMethodBridge::OnTextInputTypeChanged(View* view) {
  DCHECK(host_);

  if (IsViewFocused(view))
    host_->OnTextInputTypeChanged(this);
  InputMethodBase::OnTextInputTypeChanged(view);
}

void InputMethodBridge::OnCaretBoundsChanged(View* view) {
  DCHECK(host_);

  if (IsViewFocused(view) && !IsTextInputTypeNone())
    host_->OnCaretBoundsChanged(this);
}

void InputMethodBridge::CancelComposition(View* view) {
  DCHECK(host_);

  if (IsViewFocused(view))
    host_->CancelComposition(this);
}

void InputMethodBridge::OnInputLocaleChanged() {
  DCHECK(host_);

  host_->OnInputLocaleChanged();
}

std::string InputMethodBridge::GetInputLocale() {
  DCHECK(host_);

  return host_->GetInputLocale();
}

base::i18n::TextDirection InputMethodBridge::GetInputTextDirection() {
  DCHECK(host_);

  return host_->GetInputTextDirection();
}

bool InputMethodBridge::IsActive() {
  DCHECK(host_);

  return host_->IsActive();
}

bool InputMethodBridge::IsCandidatePopupOpen() const {
  DCHECK(host_);

  return host_->IsCandidatePopupOpen();
}

// Overridden from TextInputClient. Forward an event from the system-wide IME
// to the text input |client|, which is e.g. views::NativeTextfieldViews.
void InputMethodBridge::SetCompositionText(
    const ui::CompositionText& composition) {
  TextInputClient* client = GetTextInputClient();
  if (client)
    client->SetCompositionText(composition);
}

void InputMethodBridge::ConfirmCompositionText() {
  TextInputClient* client = GetTextInputClient();
  if (client)
    client->ConfirmCompositionText();
}

void InputMethodBridge::ClearCompositionText() {
  TextInputClient* client = GetTextInputClient();
  if (client)
    client->ClearCompositionText();
}

void InputMethodBridge::InsertText(const string16& text) {
  TextInputClient* client = GetTextInputClient();
  if (client)
    client->InsertText(text);
}

void InputMethodBridge::InsertChar(char16 ch, int flags) {
  TextInputClient* client = GetTextInputClient();
  if (client)
    client->InsertChar(ch, flags);
}

gfx::NativeWindow InputMethodBridge::GetAttachedWindow() const {
  TextInputClient* client = GetTextInputClient();
  return client ?
      client->GetAttachedWindow() : static_cast<gfx::NativeWindow>(NULL);
}

ui::TextInputType InputMethodBridge::GetTextInputType() const {
  TextInputClient* client = GetTextInputClient();
  return client ? client->GetTextInputType() : ui::TEXT_INPUT_TYPE_NONE;
}

ui::TextInputMode InputMethodBridge::GetTextInputMode() const {
  TextInputClient* client = GetTextInputClient();
  return client ? client->GetTextInputMode() : ui::TEXT_INPUT_MODE_DEFAULT;
}

bool InputMethodBridge::CanComposeInline() const {
  TextInputClient* client = GetTextInputClient();
  return client ? client->CanComposeInline() : true;
}

gfx::Rect InputMethodBridge::GetCaretBounds() const {
  TextInputClient* client = GetTextInputClient();
  if (!client)
    return gfx::Rect();

  return client->GetCaretBounds();
}

bool InputMethodBridge::GetCompositionCharacterBounds(uint32 index,
                                                      gfx::Rect* rect) const {
  DCHECK(rect);
  TextInputClient* client = GetTextInputClient();
  if (!client)
    return false;

  return client->GetCompositionCharacterBounds(index, rect);
}

bool InputMethodBridge::HasCompositionText() const {
  TextInputClient* client = GetTextInputClient();
  return client ? client->HasCompositionText() : false;
}

bool InputMethodBridge::GetTextRange(gfx::Range* range) const {
  TextInputClient* client = GetTextInputClient();
  return client ?  client->GetTextRange(range) : false;
}

bool InputMethodBridge::GetCompositionTextRange(gfx::Range* range) const {
  TextInputClient* client = GetTextInputClient();
  return client ? client->GetCompositionTextRange(range) : false;
}

bool InputMethodBridge::GetSelectionRange(gfx::Range* range) const {
  TextInputClient* client = GetTextInputClient();
  return client ? client->GetSelectionRange(range) : false;
}

bool InputMethodBridge::SetSelectionRange(const gfx::Range& range) {
  TextInputClient* client = GetTextInputClient();
  return client ? client->SetSelectionRange(range) : false;
}

bool InputMethodBridge::DeleteRange(const gfx::Range& range) {
  TextInputClient* client = GetTextInputClient();
  return client ? client->DeleteRange(range) : false;
}

bool InputMethodBridge::GetTextFromRange(const gfx::Range& range,
                                         string16* text) const {
  TextInputClient* client = GetTextInputClient();
  return client ? client->GetTextFromRange(range, text) : false;
}

void InputMethodBridge::OnInputMethodChanged() {
  TextInputClient* client = GetTextInputClient();
  if (client)
    client->OnInputMethodChanged();
}

bool InputMethodBridge::ChangeTextDirectionAndLayoutAlignment(
    base::i18n::TextDirection direction) {
  TextInputClient* client = GetTextInputClient();
  return client ?
      client->ChangeTextDirectionAndLayoutAlignment(direction) : false;
}

void InputMethodBridge::ExtendSelectionAndDelete(size_t before, size_t after) {
  TextInputClient* client = GetTextInputClient();
  if (client)
    client->ExtendSelectionAndDelete(before, after);
}

void InputMethodBridge::EnsureCaretInRect(const gfx::Rect& rect) {
  TextInputClient* client = GetTextInputClient();
  if (client)
    client->EnsureCaretInRect(rect);
}

void InputMethodBridge::OnCandidateWindowShown() {
}

void InputMethodBridge::OnCandidateWindowUpdated() {
}

void InputMethodBridge::OnCandidateWindowHidden() {
}

// Overridden from FocusChangeListener.
void InputMethodBridge::OnWillChangeFocus(View* focused_before, View* focused) {
  if (HasCompositionText()) {
    ConfirmCompositionText();
    CancelComposition(focused_before);
  }
}

void InputMethodBridge::OnDidChangeFocus(View* focused_before, View* focused) {
  DCHECK_EQ(GetFocusedView(), focused);
  OnTextInputTypeChanged(focused);
  OnCaretBoundsChanged(focused);
}

ui::InputMethod* InputMethodBridge::GetHostInputMethod() const {
  return host_;
}

}  // namespace views
<commit_msg>Call OnCaretBoundsChanged in InputMethodBridge::OnFocus<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/views/ime/input_method_bridge.h"

#include "ui/base/ime/input_method.h"
#include "ui/base/ime/input_method_observer.h"
#include "ui/events/event.h"
#include "ui/gfx/rect.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"

namespace views {

// InputMethodBridge::HostObserver class ---------------------------------------

// An observer class for observing the host input method. When the host input
// method is destroyed, it will null out the |host_| field on the
// InputMethodBridge object.
class InputMethodBridge::HostObserver : public ui::InputMethodObserver {
 public:
  explicit HostObserver(InputMethodBridge* bridge);
  virtual ~HostObserver();

  virtual void OnTextInputTypeChanged(
      const ui::TextInputClient* client) OVERRIDE {}
  virtual void OnFocus() OVERRIDE {}
  virtual void OnBlur() OVERRIDE {}
  virtual void OnCaretBoundsChanged(
      const ui::TextInputClient* client) OVERRIDE {}
  virtual void OnTextInputStateChanged(
      const ui::TextInputClient* client) OVERRIDE {}
  virtual void OnInputMethodDestroyed(
      const ui::InputMethod* input_method) OVERRIDE;

 private:
  InputMethodBridge* bridge_;

  DISALLOW_COPY_AND_ASSIGN(HostObserver);
};

InputMethodBridge::HostObserver::HostObserver(InputMethodBridge* bridge)
    : bridge_(bridge) {
  bridge_->host_->AddObserver(this);
}

InputMethodBridge::HostObserver::~HostObserver() {
  if (bridge_->host_)
    bridge_->host_->RemoveObserver(this);
}

void InputMethodBridge::HostObserver::OnInputMethodDestroyed(
    const ui::InputMethod* input_method) {
  DCHECK_EQ(bridge_->host_, input_method);
  bridge_->host_->RemoveObserver(this);
  bridge_->host_ = NULL;
}

// InputMethodBridge class -----------------------------------------------------

InputMethodBridge::InputMethodBridge(internal::InputMethodDelegate* delegate,
                                     ui::InputMethod* host,
                                     bool shared_input_method)
    : host_(host),
      shared_input_method_(shared_input_method) {
  DCHECK(host_);
  SetDelegate(delegate);

  host_observer_.reset(new HostObserver(this));
}

InputMethodBridge::~InputMethodBridge() {
  // By the time we get here it's very likely |widget_|'s NativeWidget has been
  // destroyed. This means any calls to |widget_| that go to the NativeWidget,
  // such as IsActive(), will crash. SetFocusedTextInputClient() may callback to
  // this and go into |widget_|. NULL out |widget_| so we don't attempt to use
  // it.
  DetachFromWidget();

  // Host input method might have been destroyed at this point.
  if (host_)
    host_->DetachTextInputClient(this);
}

void InputMethodBridge::OnFocus() {
  DCHECK(host_);

  // Direct the shared IME to send TextInputClient messages to |this| object.
  if (shared_input_method_ || !host_->GetTextInputClient())
    host_->SetFocusedTextInputClient(this);

  // TODO(yusukes): We don't need to call OnTextInputTypeChanged() once we move
  // text input type tracker code to ui::InputMethodBase.
  if (GetFocusedView()) {
    OnTextInputTypeChanged(GetFocusedView());
    OnCaretBoundsChanged(GetFocusedView());
  }
}

void InputMethodBridge::OnBlur() {
  DCHECK(host_);

  if (HasCompositionText()) {
    ConfirmCompositionText();
    host_->CancelComposition(this);
  }

  if (host_->GetTextInputClient() == this)
    host_->SetFocusedTextInputClient(NULL);
}

bool InputMethodBridge::OnUntranslatedIMEMessage(const base::NativeEvent& event,
                                                 NativeEventResult* result) {
  DCHECK(host_);

  return host_->OnUntranslatedIMEMessage(event, result);
}

void InputMethodBridge::DispatchKeyEvent(const ui::KeyEvent& key) {
  DCHECK(key.type() == ui::ET_KEY_PRESSED || key.type() == ui::ET_KEY_RELEASED);

  // We can just dispatch the event here since the |key| is already processed by
  // the system-wide IME.
  DispatchKeyEventPostIME(key);
}

void InputMethodBridge::OnTextInputTypeChanged(View* view) {
  DCHECK(host_);

  if (IsViewFocused(view))
    host_->OnTextInputTypeChanged(this);
  InputMethodBase::OnTextInputTypeChanged(view);
}

void InputMethodBridge::OnCaretBoundsChanged(View* view) {
  DCHECK(host_);

  if (IsViewFocused(view) && !IsTextInputTypeNone())
    host_->OnCaretBoundsChanged(this);
}

void InputMethodBridge::CancelComposition(View* view) {
  DCHECK(host_);

  if (IsViewFocused(view))
    host_->CancelComposition(this);
}

void InputMethodBridge::OnInputLocaleChanged() {
  DCHECK(host_);

  host_->OnInputLocaleChanged();
}

std::string InputMethodBridge::GetInputLocale() {
  DCHECK(host_);

  return host_->GetInputLocale();
}

base::i18n::TextDirection InputMethodBridge::GetInputTextDirection() {
  DCHECK(host_);

  return host_->GetInputTextDirection();
}

bool InputMethodBridge::IsActive() {
  DCHECK(host_);

  return host_->IsActive();
}

bool InputMethodBridge::IsCandidatePopupOpen() const {
  DCHECK(host_);

  return host_->IsCandidatePopupOpen();
}

// Overridden from TextInputClient. Forward an event from the system-wide IME
// to the text input |client|, which is e.g. views::NativeTextfieldViews.
void InputMethodBridge::SetCompositionText(
    const ui::CompositionText& composition) {
  TextInputClient* client = GetTextInputClient();
  if (client)
    client->SetCompositionText(composition);
}

void InputMethodBridge::ConfirmCompositionText() {
  TextInputClient* client = GetTextInputClient();
  if (client)
    client->ConfirmCompositionText();
}

void InputMethodBridge::ClearCompositionText() {
  TextInputClient* client = GetTextInputClient();
  if (client)
    client->ClearCompositionText();
}

void InputMethodBridge::InsertText(const string16& text) {
  TextInputClient* client = GetTextInputClient();
  if (client)
    client->InsertText(text);
}

void InputMethodBridge::InsertChar(char16 ch, int flags) {
  TextInputClient* client = GetTextInputClient();
  if (client)
    client->InsertChar(ch, flags);
}

gfx::NativeWindow InputMethodBridge::GetAttachedWindow() const {
  TextInputClient* client = GetTextInputClient();
  return client ?
      client->GetAttachedWindow() : static_cast<gfx::NativeWindow>(NULL);
}

ui::TextInputType InputMethodBridge::GetTextInputType() const {
  TextInputClient* client = GetTextInputClient();
  return client ? client->GetTextInputType() : ui::TEXT_INPUT_TYPE_NONE;
}

ui::TextInputMode InputMethodBridge::GetTextInputMode() const {
  TextInputClient* client = GetTextInputClient();
  return client ? client->GetTextInputMode() : ui::TEXT_INPUT_MODE_DEFAULT;
}

bool InputMethodBridge::CanComposeInline() const {
  TextInputClient* client = GetTextInputClient();
  return client ? client->CanComposeInline() : true;
}

gfx::Rect InputMethodBridge::GetCaretBounds() const {
  TextInputClient* client = GetTextInputClient();
  if (!client)
    return gfx::Rect();

  return client->GetCaretBounds();
}

bool InputMethodBridge::GetCompositionCharacterBounds(uint32 index,
                                                      gfx::Rect* rect) const {
  DCHECK(rect);
  TextInputClient* client = GetTextInputClient();
  if (!client)
    return false;

  return client->GetCompositionCharacterBounds(index, rect);
}

bool InputMethodBridge::HasCompositionText() const {
  TextInputClient* client = GetTextInputClient();
  return client ? client->HasCompositionText() : false;
}

bool InputMethodBridge::GetTextRange(gfx::Range* range) const {
  TextInputClient* client = GetTextInputClient();
  return client ?  client->GetTextRange(range) : false;
}

bool InputMethodBridge::GetCompositionTextRange(gfx::Range* range) const {
  TextInputClient* client = GetTextInputClient();
  return client ? client->GetCompositionTextRange(range) : false;
}

bool InputMethodBridge::GetSelectionRange(gfx::Range* range) const {
  TextInputClient* client = GetTextInputClient();
  return client ? client->GetSelectionRange(range) : false;
}

bool InputMethodBridge::SetSelectionRange(const gfx::Range& range) {
  TextInputClient* client = GetTextInputClient();
  return client ? client->SetSelectionRange(range) : false;
}

bool InputMethodBridge::DeleteRange(const gfx::Range& range) {
  TextInputClient* client = GetTextInputClient();
  return client ? client->DeleteRange(range) : false;
}

bool InputMethodBridge::GetTextFromRange(const gfx::Range& range,
                                         string16* text) const {
  TextInputClient* client = GetTextInputClient();
  return client ? client->GetTextFromRange(range, text) : false;
}

void InputMethodBridge::OnInputMethodChanged() {
  TextInputClient* client = GetTextInputClient();
  if (client)
    client->OnInputMethodChanged();
}

bool InputMethodBridge::ChangeTextDirectionAndLayoutAlignment(
    base::i18n::TextDirection direction) {
  TextInputClient* client = GetTextInputClient();
  return client ?
      client->ChangeTextDirectionAndLayoutAlignment(direction) : false;
}

void InputMethodBridge::ExtendSelectionAndDelete(size_t before, size_t after) {
  TextInputClient* client = GetTextInputClient();
  if (client)
    client->ExtendSelectionAndDelete(before, after);
}

void InputMethodBridge::EnsureCaretInRect(const gfx::Rect& rect) {
  TextInputClient* client = GetTextInputClient();
  if (client)
    client->EnsureCaretInRect(rect);
}

void InputMethodBridge::OnCandidateWindowShown() {
}

void InputMethodBridge::OnCandidateWindowUpdated() {
}

void InputMethodBridge::OnCandidateWindowHidden() {
}

// Overridden from FocusChangeListener.
void InputMethodBridge::OnWillChangeFocus(View* focused_before, View* focused) {
  if (HasCompositionText()) {
    ConfirmCompositionText();
    CancelComposition(focused_before);
  }
}

void InputMethodBridge::OnDidChangeFocus(View* focused_before, View* focused) {
  DCHECK_EQ(GetFocusedView(), focused);
  OnTextInputTypeChanged(focused);
  OnCaretBoundsChanged(focused);
}

ui::InputMethod* InputMethodBridge::GetHostInputMethod() const {
  return host_;
}

}  // namespace views
<|endoftext|>


<commit_before>// Licensed GNU LGPL v3 or later: http://www.gnu.org/licenses/lgpl.html
#include "main.hh"
#include "strings.hh"
#include <string.h>
#include <algorithm>

#include <glib.h>

namespace Rapicorn {

// === initialization hooks ===
static InitHook *init_hooks = NULL;

InitHook::InitHook (const String &fname, InitHookFunc func) :
  next (NULL), hook (func), m_name (fname)
{
  next = init_hooks;
  init_hooks = this;
}

static int
init_hook_cmp (const InitHook *const &v1, const InitHook *const &v2)
{
  static const char *levels[] = { "core/", "threading/", "ui/" };
  uint l1 = UINT_MAX, l2 = UINT_MAX;
  for (uint i = 0; i < RAPICORN_ARRAY_SIZE (levels); i++)
    {
      const uint len = strlen (levels[i]);
      if (l1 == UINT_MAX && strncmp (levels[i], v1->name().c_str(), len) == 0)
        {
          l1 = i;
          if (l2 != UINT_MAX)
            break;
        }
      if (l2 == UINT_MAX && strncmp (levels[i], v2->name().c_str(), len) == 0)
        {
          l2 = i;
          if (l1 != UINT_MAX)
            break;
        }
    }
  if (l1 != l2)
    return l1 < l2 ? -1 : l2 > l1;
  return strverscmp (v1->name().c_str(), v2->name().c_str()) < 0;
}

static StringVector *init_hook_main_args = NULL;

StringVector
InitHook::main_args () const
{
  return *init_hook_main_args;
}

void
InitHook::invoke_hooks (const String &kind, int *argcp, char **argv, const StringVector &args)
{
  std::vector<InitHook*> hv;
  for (InitHook *ihook = init_hooks; ihook; ihook = ihook->next)
    hv.push_back (ihook);
  stable_sort (hv.begin(), hv.end(), init_hook_cmp);
  StringVector main_args;
  for (uint i = 1; i < uint (*argcp); i++)
    main_args.push_back (argv[i]);
  init_hook_main_args = &main_args;
  for (std::vector<InitHook*>::iterator it = hv.begin(); it != hv.end(); it++)
    {
      String name = (*it)->name();
      if (name.size() > kind.size() && strncmp (name.data(), kind.data(), kind.size()) == 0)
        {
          RAPICORN_DEBUG ("InitHook: %s", name.c_str());
          (*it)->hook (args);
        }
    }
  init_hook_main_args = NULL;
}

// === arg parsers ===
/**
 * Try to parse argument @a arg at position @a i in @a argv.
 * If successfull, @a i is incremented and the argument
 * is set to NULL.
 * @returns true if successfull.
 */
bool
arg_parse_option (uint         argc,
                  char       **argv,
                  size_t      *i,
                  const char  *arg)
{
  if (strcmp (argv[*i], arg) == 0)
    {
      argv[*i] = NULL;
      return true;
    }
  return false;
}

/**
 * Try to parse argument @a arg at position @a i in @a argv.
 * If successfull, @a i is incremented and the argument and possibly
 * the next option argument are set to NULL.
 * @returns true if successfull and the string option in @a strp.
 */
bool
arg_parse_string_option (uint         argc,
                         char       **argv,
                         size_t      *i,
                         const char  *arg,
                         const char **strp)
{
  const size_t length = strlen (arg);
  if (strncmp (argv[*i], arg, length) == 0)
    {
      const char *equal = argv[*i] + length;
      if (*equal == '=')                // -x=VAL
        *strp = equal + 1;
      else if (*equal)                  // -xVAL
        *strp = equal;
      else if (*i + 1 < argc)           // -x VAL
        {
          argv[(*i)++] = NULL;
          *strp = argv[*i];
        }
      else
        *strp = NULL;
      argv[*i] = NULL;
      if (*strp)
        return true;
    }
  return false;
}

/**
 * Collapse @a argv by eliminating NULL strings.
 * @returns Number of collapsed arguments.
 */
int
arg_parse_collapse (int   *argcp,
                    char **argv)
{
  // collapse args
  const uint argc = *argcp;
  uint e = 1;
  for (uint i = 1; i < argc; i++)
    if (argv[i])
      {
        argv[e++] = argv[i];
        if (i >= e)
          argv[i] = NULL;
      }
  const int collapsed = *argcp - e;
  *argcp = e;
  return collapsed;
}

static bool
parse_bool_option (const String &s, const char *arg, bool *boolp)
{
  const size_t length = strlen (arg);
  if (s.size() > length && s[length] == '=' && strncmp (&s[0], arg, length) == 0)
    {
      *boolp = string_to_bool (s.substr (length + 1));
      return true;
    }
  return false;
}

// === initialization ===
struct VInitSettings : InitSettings {
  bool& autonomous()    { return m_autonomous; }
  uint& test_codes()    { return m_test_codes; }
  VInitSettings() { m_autonomous = false; m_test_codes = 0; }
} static vsettings;
static VInitSettings vinit_settings;
const InitSettings  *InitSettings::sis = &vinit_settings;

static void
parse_settings_and_args (VInitSettings      &vsettings,
                         const StringVector &args,
                         int                *argcp,
                         char              **argv)
{
  bool b = 0, pta = false;
  // apply init settings
  for (StringVector::const_iterator it = args.begin(); it != args.end(); it++)
    if      (parse_bool_option (*it, "autonomous", &b))
      vsettings.autonomous() = b;
    else if (parse_bool_option (*it, "parse-testargs", &b))
      pta = b;
    else if (parse_bool_option (*it, "test-verbose", &b))
      vsettings.test_codes() |= 0x1;
    else if (parse_bool_option (*it, "test-log", &b))
      vsettings.test_codes() |= 0x2;
    else if (parse_bool_option (*it, "test-slow", &b))
      vsettings.test_codes() |= 0x4;
  // parse command line args
  const size_t argc = *argcp;
  for (size_t i = 1; i < argc; i++)
    {
      if (            arg_parse_option (*argcp, argv, &i, "--g-fatal-warnings"))
        {
          const uint fatal_mask = g_log_set_always_fatal (GLogLevelFlags (G_LOG_FATAL_MASK));
          g_log_set_always_fatal (GLogLevelFlags (fatal_mask | G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL));
        }
      else if (pta && arg_parse_option (*argcp, argv, &i, "--test-verbose"))
        vsettings.test_codes() |= 0x1;
      else if (pta && arg_parse_option (*argcp, argv, &i, "--test-log"))
        vsettings.test_codes() |= 0x2;
      else if (pta && arg_parse_option (*argcp, argv, &i, "--test-slow"))
        vsettings.test_codes() |= 0x4;
      else if (pta && strcmp ("--verbose", argv[i]) == 0)
        {
          vsettings.test_codes() |= 0x1;
          /* interpret --verbose for GLib compat but don't delete the argument
           * since regular non-test programs may need this. could be fixed by
           * having a separate test program argument parser.
           */
        }
    }
  // collapse NULL arguments
  arg_parse_collapse (argcp, argv);
}

static String program_argv0 = "";
static String program_app_ident = "";
static String program_cwd0 = "";

/**
 * File name of the current process as set in argv[0] at startup.
 */
String
program_file ()
{
  return program_argv0;
}

/**
 * The program identifier @a app_ident as specified during initialization of Rapicorn.
 */
String
program_ident ()
{
  return program_app_ident;
}

/**
 * The current working directory during startup.
 */
String
program_cwd ()
{
  return program_cwd0;
}

static struct __StaticCTorTest { int v; __StaticCTorTest() : v (0x12affe16) { v++; } } __staticctortest;

/**
 * @param app_ident     Application identifier, needed to associate persistent resources
 * @param argcp         location of the 'argc' argument to main()
 * @param argv          location of the 'argv' arguments to main()
 * @param args          program specific initialization values
 *
 * Initialize the Rapicorn toolkit, including threading, CPU detection, loading resource libraries, etc.
 * The arguments passed in @a argcp and @a argv are parsed and any Rapicorn specific arguments
 * are stripped.
 * Supported command line arguments are:
 * - @c --test-verbose - execute test cases verbosely.
 * - @c --test-log - execute logtest test cases.
 * - @c --test-slow - execute slow test cases.
 * - @c --verbose - behaves like @c --test-verbose, this option is recognized but not stripped.
 * .
 * Additional initialization arguments can be passed in @a args, currently supported are:
 * - @c autonomous - For test programs to request a self-contained runtime environment.
 * - @c cpu-affinity - CPU# to bind rapicorn thread to.
 * - @c parse-testargs - Used by init_core_test() internally.
 * - @c test-verbose - acts like --test-verbose.
 * - @c test-log - acts like --test-log.
 * - @c test-slow - acts like --test-slow.
 * .
 * Additionally, the @c $RAPICORN environment variable affects toolkit behaviour. It supports
 * multiple colon (':') separated options (options can be prfixed with 'no-' to disable):
 * - @c debug - Enables verbose debugging output (default=off).
 * - @c fatal-syslog - Fatal program conditions that lead to aborting are recorded via syslog (default=on).
 * - @c syslog - Critical and warning conditions are recorded via syslog (default=off).
 * - @c fatal-warnings - Critical and warning conditions are treated as fatal conditions (default=off).
 * - @c logfile=FILENAME - Record all messages and conditions into FILENAME.
 * .
 */
void
init_core (const String       &app_ident,
           int                *argcp,
           char              **argv,
           const StringVector &args)
{
  return_if_fail (app_ident.empty() == false);
  // assert global_ctors work
  if (__staticctortest.v != 0x12affe17)
    fatal ("librapicorncore: link error: C++ constructors have not been executed");

  // guard against double initialization
  if (program_app_ident.empty() == false)
    fatal ("librapicorncore: multiple calls to Rapicorn::init_app()");
  program_app_ident = app_ident;

  // mandatory threading initialization
  if (!g_threads_got_initialized)
    g_thread_init (NULL);

  // setup program and application name
  if (program_argv0.empty() && argcp && *argcp && argv && argv[0] && argv[0][0] != 0)
    program_argv0 = argv[0];
  if (program_cwd0.empty())
    program_cwd0 = Path::cwd();
  if (!g_get_prgname() && !program_argv0.empty())
    g_set_prgname (Path::basename (program_argv0).c_str());
  if (!g_get_application_name() || g_get_application_name() == g_get_prgname())
    g_set_application_name (program_app_ident.c_str());

  // ensure logging works correctly
  const char *env_rapicorn = getenv ("RAPICORN");
  Logging::configure (env_rapicorn ? env_rapicorn : "");
  RAPICORN_DEBUG ("startup; RAPICORN=%s", env_rapicorn ? env_rapicorn : "");

  // setup init settings
  parse_settings_and_args (vinit_settings, args, argcp, argv);

  // initialize sub systems
  struct InitHookCaller : public InitHook {
    static void  invoke (const String &kind, int *argcp, char **argv, const StringVector &args)
    { invoke_hooks (kind, argcp, argv, args); }
  };
  InitHookCaller::invoke ("core/", argcp, argv, args);
  InitHookCaller::invoke ("threading/", argcp, argv, args);
}

} // Rapicorn
<commit_msg>RCORE: docu fixup<commit_after>// Licensed GNU LGPL v3 or later: http://www.gnu.org/licenses/lgpl.html
#include "main.hh"
#include "strings.hh"
#include <string.h>
#include <algorithm>

#include <glib.h>

namespace Rapicorn {

// === initialization hooks ===
static InitHook *init_hooks = NULL;

InitHook::InitHook (const String &fname, InitHookFunc func) :
  next (NULL), hook (func), m_name (fname)
{
  next = init_hooks;
  init_hooks = this;
}

static int
init_hook_cmp (const InitHook *const &v1, const InitHook *const &v2)
{
  static const char *levels[] = { "core/", "threading/", "ui/" };
  uint l1 = UINT_MAX, l2 = UINT_MAX;
  for (uint i = 0; i < RAPICORN_ARRAY_SIZE (levels); i++)
    {
      const uint len = strlen (levels[i]);
      if (l1 == UINT_MAX && strncmp (levels[i], v1->name().c_str(), len) == 0)
        {
          l1 = i;
          if (l2 != UINT_MAX)
            break;
        }
      if (l2 == UINT_MAX && strncmp (levels[i], v2->name().c_str(), len) == 0)
        {
          l2 = i;
          if (l1 != UINT_MAX)
            break;
        }
    }
  if (l1 != l2)
    return l1 < l2 ? -1 : l2 > l1;
  return strverscmp (v1->name().c_str(), v2->name().c_str()) < 0;
}

static StringVector *init_hook_main_args = NULL;

StringVector
InitHook::main_args () const
{
  return *init_hook_main_args;
}

void
InitHook::invoke_hooks (const String &kind, int *argcp, char **argv, const StringVector &args)
{
  std::vector<InitHook*> hv;
  for (InitHook *ihook = init_hooks; ihook; ihook = ihook->next)
    hv.push_back (ihook);
  stable_sort (hv.begin(), hv.end(), init_hook_cmp);
  StringVector main_args;
  for (uint i = 1; i < uint (*argcp); i++)
    main_args.push_back (argv[i]);
  init_hook_main_args = &main_args;
  for (std::vector<InitHook*>::iterator it = hv.begin(); it != hv.end(); it++)
    {
      String name = (*it)->name();
      if (name.size() > kind.size() && strncmp (name.data(), kind.data(), kind.size()) == 0)
        {
          RAPICORN_DEBUG ("InitHook: %s", name.c_str());
          (*it)->hook (args);
        }
    }
  init_hook_main_args = NULL;
}

// === arg parsers ===
/**
 * Try to parse argument @a arg at position @a i in @a argv.
 * If successfull, @a i is incremented and the argument
 * is set to NULL.
 * @returns true if successfull.
 */
bool
arg_parse_option (uint         argc,
                  char       **argv,
                  size_t      *i,
                  const char  *arg)
{
  if (strcmp (argv[*i], arg) == 0)
    {
      argv[*i] = NULL;
      return true;
    }
  return false;
}

/**
 * Try to parse argument @a arg at position @a i in @a argv.
 * If successfull, @a i is incremented and the argument and possibly
 * the next option argument are set to NULL.
 * @returns true if successfull and the string option in @a strp.
 */
bool
arg_parse_string_option (uint         argc,
                         char       **argv,
                         size_t      *i,
                         const char  *arg,
                         const char **strp)
{
  const size_t length = strlen (arg);
  if (strncmp (argv[*i], arg, length) == 0)
    {
      const char *equal = argv[*i] + length;
      if (*equal == '=')                // -x=VAL
        *strp = equal + 1;
      else if (*equal)                  // -xVAL
        *strp = equal;
      else if (*i + 1 < argc)           // -x VAL
        {
          argv[(*i)++] = NULL;
          *strp = argv[*i];
        }
      else
        *strp = NULL;
      argv[*i] = NULL;
      if (*strp)
        return true;
    }
  return false;
}

/**
 * Collapse @a argv by eliminating NULL strings.
 * @returns Number of collapsed arguments.
 */
int
arg_parse_collapse (int   *argcp,
                    char **argv)
{
  // collapse args
  const uint argc = *argcp;
  uint e = 1;
  for (uint i = 1; i < argc; i++)
    if (argv[i])
      {
        argv[e++] = argv[i];
        if (i >= e)
          argv[i] = NULL;
      }
  const int collapsed = *argcp - e;
  *argcp = e;
  return collapsed;
}

static bool
parse_bool_option (const String &s, const char *arg, bool *boolp)
{
  const size_t length = strlen (arg);
  if (s.size() > length && s[length] == '=' && strncmp (&s[0], arg, length) == 0)
    {
      *boolp = string_to_bool (s.substr (length + 1));
      return true;
    }
  return false;
}

// === initialization ===
struct VInitSettings : InitSettings {
  bool& autonomous()    { return m_autonomous; }
  uint& test_codes()    { return m_test_codes; }
  VInitSettings() { m_autonomous = false; m_test_codes = 0; }
} static vsettings;
static VInitSettings vinit_settings;
const InitSettings  *InitSettings::sis = &vinit_settings;

static void
parse_settings_and_args (VInitSettings      &vsettings,
                         const StringVector &args,
                         int                *argcp,
                         char              **argv)
{
  bool b = 0, pta = false;
  // apply init settings
  for (StringVector::const_iterator it = args.begin(); it != args.end(); it++)
    if      (parse_bool_option (*it, "autonomous", &b))
      vsettings.autonomous() = b;
    else if (parse_bool_option (*it, "parse-testargs", &b))
      pta = b;
    else if (parse_bool_option (*it, "test-verbose", &b))
      vsettings.test_codes() |= 0x1;
    else if (parse_bool_option (*it, "test-log", &b))
      vsettings.test_codes() |= 0x2;
    else if (parse_bool_option (*it, "test-slow", &b))
      vsettings.test_codes() |= 0x4;
  // parse command line args
  const size_t argc = *argcp;
  for (size_t i = 1; i < argc; i++)
    {
      if (            arg_parse_option (*argcp, argv, &i, "--g-fatal-warnings"))
        {
          const uint fatal_mask = g_log_set_always_fatal (GLogLevelFlags (G_LOG_FATAL_MASK));
          g_log_set_always_fatal (GLogLevelFlags (fatal_mask | G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL));
        }
      else if (pta && arg_parse_option (*argcp, argv, &i, "--test-verbose"))
        vsettings.test_codes() |= 0x1;
      else if (pta && arg_parse_option (*argcp, argv, &i, "--test-log"))
        vsettings.test_codes() |= 0x2;
      else if (pta && arg_parse_option (*argcp, argv, &i, "--test-slow"))
        vsettings.test_codes() |= 0x4;
      else if (pta && strcmp ("--verbose", argv[i]) == 0)
        {
          vsettings.test_codes() |= 0x1;
          /* interpret --verbose for GLib compat but don't delete the argument
           * since regular non-test programs may need this. could be fixed by
           * having a separate test program argument parser.
           */
        }
    }
  // collapse NULL arguments
  arg_parse_collapse (argcp, argv);
}

static String program_argv0 = "";
static String program_app_ident = "";
static String program_cwd0 = "";

/**
 * File name of the current process as set in argv[0] at startup.
 */
String
program_file ()
{
  return program_argv0;
}

/**
 * The program identifier @a app_ident as specified during initialization of Rapicorn.
 */
String
program_ident ()
{
  return program_app_ident;
}

/**
 * The current working directory during startup.
 */
String
program_cwd ()
{
  return program_cwd0;
}

static struct __StaticCTorTest { int v; __StaticCTorTest() : v (0x12affe16) { v++; } } __staticctortest;

/**
 * @param app_ident     Application identifier, used to associate persistent resources
 * @param argcp         location of the 'argc' argument to main()
 * @param argv          location of the 'argv' arguments to main()
 * @param args          program specific initialization values
 *
 * Initialize the Rapicorn toolkit, including threading, CPU detection, loading resource libraries, etc.
 * The arguments passed in @a argcp and @a argv are parsed and any Rapicorn specific arguments
 * are stripped.
 * Supported command line arguments are:
 * - @c --test-verbose - execute test cases verbosely.
 * - @c --test-log - execute logtest test cases.
 * - @c --test-slow - execute slow test cases.
 * - @c --verbose - behaves like @c --test-verbose, this option is recognized but not stripped.
 * .
 * Additional initialization arguments can be passed in @a args, currently supported are:
 * - @c autonomous - For test programs to request a self-contained runtime environment.
 * - @c cpu-affinity - CPU# to bind rapicorn thread to.
 * - @c parse-testargs - Used by init_core_test() internally.
 * - @c test-verbose - acts like --test-verbose.
 * - @c test-log - acts like --test-log.
 * - @c test-slow - acts like --test-slow.
 * .
 * Additionally, the @c $RAPICORN environment variable affects toolkit behaviour. It supports
 * multiple colon (':') separated options (options can be prfixed with 'no-' to disable):
 * - @c debug - Enables verbose debugging output (default=off).
 * - @c fatal-syslog - Fatal program conditions that lead to aborting are recorded via syslog (default=on).
 * - @c syslog - Critical and warning conditions are recorded via syslog (default=off).
 * - @c fatal-warnings - Critical and warning conditions are treated as fatal conditions (default=off).
 * - @c logfile=FILENAME - Record all messages and conditions into FILENAME.
 * .
 */
void
init_core (const String       &app_ident,
           int                *argcp,
           char              **argv,
           const StringVector &args)
{
  return_if_fail (app_ident.empty() == false);
  // assert global_ctors work
  if (__staticctortest.v != 0x12affe17)
    fatal ("librapicorncore: link error: C++ constructors have not been executed");

  // guard against double initialization
  if (program_app_ident.empty() == false)
    fatal ("librapicorncore: multiple calls to Rapicorn::init_app()");
  program_app_ident = app_ident;

  // mandatory threading initialization
  if (!g_threads_got_initialized)
    g_thread_init (NULL);

  // setup program and application name
  if (program_argv0.empty() && argcp && *argcp && argv && argv[0] && argv[0][0] != 0)
    program_argv0 = argv[0];
  if (program_cwd0.empty())
    program_cwd0 = Path::cwd();
  if (!g_get_prgname() && !program_argv0.empty())
    g_set_prgname (Path::basename (program_argv0).c_str());
  if (!g_get_application_name() || g_get_application_name() == g_get_prgname())
    g_set_application_name (program_app_ident.c_str());

  // ensure logging works correctly
  const char *env_rapicorn = getenv ("RAPICORN");
  Logging::configure (env_rapicorn ? env_rapicorn : "");
  RAPICORN_DEBUG ("startup; RAPICORN=%s", env_rapicorn ? env_rapicorn : "");

  // setup init settings
  parse_settings_and_args (vinit_settings, args, argcp, argv);

  // initialize sub systems
  struct InitHookCaller : public InitHook {
    static void  invoke (const String &kind, int *argcp, char **argv, const StringVector &args)
    { invoke_hooks (kind, argcp, argv, args); }
  };
  InitHookCaller::invoke ("core/", argcp, argv, args);
  InitHookCaller::invoke ("threading/", argcp, argv, args);
}

} // Rapicorn
<|endoftext|>


<commit_before>//
//  ASTThirdLevelExpressionNode.cpp
//  lut-lang
//
//  Created by Robin Ricard on 22/03/15.
//  Copyright (c) 2015 INSA Lyon. All rights reserved.
//

#include "ASTThirdLevelExpressionNode.h"

#include <tuple>
#include <iostream>
#include <utility>
#include <string>
#include <sstream>

using std::cout;
using std::cerr;
using std::endl;
using std::pair;
using std::stringstream;

ASTThirdLevelExpressionNode::ASTThirdLevelExpressionNode(ASTTokenNode* identifierOrValue,
                                                         TokenType type) : ASTNode(type) {
  this->identifierOrValue = identifierOrValue;
  this->expression = NULL;
}

ASTThirdLevelExpressionNode::ASTThirdLevelExpressionNode(ASTFirstLevelExpressionNode* expression,
                                                         TokenType type) : ASTNode(type) {
  this->identifierOrValue = NULL;
  this->expression = expression;
}

ASTTokenNode* ASTThirdLevelExpressionNode::getIdentifierOrValue() {
  return this->identifierOrValue;
}

ASTFirstLevelExpressionNode* ASTThirdLevelExpressionNode::getExpression() {
  return this->expression;
}

bool ASTThirdLevelExpressionNode::analyze(analyze_table* table) {
  if (expression != NULL && !expression->analyze(table)) {
    return false;
  } else if (this->identifierOrValue != NULL &&
             this->identifierOrValue->getTokenType() == TokenType::ID &&
             (table->count(this->identifierOrValue->getValue()) < 1 ||
              !std::get<0>((*table)[this->identifierOrValue->getValue()]))) {
    cerr << "variable non affectee : " << this->identifierOrValue->getValue() << endl;
    return false;
  } else if (this->identifierOrValue != NULL &&
             this->identifierOrValue->getTokenType() == TokenType::ID) {
    bool isConst = std::get<1>((*table)[this->identifierOrValue->getValue()]);
    (*table)[this->identifierOrValue->getValue()] = std::make_tuple(true, isConst, true);
  }
  return true;
}

int64_t ASTThirdLevelExpressionNode::exec(exec_table* table) {
  if (this->identifierOrValue != NULL) {
    if (this->identifierOrValue->getTokenType() == TokenType::ID &&
        table->count(this->identifierOrValue->getValue()) > 0) {
      return std::get<0>((*table)[this->identifierOrValue->getValue()]);
    } else if (this->identifierOrValue->getTokenType() == TokenType::ID) {
      throw std::logic_error("does not exist");
    } else {
      stringstream ss;
      ss << this->identifierOrValue->getValue();
      int64_t value;
      ss >> value;
      return value;
    }
  } else {
    return expression->exec(table);
  }
}

void ASTThirdLevelExpressionNode::print() {
  if (this->identifierOrValue != NULL) {
    this->identifierOrValue->print();
  } else {
    cout << "(";
    this->expression->print();
    cout << ")";
  }
}

void ASTThirdLevelExpressionNode::transform(exec_table* table) {
  if (this->expression != NULL) {
    this->expression->transform(table);
  } else if (this->identifierOrValue != NULL &&
      this->identifierOrValue->getTokenType() == TokenType::ID &&
      table->count(this->identifierOrValue->getValue()) > 0) {
    std::tuple<int64_t, bool> constTerm = (*table)[this->identifierOrValue->getValue()];
    if (std::get<1>(constTerm)) {
      stringstream ss;
      ss << std::get<0>(constTerm);
      string val = ss.str();
      this->identifierOrValue = new ASTTokenNode(TokenType::VAL, val);
    }
  }
}
<commit_msg>Fix Circle<commit_after>//
//  ASTThirdLevelExpressionNode.cpp
//  lut-lang
//
//  Created by Robin Ricard on 22/03/15.
//  Copyright (c) 2015 INSA Lyon. All rights reserved.
//

#include "ASTThirdLevelExpressionNode.h"

#include <tuple>
#include <iostream>
#include <utility>
#include <string>
#include <sstream>

using std::cout;
using std::cerr;
using std::endl;
using std::pair;
using std::stringstream;

ASTThirdLevelExpressionNode::ASTThirdLevelExpressionNode(ASTTokenNode* identifierOrValue,
                                                         TokenType type) : ASTNode(type) {
  this->identifierOrValue = identifierOrValue;
  this->expression = NULL;
}

ASTThirdLevelExpressionNode::ASTThirdLevelExpressionNode(ASTFirstLevelExpressionNode* expression,
                                                         TokenType type) : ASTNode(type) {
  this->identifierOrValue = NULL;
  this->expression = expression;
}

ASTTokenNode* ASTThirdLevelExpressionNode::getIdentifierOrValue() {
  return this->identifierOrValue;
}

ASTFirstLevelExpressionNode* ASTThirdLevelExpressionNode::getExpression() {
  return this->expression;
}

bool ASTThirdLevelExpressionNode::analyze(analyze_table* table) {
  if (expression != NULL && !expression->analyze(table)) {
    return false;
  } else if (this->identifierOrValue != NULL &&
             this->identifierOrValue->getTokenType() == TokenType::ID &&
             (table->count(this->identifierOrValue->getValue()) < 1 ||
              !std::get<0>((*table)[this->identifierOrValue->getValue()]))) {
    cerr << "variable non affectee : " << this->identifierOrValue->getValue() << endl;
    return false;
  } else if (this->identifierOrValue != NULL &&
             this->identifierOrValue->getTokenType() == TokenType::ID) {
    bool isConst = std::get<1>((*table)[this->identifierOrValue->getValue()]);
    (*table)[this->identifierOrValue->getValue()] = std::make_tuple(true, isConst, true);
  }
  return true;
}

int64_t ASTThirdLevelExpressionNode::exec(exec_table* table) {
  if (this->identifierOrValue != NULL) {
    if (this->identifierOrValue->getTokenType() == TokenType::ID &&
        table->count(this->identifierOrValue->getValue()) > 0) {
      return std::get<0>((*table)[this->identifierOrValue->getValue()]);
    } else if (this->identifierOrValue->getTokenType() == TokenType::ID) {
      throw std::exception();
      return false;
    } else {
      stringstream ss;
      ss << this->identifierOrValue->getValue();
      int64_t value;
      ss >> value;
      return value;
    }
  } else {
    return expression->exec(table);
  }
}

void ASTThirdLevelExpressionNode::print() {
  if (this->identifierOrValue != NULL) {
    this->identifierOrValue->print();
  } else {
    cout << "(";
    this->expression->print();
    cout << ")";
  }
}

void ASTThirdLevelExpressionNode::transform(exec_table* table) {
  if (this->expression != NULL) {
    this->expression->transform(table);
  } else if (this->identifierOrValue != NULL &&
      this->identifierOrValue->getTokenType() == TokenType::ID &&
      table->count(this->identifierOrValue->getValue()) > 0) {
    std::tuple<int64_t, bool> constTerm = (*table)[this->identifierOrValue->getValue()];
    if (std::get<1>(constTerm)) {
      stringstream ss;
      ss << std::get<0>(constTerm);
      string val = ss.str();
      this->identifierOrValue = new ASTTokenNode(TokenType::VAL, val);
    }
  }
}
<|endoftext|>