<commit_before>//
// Copyright (c) 2014 CNRS
// Authors: Florent Lamiraux
//
// This file is part of hpp-core
// hpp-core is free software: you can redistribute it
// and/or modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation, either version
// 3 of the License, or (at your option) any later version.
//
// hpp-core is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Lesser Public License for more details.  You should have
// received a copy of the GNU Lesser General Public License along with
// hpp-core  If not, see
// <http://www.gnu.org/licenses/>.

#ifndef HPP_CORE_PATH_HH
# define HPP_CORE_PATH_HH

# include <boost/concept_check.hpp>
# include <hpp/util/exception.hh>
# include <hpp/core/fwd.hh>
# include <hpp/core/config.hh>
# include <hpp/core/constraint-set.hh>
# include <hpp/core/deprecated.hh>
# include <hpp/core/projection-error.hh>
# include <hpp/core/time-parameterization.hh>

namespace hpp {
  namespace core {
    /// \addtogroup path Path
    /// Path abstraction, implementation and decorators
    /// \{

    /// Abstraction of paths: mapping from time to configuration space
    ///
    class HPP_CORE_DLLAPI Path
    {
    public:
      /// \name Construction, destruction, copy
      /// \{

      /// Destructor
      virtual ~Path () throw () {}

      /// Return a shared pointer to a copy of this
      virtual PathPtr_t copy () const = 0;

      /// Return a shared pointer to a copy of this and set constraints
      ///
      /// \param constraints constraints to apply to the copy
      /// \precond *this should not have constraints.
      virtual PathPtr_t copy (const ConstraintSetPtr_t& constraints) const = 0;

      /// Static cast into a derived type
      template <class T> boost::shared_ptr<T> as (void)
      {
	assert (HPP_DYNAMIC_PTR_CAST (T, weak_.lock ()));
	return HPP_STATIC_PTR_CAST (T, weak_.lock ());
      }

      /// Static cast into a derived type
      template <class T> boost::shared_ptr<const T> as (void) const
      {
	assert (HPP_DYNAMIC_PTR_CAST (const T, weak_.lock ()));
	return HPP_STATIC_PTR_CAST (const T, weak_.lock ());
      }

      /// Extraction/Reversion of a sub-path
      /// \param subInterval interval of definition of the extract path
      /// If upper bound of subInterval is smaller than lower bound,
      /// result is reversed.
      /// \exception projection_error is thrown when an end configuration of
      ///                             the returned path could not be computed
      ///                             due to projection failure.
      virtual PathPtr_t extract (const interval_t& subInterval) const
        throw (projection_error);

      /// Reversion of a path
      /// \return a new path that is this one reversed.
      virtual PathPtr_t reverse () const;

      /// \}

      Configuration_t operator () (const value_type& time) const
        HPP_CORE_DEPRECATED
      {
	Configuration_t result (outputSize ());
	impl_compute (result, paramAtTime(time));
	if (constraints_) {
	  constraints_->apply (result);
	}
	return result;
      }

      Configuration_t operator () (const value_type& time, bool& success) const
      {
	Configuration_t result (outputSize ());
	success = impl_compute (result, paramAtTime(time));
	if (!success) return result;
	if (constraints_) {
	  success = constraints_->apply (result);
	}
	return result;
      }

      bool operator () (ConfigurationOut_t result, const value_type& time)
       const throw ()
      {
	bool success = impl_compute (result, paramAtTime(time));
	if (!success) return false;
	return (!constraints_ || constraints_->apply (result));
      }

      /// Get the configuration at a parameter without applying the constraints.
      bool at (const value_type& time, ConfigurationOut_t result) const
      {
        return impl_compute (result, paramAtTime(time));
      }

      /// Get derivative with respect to parameter at given parameter
      /// \param time value of the time in the definition interval,
      /// \param order order of the derivative
      /// \retval result derivative. Should be allocated and of correct size.
      /// \warning the method is not implemented in this class and throws if
      ///          called without being implemented in the derived class.
      /// \note unless otherwise stated, this method is not compatible with
      ///       constraints. The derivative of the non-constrained path will
      ///       be computed.
      void derivative (vectorOut_t result, const value_type& time,
          size_type order) const
      {
        if (timeParam_) {
          assert (order == 1);
          impl_derivative (result, timeParam_->value(time), order);
          result *= timeParam_->derivative(time);
        } else {
          impl_derivative (result, time, order);
        }
      }

      /// Get the maximum velocity on a sub-interval of this path
      /// \param t0 begin of the interval
      /// \param t1 end of the interval
      /// \retval result maximal derivative on the sub-interval. Should be allocated and of correct size.
      /// \warning the method is not implemented in this class and throws if
      ///          called without being implemented in the derived class.
      /// \note unless otherwise stated, this method is not compatible with
      ///       constraints. The derivative of the non-constrained path will
      ///       be computed.
      void velocityBound (vectorOut_t result, const value_type& t0, const value_type& t1) const
      {
        assert(result.size() == outputDerivativeSize());
        assert(t0 <= t1);
	impl_velocityBound (result,
            paramAtTime (std::max(t0, timeRange().first )),
            paramAtTime (std::min(t1, timeRange().second)));
        if (timeParam_)
          result *= timeParam_->derivativeBound (t0, t1);
      }

      /// \brief Function evaluation without applying constraints
      ///
      /// \return true if everything went good.
      virtual bool impl_compute (ConfigurationOut_t configuration,
				 value_type param) const = 0;

      /// Virtual implementation of derivative
      virtual void impl_derivative (vectorOut_t, const value_type&,
				    size_type) const
      {
	HPP_THROW_EXCEPTION (hpp::Exception, "not implemented");
      }

      /// Virtual implementation of velocityBound
      virtual void impl_velocityBound (vectorOut_t, const value_type&, const value_type&) const
      {
	HPP_THROW_EXCEPTION (hpp::Exception, "not implemented");
      }

      /// \name Constraints
      /// \{

      /// Get constraints the path is subject to
      const ConstraintSetPtr_t& constraints () const
      {
	return constraints_;
      }
      /// \}

      /// Get size of configuration space
      size_type outputSize () const
      {
	return outputSize_;
      }

      /// Get size of velocity
      size_type outputDerivativeSize () const
      {
	return outputDerivativeSize_;
      }

      /// Get interval of definition
      const interval_t& timeRange () const
      {
	return timeRange_;
      }

      /// Get interval of parameters.
      /// If the instance contains a \ref timeParam_
      /// this returns timeParam_ (timeRange())
      /// otherwise, it returns \ref timeRange
      const interval_t& paramRange () const
      {
	return paramRange_;
      }

      /// Set the time parameterization function
      void timeParameterization (const TimeParameterizationPtr_t& tp,
          const interval_t& tr)
      {
        timeParam_ = tp;
        timeRange (tr);
      }

      /// Get length of definition interval
      value_type length () const
      {
	return timeRange_.second - timeRange_.first;
      }

      /// Get the initial configuration
      virtual Configuration_t initial () const = 0;

      /// Get the final configuration
      virtual Configuration_t end () const = 0;

    protected:
      /// Print interval of definition (and of parameters if relevant)
      /// in a stream
      virtual std::ostream& print (std::ostream &os) const;

      /// Constructor
      /// \param interval interval of definition of the path,
      /// \param outputSize size of the output configuration,
      /// \param outputDerivativeSize number of degrees of freedom of  the
      ///        underlying robot
      /// \param constraints constraints the set is subject to,
      ///        constraints are solved at each evaluation of the output
      ///        configuration.
      /// \note Constraints are copied.
      Path (const interval_t& interval, size_type outputSize,
	    size_type outputDerivativeSize,
	    const ConstraintSetPtr_t& constraints);

      /// Constructor
      /// \param interval interval of definition of the path,
      /// \param outputSize size of the output configuration,
      /// \param outputDerivativeSize number of degrees of freedom of  the
      ///        underlying robot
      Path (const interval_t& interval, size_type outputSize,
	    size_type outputDerivativeSize);

      /// Copy constructor
      Path (const Path& path);

      /// Copy constructor with constraints
      Path (const Path& path, const ConstraintSetPtr_t& constraints);

      /// Store weak pointer to itself
      ///
      /// should be called at construction of derived class instances
      void init (const PathWkPtr_t& self);

      /// Interval of parameters
      interval_t paramRange_;

      /// Set the constraints
      /// \warning this method is protected for child classes that need to
      ///          initialize themselves before being sure that the initial and
      ///          end configuration satisfy the constraints
      void constraints (const ConstraintSetPtr_t& constraint) {
        constraints_ = constraint;
      }

      /// Should be called by child classes after having init.
      virtual void checkPath () const;

      void timeRange (const interval_t& timeRange)
      {
        timeRange_ = timeRange;
        if (timeParam_) {
          paramRange_.first  = timeParam_->value(timeRange_.first );
          paramRange_.second = timeParam_->value(timeRange_.second);
        } else
          paramRange_ = timeRange_;
      }

      const TimeParameterizationPtr_t& timeParameterization() const
      {
        return timeParam_;
      }

      value_type paramLength() const
      {
        return paramRange_.second - paramRange_.first;
      }
    private:
      /// Interval of definition
      interval_t timeRange_;

      value_type paramAtTime (const value_type& time) const
      {
        if (timeParam_) {
          return timeParam_->value (time);
        }
        return time;
      }

      /// Size of the configuration space
      size_type outputSize_;
      /// Number of degrees of freedom of the robot
      size_type outputDerivativeSize_;
      /// Constraints that apply to the robot
      ConstraintSetPtr_t constraints_;
      /// Time parameterization
      TimeParameterizationPtr_t timeParam_;
      /// Weak pointer to itself
      PathWkPtr_t weak_;
      friend std::ostream& operator<< (std::ostream& os, const Path& path);
    }; // class Path
    inline std::ostream& operator<< (std::ostream& os, const Path& path)
    {
      return path.print (os);
    }
    /// \}

  } //   namespace core
} // namespace hpp
#endif // HPP_CORE_PATH_HH
<commit_msg>Add Path::configAtParam and make impl_compute, impl_derivative and impl_velocityBound protected<commit_after>//
// Copyright (c) 2014 CNRS
// Authors: Florent Lamiraux
//
// This file is part of hpp-core
// hpp-core is free software: you can redistribute it
// and/or modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation, either version
// 3 of the License, or (at your option) any later version.
//
// hpp-core is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Lesser Public License for more details.  You should have
// received a copy of the GNU Lesser General Public License along with
// hpp-core  If not, see
// <http://www.gnu.org/licenses/>.

#ifndef HPP_CORE_PATH_HH
# define HPP_CORE_PATH_HH

# include <boost/concept_check.hpp>
# include <hpp/util/exception.hh>
# include <hpp/core/fwd.hh>
# include <hpp/core/config.hh>
# include <hpp/core/constraint-set.hh>
# include <hpp/core/deprecated.hh>
# include <hpp/core/projection-error.hh>
# include <hpp/core/time-parameterization.hh>

namespace hpp {
  namespace core {
    /// \addtogroup path Path
    /// Path abstraction, implementation and decorators
    /// \{

    /// Abstraction of paths: mapping from time to configuration space
    ///
    class HPP_CORE_DLLAPI Path
    {
    public:
      /// \name Construction, destruction, copy
      /// \{

      /// Destructor
      virtual ~Path () throw () {}

      /// Return a shared pointer to a copy of this
      virtual PathPtr_t copy () const = 0;

      /// Return a shared pointer to a copy of this and set constraints
      ///
      /// \param constraints constraints to apply to the copy
      /// \precond *this should not have constraints.
      virtual PathPtr_t copy (const ConstraintSetPtr_t& constraints) const = 0;

      /// Static cast into a derived type
      template <class T> boost::shared_ptr<T> as (void)
      {
	assert (HPP_DYNAMIC_PTR_CAST (T, weak_.lock ()));
	return HPP_STATIC_PTR_CAST (T, weak_.lock ());
      }

      /// Static cast into a derived type
      template <class T> boost::shared_ptr<const T> as (void) const
      {
	assert (HPP_DYNAMIC_PTR_CAST (const T, weak_.lock ()));
	return HPP_STATIC_PTR_CAST (const T, weak_.lock ());
      }

      /// Extraction/Reversion of a sub-path
      /// \param subInterval interval of definition of the extract path
      /// If upper bound of subInterval is smaller than lower bound,
      /// result is reversed.
      /// \exception projection_error is thrown when an end configuration of
      ///                             the returned path could not be computed
      ///                             due to projection failure.
      virtual PathPtr_t extract (const interval_t& subInterval) const
        throw (projection_error);

      /// Reversion of a path
      /// \return a new path that is this one reversed.
      virtual PathPtr_t reverse () const;

      /// \}

      Configuration_t operator () (const value_type& time) const
        HPP_CORE_DEPRECATED
      {
	Configuration_t result (outputSize ());
	impl_compute (result, paramAtTime(time));
	if (constraints_) {
	  constraints_->apply (result);
	}
	return result;
      }

      Configuration_t operator () (const value_type& time, bool& success) const
      {
        return configAtParam (paramAtTime(time), success);
      }

      bool operator () (ConfigurationOut_t result, const value_type& time)
       const throw ()
      {
	bool success = impl_compute (result, paramAtTime(time));
	if (!success) return false;
	return (!constraints_ || constraints_->apply (result));
      }

      /// Get the configuration at a parameter without applying the constraints.
      bool at (const value_type& time, ConfigurationOut_t result) const
      {
        return impl_compute (result, paramAtTime(time));
      }

      /// Get derivative with respect to parameter at given parameter
      /// \param time value of the time in the definition interval,
      /// \param order order of the derivative
      /// \retval result derivative. Should be allocated and of correct size.
      /// \warning the method is not implemented in this class and throws if
      ///          called without being implemented in the derived class.
      /// \note unless otherwise stated, this method is not compatible with
      ///       constraints. The derivative of the non-constrained path will
      ///       be computed.
      void derivative (vectorOut_t result, const value_type& time,
          size_type order) const
      {
        if (timeParam_) {
          assert (order == 1);
          impl_derivative (result, timeParam_->value(time), order);
          result *= timeParam_->derivative(time);
        } else {
          impl_derivative (result, time, order);
        }
      }

      /// Get the maximum velocity on a sub-interval of this path
      /// \param t0 begin of the interval
      /// \param t1 end of the interval
      /// \retval result maximal derivative on the sub-interval. Should be allocated and of correct size.
      /// \warning the method is not implemented in this class and throws if
      ///          called without being implemented in the derived class.
      /// \note unless otherwise stated, this method is not compatible with
      ///       constraints. The derivative of the non-constrained path will
      ///       be computed.
      void velocityBound (vectorOut_t result, const value_type& t0, const value_type& t1) const
      {
        assert(result.size() == outputDerivativeSize());
        assert(t0 <= t1);
	impl_velocityBound (result,
            paramAtTime (std::max(t0, timeRange().first )),
            paramAtTime (std::min(t1, timeRange().second)));
        if (timeParam_)
          result *= timeParam_->derivativeBound (t0, t1);
      }

      /// \name Constraints
      /// \{

      /// Get constraints the path is subject to
      const ConstraintSetPtr_t& constraints () const
      {
	return constraints_;
      }
      /// \}

      /// Get size of configuration space
      size_type outputSize () const
      {
	return outputSize_;
      }

      /// Get size of velocity
      size_type outputDerivativeSize () const
      {
	return outputDerivativeSize_;
      }

      /// Get interval of definition
      const interval_t& timeRange () const
      {
	return timeRange_;
      }

      /// Get interval of parameters.
      /// If the instance contains a \ref timeParam_
      /// this returns timeParam_ (timeRange())
      /// otherwise, it returns \ref timeRange
      const interval_t& paramRange () const
      {
	return paramRange_;
      }

      /// Set the time parameterization function
      void timeParameterization (const TimeParameterizationPtr_t& tp,
          const interval_t& tr)
      {
        timeParam_ = tp;
        timeRange (tr);
      }

      /// Get length of definition interval
      value_type length () const
      {
	return timeRange_.second - timeRange_.first;
      }

      /// Get the initial configuration
      virtual Configuration_t initial () const = 0;

      /// Get the final configuration
      virtual Configuration_t end () const = 0;

    protected:
      /// Print interval of definition (and of parameters if relevant)
      /// in a stream
      virtual std::ostream& print (std::ostream &os) const;

      /// Constructor
      /// \param interval interval of definition of the path,
      /// \param outputSize size of the output configuration,
      /// \param outputDerivativeSize number of degrees of freedom of  the
      ///        underlying robot
      /// \param constraints constraints the set is subject to,
      ///        constraints are solved at each evaluation of the output
      ///        configuration.
      /// \note Constraints are copied.
      Path (const interval_t& interval, size_type outputSize,
	    size_type outputDerivativeSize,
	    const ConstraintSetPtr_t& constraints);

      /// Constructor
      /// \param interval interval of definition of the path,
      /// \param outputSize size of the output configuration,
      /// \param outputDerivativeSize number of degrees of freedom of  the
      ///        underlying robot
      Path (const interval_t& interval, size_type outputSize,
	    size_type outputDerivativeSize);

      /// Copy constructor
      Path (const Path& path);

      /// Copy constructor with constraints
      Path (const Path& path, const ConstraintSetPtr_t& constraints);

      /// Store weak pointer to itself
      ///
      /// should be called at construction of derived class instances
      void init (const PathWkPtr_t& self);

      /// Interval of parameters
      interval_t paramRange_;

      /// Set the constraints
      /// \warning this method is protected for child classes that need to
      ///          initialize themselves before being sure that the initial and
      ///          end configuration satisfy the constraints
      void constraints (const ConstraintSetPtr_t& constraint) {
        constraints_ = constraint;
      }

      /// Should be called by child classes after having init.
      virtual void checkPath () const;

      void timeRange (const interval_t& timeRange)
      {
        timeRange_ = timeRange;
        if (timeParam_) {
          paramRange_.first  = timeParam_->value(timeRange_.first );
          paramRange_.second = timeParam_->value(timeRange_.second);
        } else
          paramRange_ = timeRange_;
      }

      const TimeParameterizationPtr_t& timeParameterization() const
      {
        return timeParam_;
      }

      value_type paramLength() const
      {
        return paramRange_.second - paramRange_.first;
      }

      Configuration_t configAtParam (const value_type& param, bool& success) const
      {
	Configuration_t result (outputSize ());
	success = impl_compute (result, param);
	if (!success) return result;
	if (constraints_) {
	  success = constraints_->apply (result);
	}
	return result;
      }

      /// \brief Function evaluation without applying constraints
      ///
      /// \return true if everything went good.
      virtual bool impl_compute (ConfigurationOut_t configuration,
				 value_type param) const = 0;

      /// Virtual implementation of derivative
      virtual void impl_derivative (vectorOut_t, const value_type&,
				    size_type) const
      {
	HPP_THROW_EXCEPTION (hpp::Exception, "not implemented");
      }

      /// Virtual implementation of velocityBound
      virtual void impl_velocityBound (vectorOut_t, const value_type&, const value_type&) const
      {
	HPP_THROW_EXCEPTION (hpp::Exception, "not implemented");
      }

    private:
      /// Interval of definition
      interval_t timeRange_;

      value_type paramAtTime (const value_type& time) const
      {
        if (timeParam_) {
          return timeParam_->value (time);
        }
        return time;
      }

      /// Size of the configuration space
      size_type outputSize_;
      /// Number of degrees of freedom of the robot
      size_type outputDerivativeSize_;
      /// Constraints that apply to the robot
      ConstraintSetPtr_t constraints_;
      /// Time parameterization
      TimeParameterizationPtr_t timeParam_;
      /// Weak pointer to itself
      PathWkPtr_t weak_;
      friend std::ostream& operator<< (std::ostream& os, const Path& path);
    }; // class Path
    inline std::ostream& operator<< (std::ostream& os, const Path& path)
    {
      return path.print (os);
    }
    /// \}

  } //   namespace core
} // namespace hpp
#endif // HPP_CORE_PATH_HH
<|endoftext|>


<commit_before>// Copyright (c) 2012-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "coins.h"

#include "consensus/consensus.h"
#include "memusage.h"
#include "random.h"

#include <assert.h>

bool CCoinsView::GetCoin(const COutPoint &outpoint, Coin &coin) const { return false; }
bool CCoinsView::HaveCoin(const COutPoint &outpoint) const { return false; }
uint256 CCoinsView::GetBestBlock() const { return uint256(); }
bool CCoinsView::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { return false; }
CCoinsViewCursor *CCoinsView::Cursor() const { return 0; }

CCoinsViewBacked::CCoinsViewBacked(CCoinsView *viewIn) : base(viewIn) { }
bool CCoinsViewBacked::GetCoin(const COutPoint &outpoint, Coin &coin) const { return base->GetCoin(outpoint, coin); }
bool CCoinsViewBacked::HaveCoin(const COutPoint &outpoint) const { return base->HaveCoin(outpoint); }
uint256 CCoinsViewBacked::GetBestBlock() const { return base->GetBestBlock(); }
void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; }
bool CCoinsViewBacked::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { return base->BatchWrite(mapCoins, hashBlock); }
CCoinsViewCursor *CCoinsViewBacked::Cursor() const { return base->Cursor(); }
size_t CCoinsViewBacked::EstimateSize() const { return base->EstimateSize(); }

SaltedOutpointHasher::SaltedOutpointHasher() : k0(GetRand(std::numeric_limits<uint64_t>::max())), k1(GetRand(std::numeric_limits<uint64_t>::max())) {}

CCoinsViewCache::CCoinsViewCache(CCoinsView *baseIn) : CCoinsViewBacked(baseIn), cachedCoinsUsage(0) {}

size_t CCoinsViewCache::DynamicMemoryUsage() const {
    return memusage::DynamicUsage(cacheCoins) + cachedCoinsUsage;
}

CCoinsMap::iterator CCoinsViewCache::FetchCoin(const COutPoint &outpoint) const {
    CCoinsMap::iterator it = cacheCoins.find(outpoint);
    if (it != cacheCoins.end())
        return it;
    Coin tmp;
    if (!base->GetCoin(outpoint, tmp))
        return cacheCoins.end();
    CCoinsMap::iterator ret = cacheCoins.emplace(std::piecewise_construct, std::forward_as_tuple(outpoint), std::forward_as_tuple(std::move(tmp))).first;
    if (ret->second.coin.IsSpent()) {
        // The parent only has an empty entry for this outpoint; we can consider our
        // version as fresh.
        ret->second.flags = CCoinsCacheEntry::FRESH;
    }
    cachedCoinsUsage += ret->second.coin.DynamicMemoryUsage();
    return ret;
}

bool CCoinsViewCache::GetCoin(const COutPoint &outpoint, Coin &coin) const {
    CCoinsMap::const_iterator it = FetchCoin(outpoint);
    if (it != cacheCoins.end()) {
        coin = it->second.coin;
        return true;
    }
    return false;
}

void CCoinsViewCache::AddCoin(const COutPoint &outpoint, Coin&& coin, bool possible_overwrite) {
    assert(!coin.IsSpent());
    if (coin.out.scriptPubKey.IsUnspendable()) return;
    CCoinsMap::iterator it;
    bool inserted;
    std::tie(it, inserted) = cacheCoins.emplace(std::piecewise_construct, std::forward_as_tuple(outpoint), std::tuple<>());
    bool fresh = false;
    if (!inserted) {
        cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage();
    }
    if (!possible_overwrite) {
        if (!it->second.coin.IsSpent()) {
            throw std::logic_error("Adding new coin that replaces non-pruned entry");
        }
        fresh = !(it->second.flags & CCoinsCacheEntry::DIRTY);
    }
    it->second.coin = std::move(coin);
    it->second.flags |= CCoinsCacheEntry::DIRTY | (fresh ? CCoinsCacheEntry::FRESH : 0);
    cachedCoinsUsage += it->second.coin.DynamicMemoryUsage();
}

void AddCoins(CCoinsViewCache& cache, const CTransaction &tx, int nHeight) {
    bool fCoinbase = tx.IsCoinBase();
    const uint256& txid = tx.GetHash();
    for (size_t i = 0; i < tx.vout.size(); ++i) {
        // Pass fCoinbase as the possible_overwrite flag to AddCoin, in order to correctly
        // deal with the pre-BIP30 occurrances of duplicate coinbase transactions.
        cache.AddCoin(COutPoint(txid, i), Coin(tx.vout[i], nHeight, fCoinbase), fCoinbase);
    }
}

void CCoinsViewCache::SpendCoin(const COutPoint &outpoint, Coin* moveout) {
    CCoinsMap::iterator it = FetchCoin(outpoint);
    if (it == cacheCoins.end()) return;
    cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage();
    if (moveout) {
        *moveout = std::move(it->second.coin);
    }
    if (it->second.flags & CCoinsCacheEntry::FRESH) {
        cacheCoins.erase(it);
    } else {
        it->second.flags |= CCoinsCacheEntry::DIRTY;
        it->second.coin.Clear();
    }
}

static const Coin coinEmpty;

const Coin& CCoinsViewCache::AccessCoin(const COutPoint &outpoint) const {
    CCoinsMap::const_iterator it = FetchCoin(outpoint);
    if (it == cacheCoins.end()) {
        return coinEmpty;
    } else {
        return it->second.coin;
    }
}

bool CCoinsViewCache::HaveCoin(const COutPoint &outpoint) const {
    CCoinsMap::const_iterator it = FetchCoin(outpoint);
    return (it != cacheCoins.end() && !it->second.coin.IsSpent());
}

bool CCoinsViewCache::HaveCoinInCache(const COutPoint &outpoint) const {
    CCoinsMap::const_iterator it = cacheCoins.find(outpoint);
    return it != cacheCoins.end();
}

uint256 CCoinsViewCache::GetBestBlock() const {
    if (hashBlock.IsNull())
        hashBlock = base->GetBestBlock();
    return hashBlock;
}

void CCoinsViewCache::SetBestBlock(const uint256 &hashBlockIn) {
    hashBlock = hashBlockIn;
}

bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn) {
    for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) {
        if (it->second.flags & CCoinsCacheEntry::DIRTY) { // Ignore non-dirty entries (optimization).
            CCoinsMap::iterator itUs = cacheCoins.find(it->first);
            if (itUs == cacheCoins.end()) {
                // The parent cache does not have an entry, while the child does
                // We can ignore it if it's both FRESH and pruned in the child
                if (!(it->second.flags & CCoinsCacheEntry::FRESH && it->second.coin.IsSpent())) {
                    // Otherwise we will need to create it in the parent
                    // and move the data up and mark it as dirty
                    CCoinsCacheEntry& entry = cacheCoins[it->first];
                    entry.coin = std::move(it->second.coin);
                    cachedCoinsUsage += entry.coin.DynamicMemoryUsage();
                    entry.flags = CCoinsCacheEntry::DIRTY;
                    // We can mark it FRESH in the parent if it was FRESH in the child
                    // Otherwise it might have just been flushed from the parent's cache
                    // and already exist in the grandparent
                    if (it->second.flags & CCoinsCacheEntry::FRESH)
                        entry.flags |= CCoinsCacheEntry::FRESH;
                }
            } else {
                // Assert that the child cache entry was not marked FRESH if the
                // parent cache entry has unspent outputs. If this ever happens,
                // it means the FRESH flag was misapplied and there is a logic
                // error in the calling code.
                if ((it->second.flags & CCoinsCacheEntry::FRESH) && !itUs->second.coin.IsSpent())
                    throw std::logic_error("FRESH flag misapplied to cache entry for base transaction with spendable outputs");

                // Found the entry in the parent cache
                if ((itUs->second.flags & CCoinsCacheEntry::FRESH) && it->second.coin.IsSpent()) {
                    // The grandparent does not have an entry, and the child is
                    // modified and being pruned. This means we can just delete
                    // it from the parent.
                    cachedCoinsUsage -= itUs->second.coin.DynamicMemoryUsage();
                    cacheCoins.erase(itUs);
                } else {
                    // A normal modification.
                    cachedCoinsUsage -= itUs->second.coin.DynamicMemoryUsage();
                    itUs->second.coin = std::move(it->second.coin);
                    cachedCoinsUsage += itUs->second.coin.DynamicMemoryUsage();
                    itUs->second.flags |= CCoinsCacheEntry::DIRTY;
                    // NOTE: It is possible the child has a FRESH flag here in
                    // the event the entry we found in the parent is pruned. But
                    // we must not copy that FRESH flag to the parent as that
                    // pruned state likely still needs to be communicated to the
                    // grandparent.
                }
            }
        }
        CCoinsMap::iterator itOld = it++;
        mapCoins.erase(itOld);
    }
    hashBlock = hashBlockIn;
    return true;
}

bool CCoinsViewCache::Flush() {
    bool fOk = base->BatchWrite(cacheCoins, hashBlock);
    cacheCoins.clear();
    cachedCoinsUsage = 0;
    return fOk;
}

void CCoinsViewCache::Uncache(const COutPoint& hash)
{
    CCoinsMap::iterator it = cacheCoins.find(hash);
    if (it != cacheCoins.end() && it->second.flags == 0) {
        cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage();
        cacheCoins.erase(it);
    }
}

unsigned int CCoinsViewCache::GetCacheSize() const {
    return cacheCoins.size();
}

CAmount CCoinsViewCache::GetValueIn(const CTransaction& tx) const
{
    if (tx.IsCoinBase())
        return 0;

    CAmount nResult = 0;
    for (unsigned int i = 0; i < tx.vin.size(); i++)
        nResult += AccessCoin(tx.vin[i].prevout).out.nValue;

    return nResult;
}

bool CCoinsViewCache::HaveInputs(const CTransaction& tx) const
{
    if (!tx.IsCoinBase()) {
        for (unsigned int i = 0; i < tx.vin.size(); i++) {
            if (!HaveCoin(tx.vin[i].prevout)) {
                return false;
            }
        }
    }
    return true;
}

static const size_t MAX_OUTPUTS_PER_BLOCK = MAX_BLOCK_BASE_SIZE /  ::GetSerializeSize(CTxOut(), SER_NETWORK, PROTOCOL_VERSION); // TODO: merge with similar definition in undo.h.

const Coin& AccessByTxid(const CCoinsViewCache& view, const uint256& txid)
{
    COutPoint iter(txid, 0);
    while (iter.n < MAX_OUTPUTS_PER_BLOCK) {
        const Coin& alternate = view.AccessCoin(iter);
        if (!alternate.IsSpent()) return alternate;
        ++iter.n;
    }
    return coinEmpty;
}
<commit_msg>[trivial] Fix typo: "occurrences" (misspelled as "occurrances")<commit_after>// Copyright (c) 2012-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "coins.h"

#include "consensus/consensus.h"
#include "memusage.h"
#include "random.h"

#include <assert.h>

bool CCoinsView::GetCoin(const COutPoint &outpoint, Coin &coin) const { return false; }
bool CCoinsView::HaveCoin(const COutPoint &outpoint) const { return false; }
uint256 CCoinsView::GetBestBlock() const { return uint256(); }
bool CCoinsView::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { return false; }
CCoinsViewCursor *CCoinsView::Cursor() const { return 0; }

CCoinsViewBacked::CCoinsViewBacked(CCoinsView *viewIn) : base(viewIn) { }
bool CCoinsViewBacked::GetCoin(const COutPoint &outpoint, Coin &coin) const { return base->GetCoin(outpoint, coin); }
bool CCoinsViewBacked::HaveCoin(const COutPoint &outpoint) const { return base->HaveCoin(outpoint); }
uint256 CCoinsViewBacked::GetBestBlock() const { return base->GetBestBlock(); }
void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; }
bool CCoinsViewBacked::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { return base->BatchWrite(mapCoins, hashBlock); }
CCoinsViewCursor *CCoinsViewBacked::Cursor() const { return base->Cursor(); }
size_t CCoinsViewBacked::EstimateSize() const { return base->EstimateSize(); }

SaltedOutpointHasher::SaltedOutpointHasher() : k0(GetRand(std::numeric_limits<uint64_t>::max())), k1(GetRand(std::numeric_limits<uint64_t>::max())) {}

CCoinsViewCache::CCoinsViewCache(CCoinsView *baseIn) : CCoinsViewBacked(baseIn), cachedCoinsUsage(0) {}

size_t CCoinsViewCache::DynamicMemoryUsage() const {
    return memusage::DynamicUsage(cacheCoins) + cachedCoinsUsage;
}

CCoinsMap::iterator CCoinsViewCache::FetchCoin(const COutPoint &outpoint) const {
    CCoinsMap::iterator it = cacheCoins.find(outpoint);
    if (it != cacheCoins.end())
        return it;
    Coin tmp;
    if (!base->GetCoin(outpoint, tmp))
        return cacheCoins.end();
    CCoinsMap::iterator ret = cacheCoins.emplace(std::piecewise_construct, std::forward_as_tuple(outpoint), std::forward_as_tuple(std::move(tmp))).first;
    if (ret->second.coin.IsSpent()) {
        // The parent only has an empty entry for this outpoint; we can consider our
        // version as fresh.
        ret->second.flags = CCoinsCacheEntry::FRESH;
    }
    cachedCoinsUsage += ret->second.coin.DynamicMemoryUsage();
    return ret;
}

bool CCoinsViewCache::GetCoin(const COutPoint &outpoint, Coin &coin) const {
    CCoinsMap::const_iterator it = FetchCoin(outpoint);
    if (it != cacheCoins.end()) {
        coin = it->second.coin;
        return true;
    }
    return false;
}

void CCoinsViewCache::AddCoin(const COutPoint &outpoint, Coin&& coin, bool possible_overwrite) {
    assert(!coin.IsSpent());
    if (coin.out.scriptPubKey.IsUnspendable()) return;
    CCoinsMap::iterator it;
    bool inserted;
    std::tie(it, inserted) = cacheCoins.emplace(std::piecewise_construct, std::forward_as_tuple(outpoint), std::tuple<>());
    bool fresh = false;
    if (!inserted) {
        cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage();
    }
    if (!possible_overwrite) {
        if (!it->second.coin.IsSpent()) {
            throw std::logic_error("Adding new coin that replaces non-pruned entry");
        }
        fresh = !(it->second.flags & CCoinsCacheEntry::DIRTY);
    }
    it->second.coin = std::move(coin);
    it->second.flags |= CCoinsCacheEntry::DIRTY | (fresh ? CCoinsCacheEntry::FRESH : 0);
    cachedCoinsUsage += it->second.coin.DynamicMemoryUsage();
}

void AddCoins(CCoinsViewCache& cache, const CTransaction &tx, int nHeight) {
    bool fCoinbase = tx.IsCoinBase();
    const uint256& txid = tx.GetHash();
    for (size_t i = 0; i < tx.vout.size(); ++i) {
        // Pass fCoinbase as the possible_overwrite flag to AddCoin, in order to correctly
        // deal with the pre-BIP30 occurrences of duplicate coinbase transactions.
        cache.AddCoin(COutPoint(txid, i), Coin(tx.vout[i], nHeight, fCoinbase), fCoinbase);
    }
}

void CCoinsViewCache::SpendCoin(const COutPoint &outpoint, Coin* moveout) {
    CCoinsMap::iterator it = FetchCoin(outpoint);
    if (it == cacheCoins.end()) return;
    cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage();
    if (moveout) {
        *moveout = std::move(it->second.coin);
    }
    if (it->second.flags & CCoinsCacheEntry::FRESH) {
        cacheCoins.erase(it);
    } else {
        it->second.flags |= CCoinsCacheEntry::DIRTY;
        it->second.coin.Clear();
    }
}

static const Coin coinEmpty;

const Coin& CCoinsViewCache::AccessCoin(const COutPoint &outpoint) const {
    CCoinsMap::const_iterator it = FetchCoin(outpoint);
    if (it == cacheCoins.end()) {
        return coinEmpty;
    } else {
        return it->second.coin;
    }
}

bool CCoinsViewCache::HaveCoin(const COutPoint &outpoint) const {
    CCoinsMap::const_iterator it = FetchCoin(outpoint);
    return (it != cacheCoins.end() && !it->second.coin.IsSpent());
}

bool CCoinsViewCache::HaveCoinInCache(const COutPoint &outpoint) const {
    CCoinsMap::const_iterator it = cacheCoins.find(outpoint);
    return it != cacheCoins.end();
}

uint256 CCoinsViewCache::GetBestBlock() const {
    if (hashBlock.IsNull())
        hashBlock = base->GetBestBlock();
    return hashBlock;
}

void CCoinsViewCache::SetBestBlock(const uint256 &hashBlockIn) {
    hashBlock = hashBlockIn;
}

bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn) {
    for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) {
        if (it->second.flags & CCoinsCacheEntry::DIRTY) { // Ignore non-dirty entries (optimization).
            CCoinsMap::iterator itUs = cacheCoins.find(it->first);
            if (itUs == cacheCoins.end()) {
                // The parent cache does not have an entry, while the child does
                // We can ignore it if it's both FRESH and pruned in the child
                if (!(it->second.flags & CCoinsCacheEntry::FRESH && it->second.coin.IsSpent())) {
                    // Otherwise we will need to create it in the parent
                    // and move the data up and mark it as dirty
                    CCoinsCacheEntry& entry = cacheCoins[it->first];
                    entry.coin = std::move(it->second.coin);
                    cachedCoinsUsage += entry.coin.DynamicMemoryUsage();
                    entry.flags = CCoinsCacheEntry::DIRTY;
                    // We can mark it FRESH in the parent if it was FRESH in the child
                    // Otherwise it might have just been flushed from the parent's cache
                    // and already exist in the grandparent
                    if (it->second.flags & CCoinsCacheEntry::FRESH)
                        entry.flags |= CCoinsCacheEntry::FRESH;
                }
            } else {
                // Assert that the child cache entry was not marked FRESH if the
                // parent cache entry has unspent outputs. If this ever happens,
                // it means the FRESH flag was misapplied and there is a logic
                // error in the calling code.
                if ((it->second.flags & CCoinsCacheEntry::FRESH) && !itUs->second.coin.IsSpent())
                    throw std::logic_error("FRESH flag misapplied to cache entry for base transaction with spendable outputs");

                // Found the entry in the parent cache
                if ((itUs->second.flags & CCoinsCacheEntry::FRESH) && it->second.coin.IsSpent()) {
                    // The grandparent does not have an entry, and the child is
                    // modified and being pruned. This means we can just delete
                    // it from the parent.
                    cachedCoinsUsage -= itUs->second.coin.DynamicMemoryUsage();
                    cacheCoins.erase(itUs);
                } else {
                    // A normal modification.
                    cachedCoinsUsage -= itUs->second.coin.DynamicMemoryUsage();
                    itUs->second.coin = std::move(it->second.coin);
                    cachedCoinsUsage += itUs->second.coin.DynamicMemoryUsage();
                    itUs->second.flags |= CCoinsCacheEntry::DIRTY;
                    // NOTE: It is possible the child has a FRESH flag here in
                    // the event the entry we found in the parent is pruned. But
                    // we must not copy that FRESH flag to the parent as that
                    // pruned state likely still needs to be communicated to the
                    // grandparent.
                }
            }
        }
        CCoinsMap::iterator itOld = it++;
        mapCoins.erase(itOld);
    }
    hashBlock = hashBlockIn;
    return true;
}

bool CCoinsViewCache::Flush() {
    bool fOk = base->BatchWrite(cacheCoins, hashBlock);
    cacheCoins.clear();
    cachedCoinsUsage = 0;
    return fOk;
}

void CCoinsViewCache::Uncache(const COutPoint& hash)
{
    CCoinsMap::iterator it = cacheCoins.find(hash);
    if (it != cacheCoins.end() && it->second.flags == 0) {
        cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage();
        cacheCoins.erase(it);
    }
}

unsigned int CCoinsViewCache::GetCacheSize() const {
    return cacheCoins.size();
}

CAmount CCoinsViewCache::GetValueIn(const CTransaction& tx) const
{
    if (tx.IsCoinBase())
        return 0;

    CAmount nResult = 0;
    for (unsigned int i = 0; i < tx.vin.size(); i++)
        nResult += AccessCoin(tx.vin[i].prevout).out.nValue;

    return nResult;
}

bool CCoinsViewCache::HaveInputs(const CTransaction& tx) const
{
    if (!tx.IsCoinBase()) {
        for (unsigned int i = 0; i < tx.vin.size(); i++) {
            if (!HaveCoin(tx.vin[i].prevout)) {
                return false;
            }
        }
    }
    return true;
}

static const size_t MAX_OUTPUTS_PER_BLOCK = MAX_BLOCK_BASE_SIZE /  ::GetSerializeSize(CTxOut(), SER_NETWORK, PROTOCOL_VERSION); // TODO: merge with similar definition in undo.h.

const Coin& AccessByTxid(const CCoinsViewCache& view, const uint256& txid)
{
    COutPoint iter(txid, 0);
    while (iter.n < MAX_OUTPUTS_PER_BLOCK) {
        const Coin& alternate = view.AccessCoin(iter);
        if (!alternate.IsSpent()) return alternate;
        ++iter.n;
    }
    return coinEmpty;
}
<|endoftext|>


<commit_before>#include<bits/stdc++.h>
#include "sg-graph.hpp"

// SG graph checks and optimizations

// These functions perform some checks on the graph to
// eliminate dead ends and unneeded functions. This will
// lead to smaller compiled files in the end. Maybe this
// will be deferred to optimization flags later on.

// The responsibilities of these functions:
// - Check if a path from input to output exists
// - Remove out_edges on nodes leading to dead ends
// - Check for cycles
// - Remove unneeded groups
//
// The checks are performed in this order. They happen
// recursively on every level, starting from the hightest
// level. This way, nothing gets executed for the groups
// that aren't needed and the user isn't bothered by
// unnecessary warnings for groups that exist, but are
// not connected.

// Different typenames are possible if a vector of derived
// class pointers is appended to a vector of base class
// pointers. This leads to ugly gcc error messages though
// if the function is used incorrectly, so I might have
// to change this.
template<typename T, typename U>
void vector_append(std::vector<T> &a, std::vector<U> &b){
    a.insert(a.end(), b.begin(), b.end());
}

template<typename T, typename U>
std::vector<T> vector_cast(std::vector<U> in){
    std::vector<T> out;
    for(auto e:in){
	out.push_back(static_cast<T>(e));
    }
    return out;
}

void reset_visited_nodes(Group* ast_node){
    for(auto n:ast_node->children_bash_nodes){
	n->visited = false;
    }
    for(auto n:ast_node->children_io_nodes){
	n->visited = false;
    }
    for(auto n:ast_node->children_instance_nodes){
	n->visited = false;
    }
    ast_node->input_node->visited = false;
    ast_node->output_node->visited = false;
}

// This function doesn't specifically check for cycles,
// but it is robust to cycles and will not result in
// undefined behaviour.
bool dfs_reaches_output(Node* n){
    if(n->visited){
	return n->needed;
    }
    n->visited = true;

    // this is needed in case of cycles. If the
    // dfs reaches this node before the function
    // has finished for this node again , we want
    // to return false for output reaching, because
    // if there is a path to the output it will
    // still be found, but we don't want the cycle
    // to incorrectly return true.
    n->needed = false;

    if (n->is_output()){
	// reached an output
	n->needed = true;
	return true;
    }

    bool reaches_output = false;
    for(auto out_edge:n->out_edges){
	reaches_output |= dfs_reaches_output(out_edge->destination);
    }

    // flag node as needed because it lies on a path from in to out.
    n->needed = reaches_output;

    return reaches_output;
}

void dfs_remove_dead_out_edges(Node* n){
    if(! n->needed){
	// don't need to do anything on unneeded nodes,
	// they'll get removed anyway.
	return;
    }

    // copy only the out edges that point to nodes that
    // are needed.
    std::vector<Edge*> new_out_edges;
    for(auto e:n->out_edges){
	if(e->destination->needed){
	    new_out_edges.push_back(e);
	}
    }
    n->out_edges = new_out_edges;
}

std::vector<Node*> cleanup_nodes_vector(std::vector<Node*> nodes){
    int i = 0;
    for(auto & n:nodes){
	if(! n->needed){
	    // base class destructor has to be virtual,
	    // otherwise this results in undefined
	    // behaviour
	    delete n;
	}else{
	    nodes[i] = n;
	    ++i;
	}
    }
    nodes.resize(i);
    return nodes;
}

void remove_unneeded_nodes(Group* ast_node){
    auto bash_nodes = cleanup_nodes_vector(vector_cast<Node*>(ast_node->children_bash_nodes));
    auto instance_nodes = cleanup_nodes_vector(vector_cast<Node*>(ast_node->children_io_nodes));
    auto io_nodes = cleanup_nodes_vector(vector_cast<Node*>(ast_node->children_instance_nodes));

}

bool check_group_connected(Group* ast_node){
    reset_visited_nodes(ast_node);

    bool connected = false;
    for(auto n:ast_node->children_io_nodes){
	if(n->is_input()){
	    connected |= dfs_reaches_output(n);
	}
    }
    connected |= dfs_reaches_output(ast_node->input_node);

    return connected;
}

void reset_group_visited(Group* current_group){
    current_group->visited = false;
    for(auto g:current_group->children_groups){
	reset_group_visited(g);
    }
}

// a group can only be instanciated from a instance
// node on the same level or one further down. The
// instanciation further down only matters if the
// group gets instanciated at least one from the
// outside. Therefore, to see if a group is needed,
// we only need to check on the same level.
void determine_groups_needed(Group* ast_node){
    for(auto n:ast_node->children_instance_nodes){
	if(n->needed){

	}
    }
}

std::string format_group_stack(std::stack<Group*> stack){
    std::vector<std::string> names;
    while(! stack.empty()){
	Group* g = stack.top();
	stack.pop();
	names.push_back(g->name);
    }

    std::reverse(names.begin(), names.end());

    return accumulate(names.begin(), names.end(), std::string("/"));
}

void print_unvisited_groups_and_nodes(std::pair<std::vector<Group*>,
				      std::vector<std::pair<Node*,std::stack<Group*> > > > unvisited){
    std::cerr<<"WARNING: some nodes and groups are not used:\n";
    for(auto g:unvisited.first ){
	std::cerr<<"    Group " << g->name << "\n";
    }
    for(auto n:unvisited.second ){
	std::cerr<<"    Node " << format_group_stack(n.second) << "/" <<  n.first->name << "\n";
    }
}

// This function will traverse the DAG to check
// if input to output is connected.
// If fail_on_warn is set, the function will
// treat a warning (unused node) as error.
bool traversal(Group* ast_root, bool fail_on_warn){
    return true;
}
<commit_msg>Rewrote cleanup_nodes_vector as template<commit_after>#include<bits/stdc++.h>
#include "sg-graph.hpp"

// SG graph checks and optimizations

// These functions perform some checks on the graph to
// eliminate dead ends and unneeded functions. This will
// lead to smaller compiled files in the end. Maybe this
// will be deferred to optimization flags later on.

// The responsibilities of these functions:
// - Check if a path from input to output exists
// - Remove out_edges on nodes leading to dead ends
// - Check for cycles
// - Remove unneeded groups
//
// The checks are performed in this order. They happen
// recursively on every level, starting from the hightest
// level. This way, nothing gets executed for the groups
// that aren't needed and the user isn't bothered by
// unnecessary warnings for groups that exist, but are
// not connected.

// Different typenames are possible if a vector of derived
// class pointers is appended to a vector of base class
// pointers. This leads to ugly gcc error messages though
// if the function is used incorrectly, so I might have
// to change this.
template<typename T, typename U>
void vector_append(std::vector<T> &a, std::vector<U> &b){
    a.insert(a.end(), b.begin(), b.end());
}

// might be deleted, as it's not needed right now, but
// maybe in the fututre
template<typename T, typename U>
std::vector<T> vector_cast(std::vector<U> in){
    std::vector<T> out;
    for(auto e:in){
	out.push_back(static_cast<T>(e));
    }
    return out;
}

void reset_visited_nodes(Group* ast_node){
    for(auto n:ast_node->children_bash_nodes){
	n->visited = false;
    }
    for(auto n:ast_node->children_io_nodes){
	n->visited = false;
    }
    for(auto n:ast_node->children_instance_nodes){
	n->visited = false;
    }
    ast_node->input_node->visited = false;
    ast_node->output_node->visited = false;
}

// This function doesn't specifically check for cycles,
// but it is robust to cycles and will not result in
// undefined behaviour.
bool dfs_reaches_output(Node* n){
    if(n->visited){
	return n->needed;
    }
    n->visited = true;

    // this is needed in case of cycles. If the
    // dfs reaches this node before the function
    // has finished for this node again , we want
    // to return false for output reaching, because
    // if there is a path to the output it will
    // still be found, but we don't want the cycle
    // to incorrectly return true.
    n->needed = false;

    if (n->is_output()){
	// reached an output
	n->needed = true;
	return true;
    }

    bool reaches_output = false;
    for(auto out_edge:n->out_edges){
	reaches_output |= dfs_reaches_output(out_edge->destination);
    }

    // flag node as needed because it lies on a path from in to out.
    n->needed = reaches_output;

    return reaches_output;
}

void dfs_remove_dead_out_edges(Node* n){
    if(! n->needed){
	// don't need to do anything on unneeded nodes,
	// they'll get removed anyway.
	return;
    }

    // copy only the out edges that point to nodes that
    // are needed.
    std::vector<Edge*> new_out_edges;
    for(auto e:n->out_edges){
	if(e->destination->needed){
	    new_out_edges.push_back(e);
	}
    }
    n->out_edges = new_out_edges;
}

// T should be a derived node like Bash_node
template<typename T>
void cleanup_nodes_vector(std::vector<T*> & nodes){
    int i = 0;
    for(auto & n:nodes){
	if(! n->needed){
	    // base class destructor has to be virtual,
	    // otherwise this results in undefined
	    // behaviour
	    delete n;
	}else{
	    nodes[i] = n;
	    ++i;
	}
    }
    nodes.resize(i);
}

// This function has to be called after dfs_remove_dead_out_edges,
// because otherwise the pointers in the out_edges vector might
// refer to deleted objects.
void remove_unneeded_nodes(Group* ast_node){
    cleanup_nodes_vector(ast_node->children_bash_nodes);
    cleanup_nodes_vector(ast_node->children_instance_nodes);
    cleanup_nodes_vector(ast_node->children_io_nodes);
    if( ! ast_node->input_node->needed ){
	delete ast_node->input_node;
	ast_node->input_node = 0;
    }
    if( ! ast_node->output_node->needed ){
	delete ast_node->output_node;
	ast_node->output_node = 0;
    }
}

bool check_group_connected(Group* ast_node){
    reset_visited_nodes(ast_node);

    bool connected = false;
    for(auto n:ast_node->children_io_nodes){
	if(n->is_input()){
	    connected |= dfs_reaches_output(n);
	}
    }
    connected |= dfs_reaches_output(ast_node->input_node);

    return connected;
}

void reset_group_visited(Group* current_group){
    current_group->visited = false;
    for(auto g:current_group->children_groups){
	reset_group_visited(g);
    }
}

// a group can only be instanciated from a instance
// node on the same level or one further down. The
// instanciation further down only matters if the
// group gets instanciated at least one from the
// outside. Therefore, to see if a group is needed,
// we only need to check on the same level.
void determine_groups_needed(Group* ast_node){
    for(auto n:ast_node->children_instance_nodes){
	if(n->needed){

	}
    }
}

std::string format_group_stack(std::stack<Group*> stack){
    std::vector<std::string> names;
    while(! stack.empty()){
	Group* g = stack.top();
	stack.pop();
	names.push_back(g->name);
    }

    std::reverse(names.begin(), names.end());

    return accumulate(names.begin(), names.end(), std::string("/"));
}

void print_unvisited_groups_and_nodes(std::pair<std::vector<Group*>,
				      std::vector<std::pair<Node*,std::stack<Group*> > > > unvisited){
    std::cerr<<"WARNING: some nodes and groups are not used:\n";
    for(auto g:unvisited.first ){
	std::cerr<<"    Group " << g->name << "\n";
    }
    for(auto n:unvisited.second ){
	std::cerr<<"    Node " << format_group_stack(n.second) << "/" <<  n.first->name << "\n";
    }
}

// This function will traverse the DAG to check
// if input to output is connected.
// If fail_on_warn is set, the function will
// treat a warning (unused node) as error.
bool traversal(Group* ast_root, bool fail_on_warn){
    return true;
}
<|endoftext|>


<commit_before>/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */

/*
 *  Main authors:
 *     Guido Tack <guido.tack@monash.edu>
 */

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef __MINIZINC_HASH_HH__
#define __MINIZINC_HASH_HH__

#include <minizinc/ast.hh>

#include <unordered_map>
#include <unordered_set>

namespace MiniZinc {

  /// Hash class for expressions
  struct ExpressionHash {
    size_t operator() (const Expression* e) const {
      return Expression::hash(e);
    }
  };

  /// Equality test for expressions
  struct ExpressionEq {
    bool operator() (const Expression* e0, const Expression* e1) const {
      return Expression::equal(e0,e1);
    }
  };

  /// Hash map from expression to \a T
  template<class T>
  class ExpressionMap {
  protected:
    /// The underlying map implementation
    std::unordered_map<Expression*,T,ExpressionHash,ExpressionEq> _m;
  public:
    /// Iterator type
    typedef typename std::unordered_map<Expression*,T,
      ExpressionHash,ExpressionEq>::iterator iterator;
    /// Insert mapping from \a e to \a t
    void insert(Expression* e, const T& t) {
      assert(e != NULL);
      _m.insert(std::pair<Expression*,T>(e,t));
    }
    /// Find \a e in map
    iterator find(Expression* e) { return _m.find(e); }
    /// Begin of iterator
    iterator begin(void) { return _m.begin(); }
    /// End of iterator
    iterator end(void) { return _m.end(); }
    /// Remove binding of \a e from map
    void remove(Expression* e) {
      _m.erase(e);
    }
    /// Remove all elements from the map
    void clear(void) {
      _m.clear();
    }
  };

  /// Hash class for KeepAlive objects
  struct KAHash {
    size_t operator() (const KeepAlive& e) const {
      return Expression::hash(e());
    }
  };

  /// Equality test for KeepAlive objects
  struct KAEq {
    bool operator() (const KeepAlive& e0, const KeepAlive& e1) const {
      return Expression::equal(e0(),e1());
    }
  };

  /// Hash map from KeepAlive to \a T
  template<class T>
  class KeepAliveMap {
  protected:
    /// The underlying map implementation
    std::unordered_map<KeepAlive,T,KAHash,KAEq> _m;
  public:
    /// Iterator type
    typedef typename std::unordered_map<KeepAlive,T,
      KAHash,KAEq>::iterator iterator;
    /// Insert mapping from \a e to \a t
    void insert(KeepAlive& e, const T& t) {
      assert(e() != NULL);
      _m.insert(std::pair<KeepAlive,T>(e,t));
    }
    /// Find \a e in map
    iterator find(KeepAlive& e) { return _m.find(e); }
    /// Begin of iterator
    iterator begin(void) { return _m.begin(); }
    /// End of iterator
    iterator end(void) { return _m.end(); }
    /// Remove binding of \a e from map
    void remove(KeepAlive& e) {
      _m.erase(e);
    }
    template <class D> void dump(void) {
      for (auto i: _m) {
        std::cerr << i.first() << ": " << D::d(i.second) << std::endl;
      }
    }
  };

  class ExpressionSetIter : public std::unordered_set<Expression*,ExpressionHash,ExpressionEq>::iterator {
  protected:
    bool _empty;
    typedef std::unordered_set<Expression*,ExpressionHash,ExpressionEq>::iterator Iter;
  public:
    ExpressionSetIter(void) : _empty(false) {}
    ExpressionSetIter(bool) : _empty(true) {}
    ExpressionSetIter(const Iter& i) : Iter(i), _empty(false) {}
    bool operator ==(const ExpressionSetIter& i) const {
      return (_empty && i._empty) || static_cast<const Iter&>(*this)==static_cast<const Iter&>(i);
    }
  };

  /// Hash set for expressions
  class ExpressionSet {
  protected:
    /// The underlying set implementation
    std::unordered_set<Expression*,ExpressionHash,ExpressionEq> _s;
  public:
    /// Insert \a e
    void insert(Expression* e) {
      assert(e != NULL);
      _s.insert(e);
    }
    /// Find \a e in map
    ExpressionSetIter find(Expression* e) { return _s.find(e); }
    /// Begin of iterator
    ExpressionSetIter begin(void) { return _s.begin(); }
    /// End of iterator
    ExpressionSetIter end(void) { return _s.end(); }
    /// Remove binding of \a e from map
    void remove(Expression* e) {
      _s.erase(e);
    }
    bool contains(Expression* e) { return find(e) != end(); }
    /// Remove all elements from the map
    void clear(void) {
      _s.clear();
    }
    bool isEmpty(void) const { return _s.begin() == _s.end(); }
  };

}

#endif
<commit_msg>Need != operator in addition to ==<commit_after>/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */

/*
 *  Main authors:
 *     Guido Tack <guido.tack@monash.edu>
 */

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef __MINIZINC_HASH_HH__
#define __MINIZINC_HASH_HH__

#include <minizinc/ast.hh>

#include <unordered_map>
#include <unordered_set>

namespace MiniZinc {

  /// Hash class for expressions
  struct ExpressionHash {
    size_t operator() (const Expression* e) const {
      return Expression::hash(e);
    }
  };

  /// Equality test for expressions
  struct ExpressionEq {
    bool operator() (const Expression* e0, const Expression* e1) const {
      return Expression::equal(e0,e1);
    }
  };

  /// Hash map from expression to \a T
  template<class T>
  class ExpressionMap {
  protected:
    /// The underlying map implementation
    std::unordered_map<Expression*,T,ExpressionHash,ExpressionEq> _m;
  public:
    /// Iterator type
    typedef typename std::unordered_map<Expression*,T,
      ExpressionHash,ExpressionEq>::iterator iterator;
    /// Insert mapping from \a e to \a t
    void insert(Expression* e, const T& t) {
      assert(e != NULL);
      _m.insert(std::pair<Expression*,T>(e,t));
    }
    /// Find \a e in map
    iterator find(Expression* e) { return _m.find(e); }
    /// Begin of iterator
    iterator begin(void) { return _m.begin(); }
    /// End of iterator
    iterator end(void) { return _m.end(); }
    /// Remove binding of \a e from map
    void remove(Expression* e) {
      _m.erase(e);
    }
    /// Remove all elements from the map
    void clear(void) {
      _m.clear();
    }
  };

  /// Hash class for KeepAlive objects
  struct KAHash {
    size_t operator() (const KeepAlive& e) const {
      return Expression::hash(e());
    }
  };

  /// Equality test for KeepAlive objects
  struct KAEq {
    bool operator() (const KeepAlive& e0, const KeepAlive& e1) const {
      return Expression::equal(e0(),e1());
    }
  };

  /// Hash map from KeepAlive to \a T
  template<class T>
  class KeepAliveMap {
  protected:
    /// The underlying map implementation
    std::unordered_map<KeepAlive,T,KAHash,KAEq> _m;
  public:
    /// Iterator type
    typedef typename std::unordered_map<KeepAlive,T,
      KAHash,KAEq>::iterator iterator;
    /// Insert mapping from \a e to \a t
    void insert(KeepAlive& e, const T& t) {
      assert(e() != NULL);
      _m.insert(std::pair<KeepAlive,T>(e,t));
    }
    /// Find \a e in map
    iterator find(KeepAlive& e) { return _m.find(e); }
    /// Begin of iterator
    iterator begin(void) { return _m.begin(); }
    /// End of iterator
    iterator end(void) { return _m.end(); }
    /// Remove binding of \a e from map
    void remove(KeepAlive& e) {
      _m.erase(e);
    }
    template <class D> void dump(void) {
      for (auto i: _m) {
        std::cerr << i.first() << ": " << D::d(i.second) << std::endl;
      }
    }
  };

  class ExpressionSetIter : public std::unordered_set<Expression*,ExpressionHash,ExpressionEq>::iterator {
  protected:
    bool _empty;
    typedef std::unordered_set<Expression*,ExpressionHash,ExpressionEq>::iterator Iter;
  public:
    ExpressionSetIter(void) : _empty(false) {}
    ExpressionSetIter(bool) : _empty(true) {}
    ExpressionSetIter(const Iter& i) : Iter(i), _empty(false) {}
    bool operator ==(const ExpressionSetIter& i) const {
      return (_empty && i._empty) || static_cast<const Iter&>(*this)==static_cast<const Iter&>(i);
    }
    bool operator !=(const ExpressionSetIter& i) const {
      return !operator ==(i);
    }
  };

  /// Hash set for expressions
  class ExpressionSet {
  protected:
    /// The underlying set implementation
    std::unordered_set<Expression*,ExpressionHash,ExpressionEq> _s;
  public:
    /// Insert \a e
    void insert(Expression* e) {
      assert(e != NULL);
      _s.insert(e);
    }
    /// Find \a e in map
    ExpressionSetIter find(Expression* e) { return _s.find(e); }
    /// Begin of iterator
    ExpressionSetIter begin(void) { return _s.begin(); }
    /// End of iterator
    ExpressionSetIter end(void) { return _s.end(); }
    /// Remove binding of \a e from map
    void remove(Expression* e) {
      _s.erase(e);
    }
    bool contains(Expression* e) { return find(e) != end(); }
    /// Remove all elements from the map
    void clear(void) {
      _s.clear();
    }
    bool isEmpty(void) const { return _s.begin() == _s.end(); }
  };

}

#endif
<|endoftext|>


<commit_before>#include <unistd.h>
#include <signal.h>
#include <dirent.h>
#include <fcntl.h>
#include <time.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sstream>
#include <iomanip>
#include "checker/checker.hpp"

int checker::compile(
    std::string const &compile_script_filename,
    std::string const &solution_filename,
    std::string const &compiled_filename
){
	pid_t childpid = fork();
	if(childpid == -1)
		return -1;
	if(childpid == 0)
	{
		if(descriptor_setup() != 0)
			exit(-1);
		execl(compile_script_filename.c_str(), compile_script_filename.c_str(), solution_filename.c_str(), compiled_filename.c_str(), NULL);
		exit(-1);
	}
	int status;
	for(int i = 0; i < 12; ++i) // wait 12 * 5 == 60 seconds
	{
		sleep(5);
		int result = waitpid(childpid, &status, WNOHANG);
		if(result != -1)
		{
			if(!WIFEXITED(status))
				return -1;
			return WEXITSTATUS(status);
		}
	}
	// compilation is longer than 60 seconds, kill it with fire
	kill(childpid, SIGKILL);
	return -1;
}
test_result checker::test_solution(
    std::string const &submissionid,
    std::string const &solution_filename,
    std::string const &run_script_filename,
    test_data const &test){
	std::stringstream ss;
	ss.str(test.timelimit);
	int timelimit;
	ss >> timelimit;
	ss.str(test.memlimit);
	int memlimit;
	ss >> memlimit;
	struct timespec tim;
	clock_gettime(CLOCK_MONOTONIC, &tim);
	long timetaken = tim.tv_nsec;
	pid_t childpid = fork();
	if(childpid == -1)
		return test_result(submissionid, "INT", test.testid, "0.00");
	if(childpid == 0)
	{
		if(descriptor_setup() != 0)
			exit(-1);
		struct rlimit lim;
		lim.rlim_cur = memlimit * 1024 * 1024;
		lim.rlim_max = memlimit * 1024 * 1024;
		setrlimit(RLIMIT_AS, &lim);
		lim.rlim_cur = 1024 * 1024 * 1024;
		lim.rlim_max = 1024 * 1024 * 1024;
		setrlimit(RLIMIT_FSIZE, &lim);
		lim.rlim_cur = timelimit;
		lim.rlim_max = timelimit + 1;
		setrlimit(RLIMIT_CPU, &lim);
		execl(run_script_filename.c_str(), run_script_filename.c_str(), solution_filename.c_str(), test.infilename.c_str(), "tmpresult", NULL);
		exit(-1);
	}
	int result, status;
	do
	{
		result = waitpid(childpid, &status, 0);
	} while(result == -1 && errno == EINTR);
	clock_gettime(CLOCK_MONOTONIC, &tim);
	timetaken = tim.tv_nsec - timetaken;
	ss.str(std::string());
	ss << std::fixed << std::setprecision(2) << timetaken / 1000000.;
	if(WIFSIGNALED(status))
	{
		if(WTERMSIG(status) == SIGXCPU)
			return test_result(submissionid, "TLE", test.testid, ss.str());
		return test_result(submissionid, "RTE", test.testid, ss.str());
	}
	if(WEXITSTATUS(status) != 0)
		return test_result(submissionid, "RTE", test.testid, ss.str());
	childpid = fork();
	if(childpid == -1)
		return test_result(submissionid, "INT", test.testid, "0.00");
	if(childpid == 0)
	{
		if(descriptor_setup() != 0)
			exit(-1);
		execlp("diff", "diff", "-bq", "tmpresult", "outfilename", NULL);
		exit(-1);
	}
	do
	{
		result = waitpid(childpid, &status, 0);
	} while(result == -1 && errno == EINTR);
	if(WIFSIGNALED(status) || (WEXITSTATUS(status) != 0 && WEXITSTATUS(status) != 1))
		return test_result(submissionid, "INT", test.testid, ss.str());
	if(WEXITSTATUS(status) == 1)
		return test_result(submissionid, "ANS", test.testid, ss.str());
	return test_result(submissionid, "OK", test.testid, ss.str());
}

int checker::descriptor_setup(){
	DIR* dirp = opendir("/proc/self/fd");
	if(dirp == NULL)
		return -1;
	int fd = dirfd(dirp);
	while(true)
	{
		struct dirent* direntp = readdir(dirp);
		if(direntp == NULL)
			break;
		else if(direntp->d_name[0] == '.')
			continue;
		std::istringstream ss;
		ss.str(direntp->d_name);
		int closfd;
		ss >> closfd;
		if(closfd != fd)
			close(closfd);
	}
	closedir(dirp);
	int infd = open("/dev/null", O_RDONLY);
	if(infd != 0)
	{
		dup2(infd, 0);
		close(infd);
	}
	int outfd = open("/dev/null", O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU | S_IRWXG | S_IRWXO);
	if(outfd != 1)
	{
		dup2(outfd, 1);
		close(outfd);
	}
	dup2(1, 2);
	return 0;
}
<commit_msg>Quite significant typo fixed.<commit_after>#include <unistd.h>
#include <signal.h>
#include <dirent.h>
#include <fcntl.h>
#include <time.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sstream>
#include <iomanip>
#include "checker/checker.hpp"

int checker::compile(
    std::string const &compile_script_filename,
    std::string const &solution_filename,
    std::string const &compiled_filename
){
	pid_t childpid = fork();
	if(childpid == -1)
		return -1;
	if(childpid == 0)
	{
		if(descriptor_setup() != 0)
			exit(-1);
		execl(compile_script_filename.c_str(), compile_script_filename.c_str(), solution_filename.c_str(), compiled_filename.c_str(), NULL);
		exit(-1);
	}
	int status;
	for(int i = 0; i < 12; ++i) // wait 12 * 5 == 60 seconds
	{
		sleep(5);
		int result = waitpid(childpid, &status, WNOHANG);
		if(result != -1)
		{
			if(!WIFEXITED(status))
				return -1;
			return WEXITSTATUS(status);
		}
	}
	// compilation is longer than 60 seconds, kill it with fire
	kill(childpid, SIGKILL);
	return -1;
}
test_result checker::test_solution(
    std::string const &submissionid,
    std::string const &solution_filename,
    std::string const &run_script_filename,
    test_data const &test){
	std::stringstream ss;
	ss.str(test.timelimit);
	int timelimit;
	ss >> timelimit;
	ss.str(test.memlimit);
	int memlimit;
	ss >> memlimit;
	struct timespec tim;
	clock_gettime(CLOCK_MONOTONIC, &tim);
	long timetaken = tim.tv_nsec;
	pid_t childpid = fork();
	if(childpid == -1)
		return test_result(submissionid, "INT", test.testid, "0.00");
	if(childpid == 0)
	{
		if(descriptor_setup() != 0)
			exit(-1);
		struct rlimit lim;
		lim.rlim_cur = memlimit * 1024 * 1024;
		lim.rlim_max = memlimit * 1024 * 1024;
		setrlimit(RLIMIT_AS, &lim);
		lim.rlim_cur = 1024 * 1024 * 1024;
		lim.rlim_max = 1024 * 1024 * 1024;
		setrlimit(RLIMIT_FSIZE, &lim);
		lim.rlim_cur = timelimit;
		lim.rlim_max = timelimit + 1;
		setrlimit(RLIMIT_CPU, &lim);
		execl(run_script_filename.c_str(), run_script_filename.c_str(), solution_filename.c_str(), test.infilename.c_str(), "tmpresult", NULL);
		exit(-1);
	}
	int result, status;
	do
	{
		result = waitpid(childpid, &status, 0);
	} while(result == -1 && errno == EINTR);
	clock_gettime(CLOCK_MONOTONIC, &tim);
	timetaken = tim.tv_nsec - timetaken;
	ss.str(std::string());
	ss << std::fixed << std::setprecision(2) << timetaken / 1000000.;
	if(WIFSIGNALED(status))
	{
		if(WTERMSIG(status) == SIGXCPU)
			return test_result(submissionid, "TLE", test.testid, ss.str());
		return test_result(submissionid, "RTE", test.testid, ss.str());
	}
	if(WEXITSTATUS(status) != 0)
		return test_result(submissionid, "RTE", test.testid, ss.str());
	childpid = fork();
	if(childpid == -1)
		return test_result(submissionid, "INT", test.testid, "0.00");
	if(childpid == 0)
	{
		if(descriptor_setup() != 0)
			exit(-1);
		execlp("diff", "diff", "-bq", "tmpresult", test.outfilename.c_str(), NULL);
		exit(-1);
	}
	do
	{
		result = waitpid(childpid, &status, 0);
	} while(result == -1 && errno == EINTR);
	if(WIFSIGNALED(status) || (WEXITSTATUS(status) != 0 && WEXITSTATUS(status) != 1))
		return test_result(submissionid, "INT", test.testid, ss.str());
	if(WEXITSTATUS(status) == 1)
		return test_result(submissionid, "ANS", test.testid, ss.str());
	return test_result(submissionid, "OK", test.testid, ss.str());
}

int checker::descriptor_setup(){
	DIR* dirp = opendir("/proc/self/fd");
	if(dirp == NULL)
		return -1;
	int fd = dirfd(dirp);
	while(true)
	{
		struct dirent* direntp = readdir(dirp);
		if(direntp == NULL)
			break;
		else if(direntp->d_name[0] == '.')
			continue;
		std::istringstream ss;
		ss.str(direntp->d_name);
		int closfd;
		ss >> closfd;
		if(closfd != fd)
			close(closfd);
	}
	closedir(dirp);
	int infd = open("/dev/null", O_RDONLY);
	if(infd != 0)
	{
		dup2(infd, 0);
		close(infd);
	}
	int outfd = open("/dev/null", O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU | S_IRWXG | S_IRWXO);
	if(outfd != 1)
	{
		dup2(outfd, 1);
		close(outfd);
	}
	dup2(1, 2);
	return 0;
}
<|endoftext|>


<commit_before>/*
 * Copyright 2016 WebAssembly Community Group participants
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "common.h"

#include <assert.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <limits.h>

#if COMPILER_IS_MSVC
#include <fcntl.h>
#include <io.h>
#include <stdlib.h>
#define PATH_MAX _MAX_PATH
#endif

namespace wabt {

OpcodeInfo g_opcode_info[kOpcodeCount];

/* TODO(binji): It's annoying to have to have an initializer function, but it
 * seems to be necessary as g++ doesn't allow non-trival designated
 * initializers (e.g. [314] = "blah") */
void init_opcode_info(void) {
  static bool s_initialized = false;
  if (!s_initialized) {
#define V(rtype, type1, type2, mem_size, code, NAME, text) \
  g_opcode_info[code].name = text;                         \
  g_opcode_info[code].result_type = Type::rtype;           \
  g_opcode_info[code].param1_type = Type::type1;           \
  g_opcode_info[code].param2_type = Type::type2;           \
  g_opcode_info[code].memory_size = mem_size;

    WABT_FOREACH_OPCODE(V)

#undef V
  }
}

const char* g_kind_name[] = {"func", "table", "memory", "global"};
WABT_STATIC_ASSERT(WABT_ARRAY_SIZE(g_kind_name) == kExternalKindCount);

const char* g_reloc_type_name[] = {"R_FUNC_INDEX_LEB", "R_TABLE_INDEX_SLEB",
                                   "R_TABLE_INDEX_I32", "R_GLOBAL_INDEX_LEB",
                                   "R_DATA"};
WABT_STATIC_ASSERT(WABT_ARRAY_SIZE(g_reloc_type_name) == kRelocTypeCount);

bool is_naturally_aligned(Opcode opcode, uint32_t alignment) {
  uint32_t opcode_align = get_opcode_memory_size(opcode);
  return alignment == WABT_USE_NATURAL_ALIGNMENT || alignment == opcode_align;
}

uint32_t get_opcode_alignment(Opcode opcode, uint32_t alignment) {
  if (alignment == WABT_USE_NATURAL_ALIGNMENT)
    return get_opcode_memory_size(opcode);
  return alignment;
}

StringSlice empty_string_slice(void) {
  StringSlice result;
  result.start = "";
  result.length = 0;
  return result;
}

bool string_slice_eq_cstr(const StringSlice* s1, const char* s2) {
  size_t s2_len = strlen(s2);
  if (s2_len != s1->length)
    return false;

  return strncmp(s1->start, s2, s2_len) == 0;
}

bool string_slice_startswith(const StringSlice* s1, const char* s2) {
  size_t s2_len = strlen(s2);
  if (s2_len > s1->length)
    return false;

  return strncmp(s1->start, s2, s2_len) == 0;
}

StringSlice string_slice_from_cstr(const char* string) {
  StringSlice result;
  result.start = string;
  result.length = strlen(string);
  return result;
}

bool string_slice_is_empty(const StringSlice* str) {
  assert(str);
  return !str->start || str->length == 0;
}

bool string_slices_are_equal(const StringSlice* a, const StringSlice* b) {
  assert(a && b);
  return a->start && b->start && a->length == b->length &&
         memcmp(a->start, b->start, a->length) == 0;
}

void destroy_string_slice(StringSlice* str) {
  assert(str);
  delete [] str->start;
}

Result read_file(const char* filename, char** out_data, size_t* out_size) {
  FILE* infile = fopen(filename, "rb");
  if (!infile) {
    const char* format = "unable to read file %s";
    char msg[PATH_MAX + sizeof(format)];
    wabt_snprintf(msg, sizeof(msg), format, filename);
    perror(msg);
    return Result::Error;
  }

  if (fseek(infile, 0, SEEK_END) < 0) {
    perror("fseek to end failed");
    return Result::Error;
  }

  long size = ftell(infile);
  if (size < 0) {
    perror("ftell failed");
    return Result::Error;
  }

  if (fseek(infile, 0, SEEK_SET) < 0) {
    perror("fseek to beginning failed");
    return Result::Error;
  }

  char* data = new char [size];
  if (size != 0 && fread(data, size, 1, infile) != 1) {
    perror("fread failed");
    return Result::Error;
  }

  *out_data = data;
  *out_size = size;
  fclose(infile);
  return Result::Ok;
}

static void print_carets(FILE* out,
                         size_t num_spaces,
                         size_t num_carets,
                         size_t max_line) {
  /* print the caret */
  char* carets = static_cast<char*>(alloca(max_line));
  memset(carets, '^', max_line);
  if (num_carets > max_line - num_spaces)
    num_carets = max_line - num_spaces;
  /* always print at least one caret */
  if (num_carets == 0)
    num_carets = 1;
  fprintf(out, "%*s%.*s\n", static_cast<int>(num_spaces), "",
          static_cast<int>(num_carets), carets);
}

static void print_source_error(FILE* out,
                               const Location* loc,
                               const char* error,
                               const char* source_line,
                               size_t source_line_length,
                               size_t source_line_column_offset) {
  fprintf(out, "%s:%d:%d: %s\n", loc->filename, loc->line, loc->first_column,
          error);
  if (source_line && source_line_length > 0) {
    fprintf(out, "%s\n", source_line);
    size_t num_spaces = (loc->first_column - 1) - source_line_column_offset;
    size_t num_carets = loc->last_column - loc->first_column;
    print_carets(out, num_spaces, num_carets, source_line_length);
  }
}

static void print_error_header(FILE* out, DefaultErrorHandlerInfo* info) {
  if (info && info->header) {
    switch (info->print_header) {
      case PrintErrorHeader::Never:
        break;

      case PrintErrorHeader::Once:
        info->print_header = PrintErrorHeader::Never;
      /* Fallthrough. */

      case PrintErrorHeader::Always:
        fprintf(out, "%s:\n", info->header);
        break;
    }
    /* If there's a header, indent the following message. */
    fprintf(out, "  ");
  }
}

static FILE* get_default_error_handler_info_output_file(
    DefaultErrorHandlerInfo* info) {
  return info && info->out_file ? info->out_file : stderr;
}

void default_source_error_callback(const Location* loc,
                                   const char* error,
                                   const char* source_line,
                                   size_t source_line_length,
                                   size_t source_line_column_offset,
                                   void* user_data) {
  DefaultErrorHandlerInfo* info =
      static_cast<DefaultErrorHandlerInfo*>(user_data);
  FILE* out = get_default_error_handler_info_output_file(info);
  print_error_header(out, info);
  print_source_error(out, loc, error, source_line, source_line_length,
                     source_line_column_offset);
}

void default_binary_error_callback(uint32_t offset,
                                   const char* error,
                                   void* user_data) {
  DefaultErrorHandlerInfo* info =
      static_cast<DefaultErrorHandlerInfo*>(user_data);
  FILE* out = get_default_error_handler_info_output_file(info);
  print_error_header(out, info);
  if (offset == WABT_UNKNOWN_OFFSET)
    fprintf(out, "error: %s\n", error);
  else
    fprintf(out, "error: @0x%08x: %s\n", offset, error);
  fflush(out);
}

void init_stdio() {
#if COMPILER_IS_MSVC
  int result = _setmode(_fileno(stdout), _O_BINARY);
  if (result == -1)
    perror("Cannot set mode binary to stdout");
  result = _setmode(_fileno(stderr), _O_BINARY);
  if (result == -1)
    perror("Cannot set mode binary to stderr");
#endif
}

}  // namespace wabt
<commit_msg>use array of chars instead of pointer to chars so sizeof is correct (#345)<commit_after>/*
 * Copyright 2016 WebAssembly Community Group participants
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "common.h"

#include <assert.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <limits.h>

#if COMPILER_IS_MSVC
#include <fcntl.h>
#include <io.h>
#include <stdlib.h>
#define PATH_MAX _MAX_PATH
#endif

namespace wabt {

OpcodeInfo g_opcode_info[kOpcodeCount];

/* TODO(binji): It's annoying to have to have an initializer function, but it
 * seems to be necessary as g++ doesn't allow non-trival designated
 * initializers (e.g. [314] = "blah") */
void init_opcode_info(void) {
  static bool s_initialized = false;
  if (!s_initialized) {
#define V(rtype, type1, type2, mem_size, code, NAME, text) \
  g_opcode_info[code].name = text;                         \
  g_opcode_info[code].result_type = Type::rtype;           \
  g_opcode_info[code].param1_type = Type::type1;           \
  g_opcode_info[code].param2_type = Type::type2;           \
  g_opcode_info[code].memory_size = mem_size;

    WABT_FOREACH_OPCODE(V)

#undef V
  }
}

const char* g_kind_name[] = {"func", "table", "memory", "global"};
WABT_STATIC_ASSERT(WABT_ARRAY_SIZE(g_kind_name) == kExternalKindCount);

const char* g_reloc_type_name[] = {"R_FUNC_INDEX_LEB", "R_TABLE_INDEX_SLEB",
                                   "R_TABLE_INDEX_I32", "R_GLOBAL_INDEX_LEB",
                                   "R_DATA"};
WABT_STATIC_ASSERT(WABT_ARRAY_SIZE(g_reloc_type_name) == kRelocTypeCount);

bool is_naturally_aligned(Opcode opcode, uint32_t alignment) {
  uint32_t opcode_align = get_opcode_memory_size(opcode);
  return alignment == WABT_USE_NATURAL_ALIGNMENT || alignment == opcode_align;
}

uint32_t get_opcode_alignment(Opcode opcode, uint32_t alignment) {
  if (alignment == WABT_USE_NATURAL_ALIGNMENT)
    return get_opcode_memory_size(opcode);
  return alignment;
}

StringSlice empty_string_slice(void) {
  StringSlice result;
  result.start = "";
  result.length = 0;
  return result;
}

bool string_slice_eq_cstr(const StringSlice* s1, const char* s2) {
  size_t s2_len = strlen(s2);
  if (s2_len != s1->length)
    return false;

  return strncmp(s1->start, s2, s2_len) == 0;
}

bool string_slice_startswith(const StringSlice* s1, const char* s2) {
  size_t s2_len = strlen(s2);
  if (s2_len > s1->length)
    return false;

  return strncmp(s1->start, s2, s2_len) == 0;
}

StringSlice string_slice_from_cstr(const char* string) {
  StringSlice result;
  result.start = string;
  result.length = strlen(string);
  return result;
}

bool string_slice_is_empty(const StringSlice* str) {
  assert(str);
  return !str->start || str->length == 0;
}

bool string_slices_are_equal(const StringSlice* a, const StringSlice* b) {
  assert(a && b);
  return a->start && b->start && a->length == b->length &&
         memcmp(a->start, b->start, a->length) == 0;
}

void destroy_string_slice(StringSlice* str) {
  assert(str);
  delete [] str->start;
}

Result read_file(const char* filename, char** out_data, size_t* out_size) {
  FILE* infile = fopen(filename, "rb");
  if (!infile) {
    const char format[] = "unable to read file %s";
    char msg[PATH_MAX + sizeof(format)];
    wabt_snprintf(msg, sizeof(msg), format, filename);
    perror(msg);
    return Result::Error;
  }

  if (fseek(infile, 0, SEEK_END) < 0) {
    perror("fseek to end failed");
    return Result::Error;
  }

  long size = ftell(infile);
  if (size < 0) {
    perror("ftell failed");
    return Result::Error;
  }

  if (fseek(infile, 0, SEEK_SET) < 0) {
    perror("fseek to beginning failed");
    return Result::Error;
  }

  char* data = new char [size];
  if (size != 0 && fread(data, size, 1, infile) != 1) {
    perror("fread failed");
    return Result::Error;
  }

  *out_data = data;
  *out_size = size;
  fclose(infile);
  return Result::Ok;
}

static void print_carets(FILE* out,
                         size_t num_spaces,
                         size_t num_carets,
                         size_t max_line) {
  /* print the caret */
  char* carets = static_cast<char*>(alloca(max_line));
  memset(carets, '^', max_line);
  if (num_carets > max_line - num_spaces)
    num_carets = max_line - num_spaces;
  /* always print at least one caret */
  if (num_carets == 0)
    num_carets = 1;
  fprintf(out, "%*s%.*s\n", static_cast<int>(num_spaces), "",
          static_cast<int>(num_carets), carets);
}

static void print_source_error(FILE* out,
                               const Location* loc,
                               const char* error,
                               const char* source_line,
                               size_t source_line_length,
                               size_t source_line_column_offset) {
  fprintf(out, "%s:%d:%d: %s\n", loc->filename, loc->line, loc->first_column,
          error);
  if (source_line && source_line_length > 0) {
    fprintf(out, "%s\n", source_line);
    size_t num_spaces = (loc->first_column - 1) - source_line_column_offset;
    size_t num_carets = loc->last_column - loc->first_column;
    print_carets(out, num_spaces, num_carets, source_line_length);
  }
}

static void print_error_header(FILE* out, DefaultErrorHandlerInfo* info) {
  if (info && info->header) {
    switch (info->print_header) {
      case PrintErrorHeader::Never:
        break;

      case PrintErrorHeader::Once:
        info->print_header = PrintErrorHeader::Never;
      /* Fallthrough. */

      case PrintErrorHeader::Always:
        fprintf(out, "%s:\n", info->header);
        break;
    }
    /* If there's a header, indent the following message. */
    fprintf(out, "  ");
  }
}

static FILE* get_default_error_handler_info_output_file(
    DefaultErrorHandlerInfo* info) {
  return info && info->out_file ? info->out_file : stderr;
}

void default_source_error_callback(const Location* loc,
                                   const char* error,
                                   const char* source_line,
                                   size_t source_line_length,
                                   size_t source_line_column_offset,
                                   void* user_data) {
  DefaultErrorHandlerInfo* info =
      static_cast<DefaultErrorHandlerInfo*>(user_data);
  FILE* out = get_default_error_handler_info_output_file(info);
  print_error_header(out, info);
  print_source_error(out, loc, error, source_line, source_line_length,
                     source_line_column_offset);
}

void default_binary_error_callback(uint32_t offset,
                                   const char* error,
                                   void* user_data) {
  DefaultErrorHandlerInfo* info =
      static_cast<DefaultErrorHandlerInfo*>(user_data);
  FILE* out = get_default_error_handler_info_output_file(info);
  print_error_header(out, info);
  if (offset == WABT_UNKNOWN_OFFSET)
    fprintf(out, "error: %s\n", error);
  else
    fprintf(out, "error: @0x%08x: %s\n", offset, error);
  fflush(out);
}

void init_stdio() {
#if COMPILER_IS_MSVC
  int result = _setmode(_fileno(stdout), _O_BINARY);
  if (result == -1)
    perror("Cannot set mode binary to stdout");
  result = _setmode(_fileno(stderr), _O_BINARY);
  if (result == -1)
    perror("Cannot set mode binary to stderr");
#endif
}

}  // namespace wabt
<|endoftext|>