<commit_before>#ifndef ALEPH_TOPOLOGY_SPINE_HH__
#define ALEPH_TOPOLOGY_SPINE_HH__

#include <aleph/topology/Intersections.hh>

#include <algorithm>
#include <unordered_map>
#include <set>
#include <vector>

namespace aleph
{

namespace topology
{

/**
  Stores coface relationships in a simplicial complex. Given a simplex
  \f$\sigma\f$, the map contains all of its cofaces. Note that the map
  will be updated upon every elementary collapse.
*/

template <class Simplex> using CofaceMap = std::unordered_map<Simplex, std::unordered_set<Simplex> >;

template <class Simplex> bool isPrincipal( const CofaceMap<Simplex>& cofaces, const Simplex& s )
{
  return cofaces.at( s ).empty();
}

template <class Simplex> Simplex getFreeFace( const CofaceMap<Simplex>& cofaces, const Simplex& s )
{
  if( !isPrincipal( cofaces, s ) )
    return Simplex();

  // Check whether a free face exists ----------------------------------

  for( auto itFace = s.begin_boundary(); itFace != s.end_boundary(); ++itFace )
  {
    auto&& allCofaces = cofaces.at( *itFace );
    if( allCofaces.size() == 1 && allCofaces.find( s ) != allCofaces.end() )
      return *itFace;
  }

  return Simplex();
}

/**
  Checks whether a simplex in a simplicial complex is principal, i.e.
  whether it is not a proper face of any other simplex in K.
*/

template <class SimplicialComplex, class Simplex> bool isPrincipal( const Simplex& s, const SimplicialComplex& K )
{
  // Individual vertices cannot be considered to be principal because
  // they do not have a free face.
  if( s.dimension() == 0 )
    return false;

  bool principal = true;
  auto itPair    = K.range( s.dimension() + 1 );

  for( auto it = itPair.first; it != itPair.second; ++it )
  {
    auto&& t = *it;

    // This check assumes that the simplicial complex is valid, so it
    // suffices to search faces in one dimension _below_ s. Note that
    // the check only has to evaluate the *size* of the intersection,
    // as this is sufficient to determine whether a simplex is a face
    // of another simplex.
    if( sizeOfIntersection(s,t) == s.size() )
      principal = false;
  }

  return principal;
}

/**
  Checks whether a simplex in a simplicial complex is admissible, i.e.
  the simplex is *principal* and has at least one free face.
*/

template <class SimplicialComplex, class Simplex> Simplex isAdmissible( const Simplex& s, const SimplicialComplex& K )
{
  if( !isPrincipal(s,K) )
    return Simplex();

  // Check whether a free face exists ----------------------------------

  std::vector<Simplex> faces( s.begin_boundary(), s.end_boundary() );
  std::vector<bool> admissible( faces.size(), true );

  std::size_t i = 0;
  auto itPair   = K.range( s.dimension() ); // valid range for searches, viz. *all*
                                            // faces in "one dimension up"

  for( auto&& face : faces )
  {
    for( auto it = itPair.first; it != itPair.second; ++it )
    {
      auto&& t = *it;

      // We do not have to check for intersections with the original
      // simplex from which we started---we already know that we are
      // a face.
      if( t != s )
      {
        if( sizeOfIntersection(face,t) == face.size() )
        {
          admissible[i] = false;
          break;
        }
      }
    }

    ++i;
  }

  auto pos = std::find( admissible.begin(), admissible.end(), true );
  if( pos == admissible.end() )
    return Simplex();
  else
    return faces.at( std::distance( admissible.begin(), pos ) );
}

/**
  Calculates all principal faces of a given simplicial complex and
  returns them.
*/

template <class SimplicialComplex> std::unordered_map<typename SimplicialComplex::value_type, typename SimplicialComplex::value_type> principalFaces( const SimplicialComplex& K )
{
  using Simplex = typename SimplicialComplex::value_type;
  auto L        = K;

  std::unordered_map<Simplex, Simplex> admissible;

  // Step 1: determine free faces --------------------------------------
  //
  // This first checks which simplices have at least one free face,
  // meaning that they may be potentially admissible.

  for( auto it = L.begin(); it != L.end(); ++it )
  {
    if( it->dimension() == 0 )
      continue;

    // The range of the complex M is sufficient because we have
    // already encountered all lower-dimensional simplices that
    // precede the current one given by `it`.
    //
    // This complex will be used for testing free faces.
    SimplicialComplex M( L.begin(), it );

    // FIXME:
    //
    // In case of equal data values, the assignment from above does
    // *not* work and will result in incorrect candidates.
    M = L;

    bool hasFreeFace = false;
    Simplex freeFace = Simplex();

    for( auto itFace = it->begin_boundary(); itFace != it->end_boundary(); ++itFace )
    {
      bool isFace = false;
      for( auto&& simplex : M )
      {
        if( itFace->dimension() + 1 == simplex.dimension() && simplex != *it )
        {
          // The current face must *not* be a face of another simplex in
          // the simplicial complex.
          if( intersect( *itFace, simplex ) == *itFace )
          {
            isFace = true;
            break;
          }
        }
      }

      hasFreeFace = !isFace;
      if( hasFreeFace )
      {
        freeFace = *itFace;
        break;
      }
    }

    if( hasFreeFace )
      admissible.insert( std::make_pair( *it, freeFace ) );
  }

  // Step 2: determine principality ------------------------------------
  //
  // All simplices that are faces of higher-dimensional simplices are
  // now removed from the map of admissible simplices.

  for( auto&& s : L )
  {
    for( auto itFace = s.begin_boundary(); itFace != s.end_boundary(); ++itFace )
      admissible.erase( *itFace );
  }

  return admissible;
}

/**
  Performs an iterated elementary simplicial collapse until *all* of the
  admissible simplices have been collapsed. This leads to the *spine* of
  the simplicial complex.

  @see S. Matveev, "Algorithmic Topology and Classification of 3-Manifolds"
*/

template <class SimplicialComplex> SimplicialComplex spine( const SimplicialComplex& K )
{
  using Simplex = typename SimplicialComplex::value_type;
  auto L        = K;

  // Step 1: obtain initial set of principal faces to start the process
  // of collapsing the complex.
  auto admissible = principalFaces( L );

  // Step 2: collapse until no admissible simplices are left -----------

  while( !admissible.empty() )
  {
    auto s = admissible.begin()->first;
    auto t = admissible.begin()->second;

    L.remove_without_validation( s );
    L.remove_without_validation( t );

    admissible.erase( s );

    // New simplices ---------------------------------------------------
    //
    // Add new admissible simplices that may potentially have been
    // spawned by the removal of s.

    // 1. Add all faces of the principal simplex, as they may
    //    potentially become admissible again.
    std::vector<Simplex> faces( s.begin_boundary(), s.end_boundary() );

    std::for_each( faces.begin(), faces.end(),
      [&t, &L, &admissible] ( const Simplex& s )
      {
        // TODO: rename function
        auto face = isAdmissible( s, L );

        if( t != s && face )
          admissible.insert( std::make_pair( s, face ) );
      }
    );

    // 2. Add all faces othe free face, as they may now themselves
    //    become admissible.
    faces.assign( t.begin_boundary(), t.end_boundary() );

    std::for_each( faces.begin(), faces.end(),
      [&L, &admissible] ( const Simplex& s )
      {
        // TODO: rename function
        auto face = isAdmissible( s, L );

        if( face )
          admissible.insert( std::make_pair( s, face ) );
      }
    );

#if 0
    // TODO: this check could be simplified by *storing* the free face
    // along with the given simplex
    for( auto itFace = s.begin_boundary(); itFace != s.end_boundary(); ++itFace )
    {
      auto t = *itFace;

      if( isAdmissible( s, t, L ) )
      {
        L.remove_without_validation( s );
        L.remove_without_validation( t );

        admissible.erase( s );

        // New simplices -----------------------------------------------
        //
        // Add new admissible simplices that may potentially have been
        // spawned by the removal of s.

        // 1. Add all faces of the principal simplex, as they may
        //    potentially become admissible again.
        std::vector<Simplex> faces( s.begin_boundary(), s.end_boundary() );

        std::for_each( faces.begin(), faces.end(),
          [&t, &L, &admissible] ( const Simplex& s )
          {
            if( t != s && isAdmissible( s, L ) )
              admissible.insert( s );
          }
        );

        // 2. Add all faces othe free face, as they may now themselves
        //    become admissible.
        faces.assign( t.begin_boundary(), t.end_boundary() );

        std::for_each( faces.begin(), faces.end(),
          [&L, &admissible] ( const Simplex& s )
          {
            if( isAdmissible( s, L ) )
              admissible.insert( s );
          }
        );

        hasFreeFace = true;
        break;
      }
    }

    // The admissible simplex does not have a free face, so it must not
    // be used.
    if( !hasFreeFace )
      admissible.erase( s );
#endif

    // The heuristic above is incapable of detecting *all* principal
    // faces of the complex because this may involve searching *all*
    // co-faces. Instead, it is easier to fill up the admissible set
    // here.
    if( admissible.empty() )
      admissible = principalFaces( L );
  }

  return L;
}

} // namespace topology

} // namespace aleph

#endif
<commit_msg>Creation of coface map<commit_after>#ifndef ALEPH_TOPOLOGY_SPINE_HH__
#define ALEPH_TOPOLOGY_SPINE_HH__

#include <aleph/topology/Intersections.hh>

#include <algorithm>
#include <unordered_map>
#include <set>
#include <vector>

namespace aleph
{

namespace topology
{

/**
  Stores coface relationships in a simplicial complex. Given a simplex
  \f$\sigma\f$, the map contains all of its cofaces. Note that the map
  will be updated upon every elementary collapse.
*/

template <class Simplex> using CofaceMap = std::unordered_map<Simplex, std::unordered_set<Simplex> >;

template <class SimplicialComplex> CofaceMap<typename SimplicialComplex::ValueType> buildCofaceMap( const SimplicialComplex& K )
{
  using Simplex   = typename SimplicialComplex::ValueType;
  using CofaceMap = CofaceMap<Simplex>;

  CofaceMap cofaces;
  for( auto&& s : K )
  {
    for( auto itFace = s.begin_boundary(); itFace != s.end_boundary(); ++itFace )
      cofaces[ *itFace ].insert( s );
  }

  return cofaces;
}

template <class Simplex> bool isPrincipal( const CofaceMap<Simplex>& cofaces, const Simplex& s )
{
  return cofaces.at( s ).empty();
}

template <class Simplex> Simplex getFreeFace( const CofaceMap<Simplex>& cofaces, const Simplex& s )
{
  if( !isPrincipal( cofaces, s ) )
    return Simplex();

  // Check whether a free face exists ----------------------------------

  for( auto itFace = s.begin_boundary(); itFace != s.end_boundary(); ++itFace )
  {
    auto&& allCofaces = cofaces.at( *itFace );
    if( allCofaces.size() == 1 && allCofaces.find( s ) != allCofaces.end() )
      return *itFace;
  }

  return Simplex();
}

/**
  Checks whether a simplex in a simplicial complex is principal, i.e.
  whether it is not a proper face of any other simplex in K.
*/

template <class SimplicialComplex, class Simplex> bool isPrincipal( const Simplex& s, const SimplicialComplex& K )
{
  // Individual vertices cannot be considered to be principal because
  // they do not have a free face.
  if( s.dimension() == 0 )
    return false;

  bool principal = true;
  auto itPair    = K.range( s.dimension() + 1 );

  for( auto it = itPair.first; it != itPair.second; ++it )
  {
    auto&& t = *it;

    // This check assumes that the simplicial complex is valid, so it
    // suffices to search faces in one dimension _below_ s. Note that
    // the check only has to evaluate the *size* of the intersection,
    // as this is sufficient to determine whether a simplex is a face
    // of another simplex.
    if( sizeOfIntersection(s,t) == s.size() )
      principal = false;
  }

  return principal;
}

/**
  Checks whether a simplex in a simplicial complex is admissible, i.e.
  the simplex is *principal* and has at least one free face.
*/

template <class SimplicialComplex, class Simplex> Simplex isAdmissible( const Simplex& s, const SimplicialComplex& K )
{
  if( !isPrincipal(s,K) )
    return Simplex();

  // Check whether a free face exists ----------------------------------

  std::vector<Simplex> faces( s.begin_boundary(), s.end_boundary() );
  std::vector<bool> admissible( faces.size(), true );

  std::size_t i = 0;
  auto itPair   = K.range( s.dimension() ); // valid range for searches, viz. *all*
                                            // faces in "one dimension up"

  for( auto&& face : faces )
  {
    for( auto it = itPair.first; it != itPair.second; ++it )
    {
      auto&& t = *it;

      // We do not have to check for intersections with the original
      // simplex from which we started---we already know that we are
      // a face.
      if( t != s )
      {
        if( sizeOfIntersection(face,t) == face.size() )
        {
          admissible[i] = false;
          break;
        }
      }
    }

    ++i;
  }

  auto pos = std::find( admissible.begin(), admissible.end(), true );
  if( pos == admissible.end() )
    return Simplex();
  else
    return faces.at( std::distance( admissible.begin(), pos ) );
}

/**
  Calculates all principal faces of a given simplicial complex and
  returns them.
*/

template <class SimplicialComplex> std::unordered_map<typename SimplicialComplex::value_type, typename SimplicialComplex::value_type> principalFaces( const SimplicialComplex& K )
{
  using Simplex = typename SimplicialComplex::value_type;
  auto L        = K;

  std::unordered_map<Simplex, Simplex> admissible;

  // Step 1: determine free faces --------------------------------------
  //
  // This first checks which simplices have at least one free face,
  // meaning that they may be potentially admissible.

  for( auto it = L.begin(); it != L.end(); ++it )
  {
    if( it->dimension() == 0 )
      continue;

    // The range of the complex M is sufficient because we have
    // already encountered all lower-dimensional simplices that
    // precede the current one given by `it`.
    //
    // This complex will be used for testing free faces.
    SimplicialComplex M( L.begin(), it );

    // FIXME:
    //
    // In case of equal data values, the assignment from above does
    // *not* work and will result in incorrect candidates.
    M = L;

    bool hasFreeFace = false;
    Simplex freeFace = Simplex();

    for( auto itFace = it->begin_boundary(); itFace != it->end_boundary(); ++itFace )
    {
      bool isFace = false;
      for( auto&& simplex : M )
      {
        if( itFace->dimension() + 1 == simplex.dimension() && simplex != *it )
        {
          // The current face must *not* be a face of another simplex in
          // the simplicial complex.
          if( intersect( *itFace, simplex ) == *itFace )
          {
            isFace = true;
            break;
          }
        }
      }

      hasFreeFace = !isFace;
      if( hasFreeFace )
      {
        freeFace = *itFace;
        break;
      }
    }

    if( hasFreeFace )
      admissible.insert( std::make_pair( *it, freeFace ) );
  }

  // Step 2: determine principality ------------------------------------
  //
  // All simplices that are faces of higher-dimensional simplices are
  // now removed from the map of admissible simplices.

  for( auto&& s : L )
  {
    for( auto itFace = s.begin_boundary(); itFace != s.end_boundary(); ++itFace )
      admissible.erase( *itFace );
  }

  return admissible;
}

/**
  Performs an iterated elementary simplicial collapse until *all* of the
  admissible simplices have been collapsed. This leads to the *spine* of
  the simplicial complex.

  @see S. Matveev, "Algorithmic Topology and Classification of 3-Manifolds"
*/

template <class SimplicialComplex> SimplicialComplex spine( const SimplicialComplex& K )
{
  using Simplex = typename SimplicialComplex::value_type;
  auto L        = K;

  // Step 1: obtain initial set of principal faces to start the process
  // of collapsing the complex.
  auto admissible = principalFaces( L );

  // Step 2: collapse until no admissible simplices are left -----------

  while( !admissible.empty() )
  {
    auto s = admissible.begin()->first;
    auto t = admissible.begin()->second;

    L.remove_without_validation( s );
    L.remove_without_validation( t );

    admissible.erase( s );

    // New simplices ---------------------------------------------------
    //
    // Add new admissible simplices that may potentially have been
    // spawned by the removal of s.

    // 1. Add all faces of the principal simplex, as they may
    //    potentially become admissible again.
    std::vector<Simplex> faces( s.begin_boundary(), s.end_boundary() );

    std::for_each( faces.begin(), faces.end(),
      [&t, &L, &admissible] ( const Simplex& s )
      {
        // TODO: rename function
        auto face = isAdmissible( s, L );

        if( t != s && face )
          admissible.insert( std::make_pair( s, face ) );
      }
    );

    // 2. Add all faces othe free face, as they may now themselves
    //    become admissible.
    faces.assign( t.begin_boundary(), t.end_boundary() );

    std::for_each( faces.begin(), faces.end(),
      [&L, &admissible] ( const Simplex& s )
      {
        // TODO: rename function
        auto face = isAdmissible( s, L );

        if( face )
          admissible.insert( std::make_pair( s, face ) );
      }
    );

#if 0
    // TODO: this check could be simplified by *storing* the free face
    // along with the given simplex
    for( auto itFace = s.begin_boundary(); itFace != s.end_boundary(); ++itFace )
    {
      auto t = *itFace;

      if( isAdmissible( s, t, L ) )
      {
        L.remove_without_validation( s );
        L.remove_without_validation( t );

        admissible.erase( s );

        // New simplices -----------------------------------------------
        //
        // Add new admissible simplices that may potentially have been
        // spawned by the removal of s.

        // 1. Add all faces of the principal simplex, as they may
        //    potentially become admissible again.
        std::vector<Simplex> faces( s.begin_boundary(), s.end_boundary() );

        std::for_each( faces.begin(), faces.end(),
          [&t, &L, &admissible] ( const Simplex& s )
          {
            if( t != s && isAdmissible( s, L ) )
              admissible.insert( s );
          }
        );

        // 2. Add all faces othe free face, as they may now themselves
        //    become admissible.
        faces.assign( t.begin_boundary(), t.end_boundary() );

        std::for_each( faces.begin(), faces.end(),
          [&L, &admissible] ( const Simplex& s )
          {
            if( isAdmissible( s, L ) )
              admissible.insert( s );
          }
        );

        hasFreeFace = true;
        break;
      }
    }

    // The admissible simplex does not have a free face, so it must not
    // be used.
    if( !hasFreeFace )
      admissible.erase( s );
#endif

    // The heuristic above is incapable of detecting *all* principal
    // faces of the complex because this may involve searching *all*
    // co-faces. Instead, it is easier to fill up the admissible set
    // here.
    if( admissible.empty() )
      admissible = principalFaces( L );
  }

  return L;
}

} // namespace topology

} // namespace aleph

#endif
<|endoftext|>


<commit_before>#pragma once

/**
 * The HeapAnalysis class wraps a Dsa-like analysis.
 **/

#include "clam/config.h"
#include "crab/support/debug.hpp"

#include "llvm/IR/Value.h"
#include "llvm/Support/raw_ostream.h"
#include <vector>

// forward declarations
namespace llvm {
class Module;
class Function;
class Instruction;
class StringRef;
class CallInst;
} // namespace llvm

namespace clam {

////
// Dsa analysis for memory disambiguation
////
enum class heap_analysis_t {
  // disable heap analysis
  NONE,
  // use context-insensitive sea-dsa
  CI_SEA_DSA,
  // use context-sensitive sea-dsa
  CS_SEA_DSA
};

enum class region_type_t{
  UNTYPED_REGION = 0,
  BOOL_REGION = 1,
  INT_REGION = 2,
  PTR_REGION = 3
};

class RegionInfo {
  region_type_t m_region_type;
  // if PTR_REGION then bitwidth is the pointer size
  // if INT_REGION or BOOL_REGION then bitwidth is the integer's
  //    bitwidth or 1.
  unsigned m_bitwidth; // number of bits
  // whether the region is coming from a "sequence" sea-dsa node
  bool m_is_sequence;
  // whether the region is possibly allocated in the heap
  bool m_is_heap;
public:
  RegionInfo(region_type_t t, unsigned b, bool is_seq, bool is_heap)
    : m_region_type(t), m_bitwidth(b), m_is_sequence(is_seq), m_is_heap(is_heap) {}

  RegionInfo(const RegionInfo &other) = default;

  RegionInfo &operator=(const RegionInfo &other) = default;

  bool operator==(const RegionInfo &o) {
    // don't consider isSequence() or isHeap().
    // We use this operation to compare a region between caller and callee.
    return (getType() == o.getType() &&
	    getBitwidth() == o.getBitwidth());
  }

  bool containScalar() const {
    return m_region_type == region_type_t::BOOL_REGION ||
      m_region_type == region_type_t::INT_REGION;
  }

  bool containPointer() const {
    return m_region_type == region_type_t::PTR_REGION;
  }

  // Return region's type: boolean, integer or pointer.
  region_type_t getType() const { return m_region_type; }

  // Return 1 if boolean region, size of the pointer if pointer
  // region, or size of the integer if integer region. The bitwidth is
  // in bits. Otherwise, it returns 0 if bitwdith cannot be
  // determined.
  unsigned getBitwidth() const { return m_bitwidth; }

  // Whether the region corresponds to a "sequence" node
  bool isSequence() const { return m_is_sequence;}

  // Whether the region is potentially allocated via a malloc-like
  // function.
  bool isHeap() const { return m_is_heap;}
};

/**
 * A region abstracts a Dsa node field to create a symbolic name.
 **/
class Region {
public:
  using RegionId = long unsigned int;

private:
  // A region different from unknown should represent a consecutive
  // sequence of bytes in memory that have compatible types and are
  // accessed uniformly so the analysis can use it in a safe
  // manner.

  // Unique id
  RegionId m_id;
  // type of the region
  RegionInfo m_info;
  // whether the region contains a singleton value or not.
  const llvm::Value *m_singleton;

public:
  Region(RegionId id, RegionInfo info, const llvm::Value *singleton)
      : m_id(id), m_info(info), m_singleton(singleton) {}

  Region()
    : m_id(0),
      m_info(RegionInfo(region_type_t::UNTYPED_REGION, 0, false, false)),
      m_singleton(nullptr) {}

  Region(const Region &other) = default;

  Region(Region &&other) = default;

  Region &operator=(const Region &other) = default;

  RegionId getId() const { return m_id; }

  bool isUnknown() const { return (m_info.getType() == region_type_t::UNTYPED_REGION); }

  const llvm::Value *getSingleton() const { return m_singleton; }

  RegionInfo getRegionInfo() const { return m_info; }

  bool operator<(const Region &o) const { return (m_id < o.m_id); }

  bool operator==(const Region &o) const { return (m_id == o.m_id); }

  void write(llvm::raw_ostream &o) const {
    if (isUnknown()) {
      o << "unknown";
    } else {
      o << "R_" << m_id << ":";
      switch (getRegionInfo().getType()) {
      case region_type_t::UNTYPED_REGION:
        o << "U";
        break;
      case region_type_t::BOOL_REGION:
        o << "B";
        break;
      case region_type_t::INT_REGION:
        o << "I";
        break;
      case region_type_t::PTR_REGION:
        o << "P";
        break;
      }
    }
  }

  friend llvm::raw_ostream &operator<<(llvm::raw_ostream &o, const Region &r) {
    r.write(o);
    return o;
  }
};

inline llvm::raw_ostream &operator<<(llvm::raw_ostream &o,
                                     std::vector<Region> s) {
  o << "{";
  for (typename std::vector<Region>::iterator it = s.begin(), et = s.end();
       it != et;) {
    o << *it;
    ++it;
    if (it != et)
      o << ",";
  }
  o << "}";
  return o;
}

/* A convenient wrapper for a Dsa-like analysis */
class HeapAbstraction {
  friend class Region;

public:
  typedef std::vector<Region> RegionVec;
  typedef typename Region::RegionId RegionId;

  // Add a new value if a new HeapAbstraction subclass is created
  // This is used to use static_cast.
  enum class ClassId { DUMMY, SEA_DSA };

  HeapAbstraction() {}

  virtual ~HeapAbstraction() {}

  virtual ClassId getClassId() const = 0;

  virtual llvm::StringRef getName() const = 0;

  // TODO: mark all these methods as const.

  // fun is used to know in which function ptr lives.
  // If not null, i is the instruction that uses ptr.
  virtual Region getRegion(const llvm::Function &fun,
                           const llvm::Value &ptr) = 0;

  /**========  These functions allow to purify functions ========**/

  // Read-Only regions reachable by function parameters and globals
  // but not returns
  virtual RegionVec getOnlyReadRegions(const llvm::Function &) = 0;

  // Written regions reachable by function parameters and globals but
  // not returns
  virtual RegionVec getModifiedRegions(const llvm::Function &) = 0;

  // Regions that are reachable only from the return of the function
  virtual RegionVec getNewRegions(const llvm::Function &) = 0;

  // Read-only regions at the caller that are mapped to callee's
  // formal parameters and globals.
  virtual RegionVec getOnlyReadRegions(const llvm::CallInst &) = 0;

  // Written regions at the caller that are mapped to callee's formal
  // parameters and globals.
  virtual RegionVec getModifiedRegions(const llvm::CallInst &) = 0;

  // Regions at the caller that are mapped to those that are only
  // reachable from callee's returns.
  virtual RegionVec getNewRegions(const llvm::CallInst &) = 0;
};

} // namespace clam
<commit_msg>refactor(heap-abs): rename == and add write method to RegionInfo<commit_after>#pragma once

/**
 * The HeapAnalysis class wraps a Dsa-like analysis.
 **/

#include "clam/config.h"
#include "crab/support/debug.hpp"

#include "llvm/IR/Value.h"
#include "llvm/Support/raw_ostream.h"
#include <vector>

// forward declarations
namespace llvm {
class Module;
class Function;
class Instruction;
class StringRef;
class CallInst;
} // namespace llvm

namespace clam {

////
// Dsa analysis for memory disambiguation
////
enum class heap_analysis_t {
  // disable heap analysis
  NONE,
  // use context-insensitive sea-dsa
  CI_SEA_DSA,
  // use context-sensitive sea-dsa
  CS_SEA_DSA
};

enum class region_type_t{
  UNTYPED_REGION = 0,
  BOOL_REGION = 1,
  INT_REGION = 2,
  PTR_REGION = 3
};

class RegionInfo {
  region_type_t m_region_type;
  // if PTR_REGION then bitwidth is the pointer size
  // if INT_REGION or BOOL_REGION then bitwidth is the integer's
  //    bitwidth or 1.
  unsigned m_bitwidth; // number of bits
  // whether the region is coming from a "sequence" sea-dsa node
  bool m_is_sequence;
  // whether the region is possibly allocated in the heap
  bool m_is_heap;
public:
  RegionInfo(region_type_t t, unsigned b, bool is_seq, bool is_heap)
    : m_region_type(t), m_bitwidth(b), m_is_sequence(is_seq), m_is_heap(is_heap) {}

  RegionInfo(const RegionInfo &other) = default;

  RegionInfo &operator=(const RegionInfo &other) = default;

  bool hasSameType(const RegionInfo &o) const {
    return (getType() == o.getType() &&
	    getBitwidth() == o.getBitwidth());
  }

  bool containScalar() const {
    return m_region_type == region_type_t::BOOL_REGION ||
      m_region_type == region_type_t::INT_REGION;
  }

  bool containPointer() const {
    return m_region_type == region_type_t::PTR_REGION;
  }

  // Return region's type: boolean, integer or pointer.
  region_type_t getType() const { return m_region_type; }

  // Return 1 if boolean region, size of the pointer if pointer
  // region, or size of the integer if integer region. The bitwidth is
  // in bits. Otherwise, it returns 0 if bitwdith cannot be
  // determined.
  unsigned getBitwidth() const { return m_bitwidth; }

  // Whether the region corresponds to a "sequence" node
  bool isSequence() const { return m_is_sequence;}

  // Whether the region is potentially allocated via a malloc-like
  // function.
  bool isHeap() const { return m_is_heap;}

  void write(llvm::raw_ostream &o) const {
    switch (getType()) {
    case region_type_t::UNTYPED_REGION:
      o << "U";
      break;
    case region_type_t::BOOL_REGION:
      o << "B";
      break;
    case region_type_t::INT_REGION:
      o << "I" << ":" << getBitwidth();
      break;
    case region_type_t::PTR_REGION:
      o << "P";
      break;
    }
  }

  friend llvm::raw_ostream &operator<<(llvm::raw_ostream &o, const RegionInfo &rgnInfo) {
    rgnInfo.write(o);
    return o;
  }

};

/**
 * A region abstracts a Dsa node field to create a symbolic name.
 **/
class Region {
public:
  using RegionId = long unsigned int;

private:
  // A region different from unknown should represent a consecutive
  // sequence of bytes in memory that have compatible types and are
  // accessed uniformly so the analysis can use it in a safe
  // manner.

  // Unique id
  RegionId m_id;
  // type of the region
  RegionInfo m_info;
  // whether the region contains a singleton value or not.
  const llvm::Value *m_singleton;

public:
  Region(RegionId id, RegionInfo info, const llvm::Value *singleton)
      : m_id(id), m_info(info), m_singleton(singleton) {}

  Region()
    : m_id(0),
      m_info(RegionInfo(region_type_t::UNTYPED_REGION, 0, false, false)),
      m_singleton(nullptr) {}

  Region(const Region &other) = default;

  Region(Region &&other) = default;

  Region &operator=(const Region &other) = default;

  RegionId getId() const { return m_id; }

  bool isUnknown() const { return (m_info.getType() == region_type_t::UNTYPED_REGION); }

  const llvm::Value *getSingleton() const { return m_singleton; }

  RegionInfo getRegionInfo() const { return m_info; }

  bool operator<(const Region &o) const { return (m_id < o.m_id); }

  bool operator==(const Region &o) const { return (m_id == o.m_id); }

  void write(llvm::raw_ostream &o) const {
    o << "R_" << m_id << ":" << getRegionInfo();
  }

  friend llvm::raw_ostream &operator<<(llvm::raw_ostream &o, const Region &r) {
    r.write(o);
    return o;
  }
};

inline llvm::raw_ostream &operator<<(llvm::raw_ostream &o,
                                     std::vector<Region> s) {
  o << "{";
  for (typename std::vector<Region>::iterator it = s.begin(), et = s.end();
       it != et;) {
    o << *it;
    ++it;
    if (it != et)
      o << ",";
  }
  o << "}";
  return o;
}

/* A convenient wrapper for a Dsa-like analysis */
class HeapAbstraction {
  friend class Region;

public:
  typedef std::vector<Region> RegionVec;
  typedef typename Region::RegionId RegionId;

  // Add a new value if a new HeapAbstraction subclass is created
  // This is used to use static_cast.
  enum class ClassId { DUMMY, SEA_DSA };

  HeapAbstraction() {}

  virtual ~HeapAbstraction() {}

  virtual ClassId getClassId() const = 0;

  virtual llvm::StringRef getName() const = 0;

  // TODO: mark all these methods as const.

  // fun is used to know in which function ptr lives.
  // If not null, i is the instruction that uses ptr.
  virtual Region getRegion(const llvm::Function &fun,
                           const llvm::Value &ptr) = 0;

  /**========  These functions allow to purify functions ========**/

  // Read-Only regions reachable by function parameters and globals
  // but not returns
  virtual RegionVec getOnlyReadRegions(const llvm::Function &) = 0;

  // Written regions reachable by function parameters and globals but
  // not returns
  virtual RegionVec getModifiedRegions(const llvm::Function &) = 0;

  // Regions that are reachable only from the return of the function
  virtual RegionVec getNewRegions(const llvm::Function &) = 0;

  // Read-only regions at the caller that are mapped to callee's
  // formal parameters and globals.
  virtual RegionVec getOnlyReadRegions(const llvm::CallInst &) = 0;

  // Written regions at the caller that are mapped to callee's formal
  // parameters and globals.
  virtual RegionVec getModifiedRegions(const llvm::CallInst &) = 0;

  // Regions at the caller that are mapped to those that are only
  // reachable from callee's returns.
  virtual RegionVec getNewRegions(const llvm::CallInst &) = 0;
};

} // namespace clam
<|endoftext|>


<commit_before>#include "game.hpp"

bool Game::uciHandler(std::string str) {
	std::vector<std::string> cmd = getStringArray(str);
		if(cmd[0] == "isready") {
			std::cout << "readyok" << std::endl;
		} else if(cmd[0] == "position") {
			gameHash.clear();
			gameHash.resize(0);
			hash_decrement = 0;
			if(cmd[1] == "startpos") {
				game_board.setFen(game_board.startpos_fen);
				hash_decrement = 0;
				hashAge = 0;
				if(cmd.size() > 3) {
					if(cmd[2] == "moves") {
						for(unsigned int i = 3; i < cmd.size(); ++i) {
							move(cmd[i]);
						}
					}
				}
			} else if(cmd[1] == "fen") {
				std::string fen;
				unsigned int pos = 2;

				for(unsigned int i = 2; i < 8; ++i) {
					fen += cmd[i];
					if(i != cmd.size() - 1) {
						fen.push_back(' ');
					}
					++pos;
				}

				game_board.setFen(fen);
				if(cmd.size() > pos) {
					if(cmd[pos] == "moves") {
						for(unsigned int i = pos + 1; i < cmd.size(); ++i) {
							move(cmd[i]);
						}
					}
				}
			}
		} else if(cmd[0] == "go") {
			if(cmd[1] == "depth") {
				max_depth = std::stoi(cmd[2]);
			  goFixedDepth();
			} else if(cmd[1] == "movetime") {
				goFixedTime(std::stoi(cmd[2]), false);
			} else if(cmd[1] == "infinite") {
				max_depth = 99;
				goFixedDepth();
			} else {
				wtime = 0, btime = 0;
				winc = 0, binc = 0, movestogo = 0, movestogoEnable = false;
				for(unsigned int i = 1; i < cmd.size(); ++i) {
					if(cmd[i] == "wtime") {
						wtime = std::stoi(cmd[i + 1]);
					} else if(cmd[i] == "btime") {
						btime = std::stoi(cmd[i + 1]);
					} else if(cmd[i] == "winc") {
						winc = std::stoi(cmd[i + 1]);
					} else if(cmd[i] == "binc") {
						binc = std::stoi(cmd[i + 1]);
					} else if(cmd[i] == "movestogo") {
						movestogoEnable = true;
						movestogo = std::stoi(cmd[i+1]);
					}
				}

				goTournament();
			}
		} else if(cmd[0] == "posmoves") {
			MoveArray moves;
			game_board.bitBoardMoveGenerator(moves, stress);

			for(unsigned int i = 0; i < moves.count; ++i) {
				std::cout << moves.moveArray[i].getMoveString();
				std::cout << std::endl;
			}

			std::cout << game_board.getEvaluate() / PAWN_EV * 100 << std::endl;
			std::cout << game_board.getFen() << std::endl;

			std::cout << "inCheck (WHITE) : " << game_board.inCheck(WHITE) << std::endl;
			std::cout << "inCheck (BLACK) : " << game_board.inCheck(BLACK) << std::endl;
			std::cout << "color_hash: " << game_board.getColorHash() << std::endl;
		} else if(cmd[0] == "move") {
			move(cmd[1]);
		} else if(cmd[0] == "quit") {
			return false;
		} else if(cmd[0] == "uci") {
			idPrint();
			option.print();
			std::cout << "uciok" << std::endl;
		} else if(cmd[0] == "bench") {
			std::cout << "Benchmarking (15 sec)..." << std::endl;
			game_board.stress = 0;
			double st = clock();
			while((clock() - st) / CLOCKS_PER_SEC < 15) {
				for(unsigned int i = 0; i < 10000000; ++i) {
					game_board.bitBoardMoveGenerator(moveArray[0], game_board.stress);
				}
			}
			std::cout << (int64_t)(game_board.stress / ((clock() - st) / CLOCKS_PER_SEC)) / 10000 << " scores" << std::endl;
		} else if(cmd[0] == "goback") {
			game_board.goBack();
			--hash_decrement;
		} else if(cmd[0] == "perft") {
			int k;
			k = std::stoi(cmd[1]);
			for(int i = 1; i <= k; ++i) {
				combinations = 0;
				double st = clock();
				uint64_t count = perft(i);
				std::cout << "Depth: " << i << "; count: " << combinations;
				std::cout << "; speed: " << (int64_t)((double)count / (((double)clock() - (double)st) / (double)CLOCKS_PER_SEC)) << std::endl;
			}
		} else if(cmd[0] == "setoption" && cmd[1] == "name") {
			if(cmd[2] == "nullmove" && cmd[3] == "value") {
				if(cmd[4] == "true") {
					option.nullMovePruningEnable = true;
				} else if(cmd[4] == "false") {
					option.nullMovePruningEnable = false;
				}
			} else if(cmd[2] == "checkExtensions" && cmd[3] == "value") {
				if(cmd[4] == "true") {
					option.checkExtensions = true;
				} else if(cmd[4] == "false") {
					option.checkExtensions = false;
				}
			} else if(cmd[2] == "Clear" && cmd[3] == "Hash") {
				clearCash();
				std::cout << "info hashfull 0" << std::endl;
			} else if(cmd[2] == "Hash" && cmd[3] == "value") {
				int hash_size = std::stoi(cmd[4]);

				hash_size = std::min(hash_size, option.max_hash_size);
				hash_size = std::max(hash_size, option.min_hash_size);

				setHashSize(hash_size);
			} else if(cmd[2] == "UCI_AnalyseMode" && cmd[3] == "value") {
				if(cmd[4] == "true") {
					option.UCI_AnalyseMode = true;
				} else if(cmd[4] == "false") {
					option.UCI_AnalyseMode = false;
				}
			}
		}

		return true;
}

void Game::idPrint() {
	std::cout << "id name Zevra v1.7.1 r561 beta" << std::endl;
	std::cout << "id author Oleg Smirnov @sovaz1997" << std::endl;
}<commit_msg>v1.7.1 Release<commit_after>#include "game.hpp"

bool Game::uciHandler(std::string str) {
	std::vector<std::string> cmd = getStringArray(str);
		if(cmd[0] == "isready") {
			std::cout << "readyok" << std::endl;
		} else if(cmd[0] == "position") {
			gameHash.clear();
			gameHash.resize(0);
			hash_decrement = 0;
			if(cmd[1] == "startpos") {
				game_board.setFen(game_board.startpos_fen);
				hash_decrement = 0;
				hashAge = 0;
				if(cmd.size() > 3) {
					if(cmd[2] == "moves") {
						for(unsigned int i = 3; i < cmd.size(); ++i) {
							move(cmd[i]);
						}
					}
				}
			} else if(cmd[1] == "fen") {
				std::string fen;
				unsigned int pos = 2;

				for(unsigned int i = 2; i < 8; ++i) {
					fen += cmd[i];
					if(i != cmd.size() - 1) {
						fen.push_back(' ');
					}
					++pos;
				}

				game_board.setFen(fen);
				if(cmd.size() > pos) {
					if(cmd[pos] == "moves") {
						for(unsigned int i = pos + 1; i < cmd.size(); ++i) {
							move(cmd[i]);
						}
					}
				}
			}
		} else if(cmd[0] == "go") {
			if(cmd[1] == "depth") {
				max_depth = std::stoi(cmd[2]);
			  goFixedDepth();
			} else if(cmd[1] == "movetime") {
				goFixedTime(std::stoi(cmd[2]), false);
			} else if(cmd[1] == "infinite") {
				max_depth = 99;
				goFixedDepth();
			} else {
				wtime = 0, btime = 0;
				winc = 0, binc = 0, movestogo = 0, movestogoEnable = false;
				for(unsigned int i = 1; i < cmd.size(); ++i) {
					if(cmd[i] == "wtime") {
						wtime = std::stoi(cmd[i + 1]);
					} else if(cmd[i] == "btime") {
						btime = std::stoi(cmd[i + 1]);
					} else if(cmd[i] == "winc") {
						winc = std::stoi(cmd[i + 1]);
					} else if(cmd[i] == "binc") {
						binc = std::stoi(cmd[i + 1]);
					} else if(cmd[i] == "movestogo") {
						movestogoEnable = true;
						movestogo = std::stoi(cmd[i+1]);
					}
				}

				goTournament();
			}
		} else if(cmd[0] == "posmoves") {
			MoveArray moves;
			game_board.bitBoardMoveGenerator(moves, stress);

			for(unsigned int i = 0; i < moves.count; ++i) {
				std::cout << moves.moveArray[i].getMoveString();
				std::cout << std::endl;
			}

			std::cout << game_board.getEvaluate() / PAWN_EV * 100 << std::endl;
			std::cout << game_board.getFen() << std::endl;

			std::cout << "inCheck (WHITE) : " << game_board.inCheck(WHITE) << std::endl;
			std::cout << "inCheck (BLACK) : " << game_board.inCheck(BLACK) << std::endl;
			std::cout << "color_hash: " << game_board.getColorHash() << std::endl;
		} else if(cmd[0] == "move") {
			move(cmd[1]);
		} else if(cmd[0] == "quit") {
			return false;
		} else if(cmd[0] == "uci") {
			idPrint();
			option.print();
			std::cout << "uciok" << std::endl;
		} else if(cmd[0] == "bench") {
			std::cout << "Benchmarking (15 sec)..." << std::endl;
			game_board.stress = 0;
			double st = clock();
			while((clock() - st) / CLOCKS_PER_SEC < 15) {
				for(unsigned int i = 0; i < 10000000; ++i) {
					game_board.bitBoardMoveGenerator(moveArray[0], game_board.stress);
				}
			}
			std::cout << (int64_t)(game_board.stress / ((clock() - st) / CLOCKS_PER_SEC)) / 10000 << " scores" << std::endl;
		} else if(cmd[0] == "goback") {
			game_board.goBack();
			--hash_decrement;
		} else if(cmd[0] == "perft") {
			int k;
			k = std::stoi(cmd[1]);
			for(int i = 1; i <= k; ++i) {
				combinations = 0;
				double st = clock();
				uint64_t count = perft(i);
				std::cout << "Depth: " << i << "; count: " << combinations;
				std::cout << "; speed: " << (int64_t)((double)count / (((double)clock() - (double)st) / (double)CLOCKS_PER_SEC)) << std::endl;
			}
		} else if(cmd[0] == "setoption" && cmd[1] == "name") {
			if(cmd[2] == "nullmove" && cmd[3] == "value") {
				if(cmd[4] == "true") {
					option.nullMovePruningEnable = true;
				} else if(cmd[4] == "false") {
					option.nullMovePruningEnable = false;
				}
			} else if(cmd[2] == "checkExtensions" && cmd[3] == "value") {
				if(cmd[4] == "true") {
					option.checkExtensions = true;
				} else if(cmd[4] == "false") {
					option.checkExtensions = false;
				}
			} else if(cmd[2] == "Clear" && cmd[3] == "Hash") {
				clearCash();
				std::cout << "info hashfull 0" << std::endl;
			} else if(cmd[2] == "Hash" && cmd[3] == "value") {
				int hash_size = std::stoi(cmd[4]);

				hash_size = std::min(hash_size, option.max_hash_size);
				hash_size = std::max(hash_size, option.min_hash_size);

				setHashSize(hash_size);
			} else if(cmd[2] == "UCI_AnalyseMode" && cmd[3] == "value") {
				if(cmd[4] == "true") {
					option.UCI_AnalyseMode = true;
				} else if(cmd[4] == "false") {
					option.UCI_AnalyseMode = false;
				}
			}
		}

		return true;
}

void Game::idPrint() {
	std::cout << "id name Zevra v1.7.1 r563" << std::endl;
	std::cout << "id author Oleg Smirnov @sovaz1997" << std::endl;
}<|endoftext|>


<commit_before>#ifndef GAMELIB_EVENT_HPP
#define GAMELIB_EVENT_HPP

#include <memory>
#include "../Identifier.hpp"

namespace gamelib
{
    typedef ID EventID;
    constexpr EventID invalidEvent = invalidID;

    typedef Identifiable BaseEvent; // Event Interface

    typedef std::shared_ptr<BaseEvent> EventPtr;

    // Wrapper (see Identifier.hpp)
    template <ID id>
    using Event = Identifier<id, BaseEvent>;
}

#endif
<commit_msg>Add function to BaseEvent to cast to a given type<commit_after>#ifndef GAMELIB_EVENT_HPP
#define GAMELIB_EVENT_HPP

#include <memory>
#include "../Identifier.hpp"

namespace gamelib
{
    typedef ID EventID;
    constexpr EventID invalidEvent = invalidID;

    // typedef Identifiable BaseEvent; // Event Interface

    class BaseEvent : public Identifiable
    {
        public:
            virtual ~BaseEvent() {}

            // Returns a pointer T*.
            // Can be used to easily cast to the derived class.
            template <class T>
            const T* get() const
            {
                return static_cast<const T*>(this);
            }

            template <class T>
            T* get()
            {
                return static_cast<T*>(this);
            }
    };

    typedef std::shared_ptr<BaseEvent> EventPtr;

    // Wrapper (see Identifier.hpp)
    template <ID id>
    using Event = Identifier<id, BaseEvent>;
}

#endif
<|endoftext|>


<commit_before>/**
 * @file postings_data.tcc
 * @author Sean Massung
 */

#include <algorithm>
#include "index/postings_data.h"

namespace meta {
namespace index {

template <class PrimaryKey, class SecondaryKey>
postings_data<PrimaryKey, SecondaryKey>::postings_data(PrimaryKey p_id):
    _p_id{p_id}
{ /* nothing */ }

template <class PrimaryKey, class SecondaryKey>
void postings_data<PrimaryKey, SecondaryKey>::merge_with(
        postings_data & other)
{
    auto searcher = [](const pair_t & p, const SecondaryKey & s) {
        return p.first < s;
    };

    // O(n log n) now, could be O(n)

    // if the primary_key doesn't exist, add onto back
    uint64_t orig_length = _counts.size();
    for(auto & p: other._counts)
    {
        auto it = std::lower_bound(_counts.begin(),
                                   _counts.begin() + orig_length,
                                   p.first,
                                   searcher);
        if(it == _counts.end() || it->first != p.first)
            _counts.emplace_back(std::move(p));
        else
            it->second += p.second;
    }

    // sort _counts again to fix new elements added onto back
    if (_counts.size() > orig_length) {
        std::sort(_counts.begin(), _counts.end(),
            [](const pair_t & a, const pair_t & b) {
                return a.first < b.first;
            }
        );
    }
}

template <class PrimaryKey, class SecondaryKey>
void postings_data<PrimaryKey, SecondaryKey>::increase_count(
        SecondaryKey s_id, double amount)
{
    auto it = std::lower_bound(_counts.begin(), _counts.end(), s_id,
        [](const pair_t & p, const SecondaryKey & s) {
            return p.first < s;
        }
    );

    if(it == _counts.end())
        _counts.emplace_back(s_id, amount);
    else if(it->first != s_id)
        _counts.emplace(it, s_id, amount);
    else
        it->second += amount;
}

template <class PrimaryKey, class SecondaryKey>
double postings_data<PrimaryKey, SecondaryKey>::count(SecondaryKey s_id) const
{
    auto it = std::lower_bound(_counts.begin(), _counts.end(), s_id,
        [](const pair_t & p, const SecondaryKey & s) {
            return p.first < s;
        }
    );

    if(it == _counts.end() || it->first != s_id)
        return 0.0;
    return it->second;
}

template <class PrimaryKey, class SecondaryKey>
const std::vector<std::pair<SecondaryKey, double>> &
postings_data<PrimaryKey, SecondaryKey>::counts() const
{
    return _counts;
}

template <class PrimaryKey, class SecondaryKey>
void postings_data<PrimaryKey, SecondaryKey>::set_counts(const count_t & counts)
{
    _counts = counts;
    std::sort(_counts.begin(), _counts.end(),
        [](const pair_t & a, const pair_t & b) {
            return a.first < b.first;
        }
    );
}

template <class PrimaryKey, class SecondaryKey>
bool postings_data<PrimaryKey, SecondaryKey>::operator<(const postings_data & other) const
{
    return primary_key() < other.primary_key();
}

template <class PrimaryKey, class SecondaryKey>
bool operator==(const postings_data<PrimaryKey, SecondaryKey> & lhs,
                const postings_data<PrimaryKey, SecondaryKey> & rhs) {
    return lhs.primary_key() == rhs.primary_key();
}

template <class PrimaryKey, class SecondaryKey>
PrimaryKey postings_data<PrimaryKey, SecondaryKey>::primary_key() const
{
    return _p_id;
}

template <class PrimaryKey, class SecondaryKey>
void postings_data<PrimaryKey, SecondaryKey>::write_compressed(
        io::compressed_file_writer & writer) const
{
    count_t mutable_counts{_counts};
    writer.write(mutable_counts[0].first);
    writer.write(*reinterpret_cast<uint64_t*>(&mutable_counts[0].second));

    // use gap encoding on the SecondaryKeys (we know they are integral types)
    uint64_t cur_id = mutable_counts[0].first;
    for(size_t i = 1; i < mutable_counts.size(); ++i)
    {
        uint64_t temp_id = mutable_counts[i].first;
        mutable_counts[i].first = mutable_counts[i].first - cur_id;
        cur_id = temp_id;

        writer.write(mutable_counts[i].first);
        if(std::is_same<PrimaryKey, term_id>::value
           || std::is_same<PrimaryKey, std::string>::value)
            writer.write(static_cast<uint64_t>(mutable_counts[i].second));
        else
            writer.write(*reinterpret_cast<uint64_t*>(&mutable_counts[i].second));
    }

    // mark end of postings_data
    writer.write(_delimiter);
}

template <class PrimaryKey, class SecondaryKey>
void postings_data<PrimaryKey, SecondaryKey>::read_compressed(
        io::compressed_file_reader & reader)
{
    _counts.clear();
    uint64_t last_id = 0;

    while(true)
    {
        uint64_t this_id = reader.next();

        // have we reached a delimiter?
        if(this_id == _delimiter)
            break;

        // we're using gap encoding
        last_id += this_id;
        SecondaryKey key{last_id};
        uint64_t next = reader.next();
        double count;
        if(std::is_same<PrimaryKey, term_id>::value)
            count = static_cast<double>(next);
        else
            count = *reinterpret_cast<double*>(&next);

        _counts.emplace_back(key, count);
    }

    // compress vector to conserve memory (it shouldn't be modified again after
    // this)
    _counts.shrink_to_fit();
}

namespace {
    template <class T>
    uint64_t length(const T & elem,
                    typename std::enable_if<
                        std::is_same<T, std::string>::value
                    >::type * = nullptr) {
        return elem.size();
    }

    template <class T>
    uint64_t length(const T & elem,
                    typename std::enable_if<
                        !std::is_same<T, std::string>::value
                    >::type * = nullptr) {
        return sizeof(elem);
    }
}

template <class PrimaryKey, class SecondaryKey>
uint64_t postings_data<PrimaryKey, SecondaryKey>::bytes_used() const
{
    return sizeof(pair_t) * _counts.size() + length(_p_id);
}

}
}
<commit_msg>Fix bug writing the first count of a postings_data in inverted indexes.<commit_after>/**
 * @file postings_data.tcc
 * @author Sean Massung
 */

#include <algorithm>
#include "index/postings_data.h"

namespace meta {
namespace index {

template <class PrimaryKey, class SecondaryKey>
postings_data<PrimaryKey, SecondaryKey>::postings_data(PrimaryKey p_id):
    _p_id{p_id}
{ /* nothing */ }

template <class PrimaryKey, class SecondaryKey>
void postings_data<PrimaryKey, SecondaryKey>::merge_with(
        postings_data & other)
{
    auto searcher = [](const pair_t & p, const SecondaryKey & s) {
        return p.first < s;
    };

    // O(n log n) now, could be O(n)

    // if the primary_key doesn't exist, add onto back
    uint64_t orig_length = _counts.size();
    for(auto & p: other._counts)
    {
        auto it = std::lower_bound(_counts.begin(),
                                   _counts.begin() + orig_length,
                                   p.first,
                                   searcher);
        if(it == _counts.end() || it->first != p.first)
            _counts.emplace_back(std::move(p));
        else
            it->second += p.second;
    }

    // sort _counts again to fix new elements added onto back
    if (_counts.size() > orig_length) {
        std::sort(_counts.begin(), _counts.end(),
            [](const pair_t & a, const pair_t & b) {
                return a.first < b.first;
            }
        );
    }
}

template <class PrimaryKey, class SecondaryKey>
void postings_data<PrimaryKey, SecondaryKey>::increase_count(
        SecondaryKey s_id, double amount)
{
    auto it = std::lower_bound(_counts.begin(), _counts.end(), s_id,
        [](const pair_t & p, const SecondaryKey & s) {
            return p.first < s;
        }
    );

    if(it == _counts.end())
        _counts.emplace_back(s_id, amount);
    else if(it->first != s_id)
        _counts.emplace(it, s_id, amount);
    else
        it->second += amount;
}

template <class PrimaryKey, class SecondaryKey>
double postings_data<PrimaryKey, SecondaryKey>::count(SecondaryKey s_id) const
{
    auto it = std::lower_bound(_counts.begin(), _counts.end(), s_id,
        [](const pair_t & p, const SecondaryKey & s) {
            return p.first < s;
        }
    );

    if(it == _counts.end() || it->first != s_id)
        return 0.0;
    return it->second;
}

template <class PrimaryKey, class SecondaryKey>
const std::vector<std::pair<SecondaryKey, double>> &
postings_data<PrimaryKey, SecondaryKey>::counts() const
{
    return _counts;
}

template <class PrimaryKey, class SecondaryKey>
void postings_data<PrimaryKey, SecondaryKey>::set_counts(const count_t & counts)
{
    _counts = counts;
    std::sort(_counts.begin(), _counts.end(),
        [](const pair_t & a, const pair_t & b) {
            return a.first < b.first;
        }
    );
}

template <class PrimaryKey, class SecondaryKey>
bool postings_data<PrimaryKey, SecondaryKey>::operator<(const postings_data & other) const
{
    return primary_key() < other.primary_key();
}

template <class PrimaryKey, class SecondaryKey>
bool operator==(const postings_data<PrimaryKey, SecondaryKey> & lhs,
                const postings_data<PrimaryKey, SecondaryKey> & rhs) {
    return lhs.primary_key() == rhs.primary_key();
}

template <class PrimaryKey, class SecondaryKey>
PrimaryKey postings_data<PrimaryKey, SecondaryKey>::primary_key() const
{
    return _p_id;
}

template <class PrimaryKey, class SecondaryKey>
void postings_data<PrimaryKey, SecondaryKey>::write_compressed(
        io::compressed_file_writer & writer) const
{
    count_t mutable_counts{_counts};
    writer.write(mutable_counts[0].first);
    if(std::is_same<PrimaryKey, term_id>::value
       || std::is_same<PrimaryKey, std::string>::value)
        writer.write(static_cast<uint64_t>(mutable_counts[0].second));
    else
        writer.write(*reinterpret_cast<uint64_t*>(&mutable_counts[0].second));

    // use gap encoding on the SecondaryKeys (we know they are integral types)
    uint64_t cur_id = mutable_counts[0].first;
    for(size_t i = 1; i < mutable_counts.size(); ++i)
    {
        uint64_t temp_id = mutable_counts[i].first;
        mutable_counts[i].first = mutable_counts[i].first - cur_id;
        cur_id = temp_id;

        writer.write(mutable_counts[i].first);
        if(std::is_same<PrimaryKey, term_id>::value
           || std::is_same<PrimaryKey, std::string>::value)
            writer.write(static_cast<uint64_t>(mutable_counts[i].second));
        else
            writer.write(*reinterpret_cast<uint64_t*>(&mutable_counts[i].second));
    }

    // mark end of postings_data
    writer.write(_delimiter);
}

template <class PrimaryKey, class SecondaryKey>
void postings_data<PrimaryKey, SecondaryKey>::read_compressed(
        io::compressed_file_reader & reader)
{
    _counts.clear();
    uint64_t last_id = 0;

    while(true)
    {
        uint64_t this_id = reader.next();

        // have we reached a delimiter?
        if(this_id == _delimiter)
            break;

        // we're using gap encoding
        last_id += this_id;
        SecondaryKey key{last_id};
        uint64_t next = reader.next();
        double count;
        if(std::is_same<PrimaryKey, term_id>::value)
            count = static_cast<double>(next);
        else
            count = *reinterpret_cast<double*>(&next);

        _counts.emplace_back(key, count);
    }

    // compress vector to conserve memory (it shouldn't be modified again after
    // this)
    _counts.shrink_to_fit();
}

namespace {
    template <class T>
    uint64_t length(const T & elem,
                    typename std::enable_if<
                        std::is_same<T, std::string>::value
                    >::type * = nullptr) {
        return elem.size();
    }

    template <class T>
    uint64_t length(const T & elem,
                    typename std::enable_if<
                        !std::is_same<T, std::string>::value
                    >::type * = nullptr) {
        return sizeof(elem);
    }
}

template <class PrimaryKey, class SecondaryKey>
uint64_t postings_data<PrimaryKey, SecondaryKey>::bytes_used() const
{
    return sizeof(pair_t) * _counts.size() + length(_p_id);
}

}
}
<|endoftext|>


<commit_before>#include "rdo_studio/stdafx.h"
#include "rdo_studio/rdo_process/rdoprocess_project.h"
#include "rdo_studio/rdostudioapp.h"
#include "rdo_studio/rdo_process/rdoprocess_childfrm.h"
#include "rdo_studio/rdo_process/rdoprocess_docview.h"
#include "rdo_studio/rdo_process/rdoprocess_toolbar.h"
#include "rdo_studio/rdo_process/rp_misc/rdoprocess_pixmap.h"
#include "rdo_studio/rdo_process/rp_method/rdoprocess_object_flowchart.h"
#include "rdo_studio/rdo_process/rp_method/rdoprocess_method.h"
#include "rdo_studio/rdo_process/rp_misc/rdoprocess_xml.h"

#include "rdo_studio/rdostudiomodel.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

// ----------------------------------------------------------------------------
// ---------- RPProjectMFC
// ----------------------------------------------------------------------------
RPProjectMFC::RPProjectMFC():
	RPProject()
{
}

RPProjectMFC::~RPProjectMFC()
{
	std::list< RPCtrlToolbarMFC* >::iterator it = toolbars.begin();
	while ( it != toolbars.end() ) {
		delete *it;
		it++;
	}
	toolbars.clear();
}

std::ofstream& RPProjectMFC::log() const
{
	return studioApp.log;
}

RPCtrlToolbar* RPProjectMFC::createToolBar( const rp::string& caption )
{
	RPCtrlToolbarMFC* toolbar = new RPCtrlToolbarMFC( studioApp.mainFrame );
	toolbars.push_back( toolbar );
	studioApp.mainFrame->insertToolBar( &toolbar->toolbar );
	toolbar->setCaption( caption );
	return toolbar;
}

RPPixmap* RPProjectMFC::createBitmap( char* xpm[] )
{
	return new RPPixmap( xpm );
}
/*
bool RPProjectMFC::lockResource( rpMethod::RPMethod* method )
{
	RPMethodPlugin* plugin = studioApp.getMethodManager().find( method );
	if ( plugin ) {
		AfxSetResourceHandle( plugin->getLib() );
		return true;
	}
	return false;
}

void RPProjectMFC::unlockResource()
{
	AfxSetResourceHandle( studioApp.m_hInstance );
}

HWND RPProjectMFC::getMainWnd()
{
	return AfxGetMainWnd()->m_hWnd;
}
*/
void RPProjectMFC::open()
{
	try {
		rp::RPXML xml_doc;
		rp::RPXMLNode* project_node = xml_doc.open( "c:\\sample.xml" );
		if ( project_node ) {
			load( project_node );
		}
	} catch ( rp::RPXMLException& ex ) {
		studioApp.mainFrame->MessageBox( ex.getError().c_str(), NULL, MB_ICONERROR );
	}
}

void RPProjectMFC::save()
{
	try {
		rp::RPXML xml_doc;
		rp::RPXMLNode* project_node = xml_doc.getDocument().makeChild( "project" );
		save_child( project_node );
		xml_doc.save( "c:\\sample.xml" );
	} catch ( rp::RPXMLException& ex ) {
		studioApp.mainFrame->MessageBox( ex.getError().c_str(), NULL, MB_ICONERROR );
	}
}

void RPProjectMFC::load( rp::RPXMLNode* node )
{
	rp::RPXMLNode* flowchart_node = NULL;
	while ( flowchart_node = node->nextChild(flowchart_node) ) {
		if ( flowchart_node->getName() == "flowchart" ) {
			RPObjectFlowChart* flowobj = static_cast<RPObjectFlowChart*>(rpMethod::factory->getNewObject( flowchart_node->getAttribute("class"), rpMethod::project ));
			flowobj->load( flowchart_node );
		}
	}
}

void RPProjectMFC::makeFlowChartWnd( RPObjectFlowChart* flowobj )
{
	BOOL maximized = false;
	studioApp.mainFrame->MDIGetActive( &maximized );
	RPDoc* doc = static_cast<RPDoc*>(model->flowchartDocTemplate->OpenDocumentFile( NULL ));
	RPChildFrame* mdi = static_cast<RPChildFrame*>(doc->getView()->GetParent());
	mdi->SetIcon( flowobj->getMethod()->getPixmap()->getIcon(), true );
	if ( maximized ) {
		mdi->ShowWindow( SW_HIDE );
		mdi->MDIRestore();
		mdi->ShowWindow( SW_HIDE );
	}
	doc->getView()->makeFlowChartWnd( flowobj );
	flowobj->setCorrectName( flowobj->getClassInfo()->getLabel() );
	if ( maximized ) {
		mdi->MDIMaximize();
	}
/*
CDocument::SetTitle

CChildFrame::OnUpdateFrameTitle       mdi

CFrameWnd::OnUpdateFrameTitle

AfxSetWindowText     (   ) ,     .
CViewXXX    CMDIChildWnd
*/
}
<commit_msg> - удалено лишнее<commit_after>#include "rdo_studio/stdafx.h"
#include "rdo_studio/rdo_process/rdoprocess_project.h"
#include "rdo_studio/rdostudioapp.h"
#include "rdo_studio/rdo_process/rdoprocess_childfrm.h"
#include "rdo_studio/rdo_process/rdoprocess_docview.h"
#include "rdo_studio/rdo_process/rdoprocess_toolbar.h"
#include "rdo_studio/rdo_process/rp_misc/rdoprocess_pixmap.h"
#include "rdo_studio/rdo_process/rp_method/rdoprocess_object_flowchart.h"
#include "rdo_studio/rdo_process/rp_method/rdoprocess_method.h"
#include "rdo_studio/rdo_process/rp_misc/rdoprocess_xml.h"

#include "rdo_studio/rdostudiomodel.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

// ----------------------------------------------------------------------------
// ---------- RPProjectMFC
// ----------------------------------------------------------------------------
RPProjectMFC::RPProjectMFC():
	RPProject()
{
}

RPProjectMFC::~RPProjectMFC()
{
	std::list< RPCtrlToolbarMFC* >::iterator it = toolbars.begin();
	while ( it != toolbars.end() ) {
		delete *it;
		it++;
	}
	toolbars.clear();
}

std::ofstream& RPProjectMFC::log() const
{
	return studioApp.log;
}

RPCtrlToolbar* RPProjectMFC::createToolBar( const rp::string& caption )
{
	RPCtrlToolbarMFC* toolbar = new RPCtrlToolbarMFC( studioApp.mainFrame );
	toolbars.push_back( toolbar );
	studioApp.mainFrame->insertToolBar( &toolbar->toolbar );
	toolbar->setCaption( caption );
	return toolbar;
}

RPPixmap* RPProjectMFC::createBitmap( char* xpm[] )
{
	return new RPPixmap( xpm );
}
/*
bool RPProjectMFC::lockResource( rpMethod::RPMethod* method )
{
	RPMethodPlugin* plugin = studioApp.getMethodManager().find( method );
	if ( plugin ) {
		AfxSetResourceHandle( plugin->getLib() );
		return true;
	}
	return false;
}

void RPProjectMFC::unlockResource()
{
	AfxSetResourceHandle( studioApp.m_hInstance );
}

HWND RPProjectMFC::getMainWnd()
{
	return AfxGetMainWnd()->m_hWnd;
}
*/
void RPProjectMFC::open()
{
	try {
		rp::RPXML xml_doc;
		rp::RPXMLNode* project_node = xml_doc.open( "c:\\sample.xml" );
		if ( project_node ) {
			load( project_node );
		}
	} catch ( rp::RPXMLException& ex ) {
		studioApp.mainFrame->MessageBox( ex.getError().c_str(), NULL, MB_ICONERROR );
	}
}

void RPProjectMFC::save()
{
	try {
		rp::RPXML xml_doc;
		rp::RPXMLNode* project_node = xml_doc.getDocument().makeChild( "project" );
		save_child( project_node );
		xml_doc.save( "c:\\sample.xml" );
	} catch ( rp::RPXMLException& ex ) {
		studioApp.mainFrame->MessageBox( ex.getError().c_str(), NULL, MB_ICONERROR );
	}
}

void RPProjectMFC::load( rp::RPXMLNode* node )
{
	rp::RPXMLNode* flowchart_node = NULL;
	while ( flowchart_node = node->nextChild(flowchart_node) ) {
		if ( flowchart_node->getName() == "flowchart" ) {
			RPObjectFlowChart* flowobj = static_cast<RPObjectFlowChart*>(rpMethod::factory->getNewObject( flowchart_node->getAttribute("class"), rpMethod::project ));
			flowobj->load( flowchart_node );
		}
	}
}

void RPProjectMFC::makeFlowChartWnd( RPObjectFlowChart* flowobj )
{
/*
CDocument::SetTitle

CChildFrame::OnUpdateFrameTitle       mdi

CFrameWnd::OnUpdateFrameTitle

AfxSetWindowText     (   ) ,     .
CViewXXX    CMDIChildWnd
*/
}
<|endoftext|>


<commit_before>// MIT License
//
// Copyright (c) 2016-2017 Simon Ninon <simon.ninon@gmail.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#include <tacopie/utils/logger.hpp>
#include <tacopie/utils/thread_pool.hpp>

namespace tacopie {

namespace utils {

//!
//! ctor & dtor
//!

thread_pool::thread_pool(std::size_t nb_threads) {
  __TACOPIE_LOG(debug, "create thread_pool");
  set_nb_threads(nb_threads);
}

thread_pool::~thread_pool(void) {
  __TACOPIE_LOG(debug, "destroy thread_pool");
  stop();
}

//!
//! worker main loop
//!

void
thread_pool::run(void) {
  __TACOPIE_LOG(debug, "start run() worker");

  while (true) {
    auto res     = fetch_task_or_stop();
    bool stopped = res.first;
    task_t task  = res.second;

    //! if thread has been requested to stop, stop it here
    if (stopped) {
      break;
    }

    //! execute task
    if (task) {
      __TACOPIE_LOG(debug, "execute task");

      try {
        task();
      }
      catch (const std::exception&) {
        __TACOPIE_LOG(warn, "uncatched exception propagated up to the threadpool.")
      }

      __TACOPIE_LOG(debug, "execution complete");
    }
  }

  __TACOPIE_LOG(debug, "stop run() worker");
}

//!
//! stop the thread pool and wait for workers completion
//!

void
thread_pool::stop(void) {
  if (!is_running()) { return; }

  m_should_stop = true;
  m_tasks_condvar.notify_all();

  for (auto& worker : m_workers) { worker.join(); }

  m_workers.clear();

  __TACOPIE_LOG(debug, "thread_pool stopped");
}

//!
//! whether the thread_pool is running or not
//!
bool
thread_pool::is_running(void) const {
  return !m_should_stop;
}

//!
//! whether the current thread should stop or not
//!
bool
thread_pool::should_stop(void) const {
  return m_should_stop || m_nb_running_threads > m_max_nb_threads;
}

//!
//! retrieve a new task
//!

std::pair<bool, thread_pool::task_t>
thread_pool::fetch_task_or_stop(void) {
  std::unique_lock<std::mutex> lock(m_tasks_mtx);

  __TACOPIE_LOG(debug, "waiting to fetch task");

  m_tasks_condvar.wait(lock, [&] { return should_stop() || !m_tasks.empty(); });

  if (should_stop()) {
    --m_nb_running_threads;
    return {true, nullptr};
  }

  task_t task = std::move(m_tasks.front());
  m_tasks.pop();
  return {false, task};
}

//!
//! add tasks to thread pool
//!

void
thread_pool::add_task(const task_t& task) {
  std::lock_guard<std::mutex> lock(m_tasks_mtx);

  __TACOPIE_LOG(debug, "add task to thread_pool");

  m_tasks.push(task);
  m_tasks_condvar.notify_all();
}

thread_pool&
thread_pool::operator<<(const task_t& task) {
  add_task(task);

  return *this;
}

//!
//! adjust number of threads
//!
void
thread_pool::set_nb_threads(std::size_t nb_threads) {
  m_max_nb_threads = nb_threads;

  //! if we increased the number of threads, spawn them
  while (m_nb_running_threads < m_max_nb_threads) {
    ++m_nb_running_threads;
    m_workers.push_back(std::thread(std::bind(&thread_pool::run, this)));
  }

  //! otherwise, wake up threads to make them stop if necessary (until we get the right amount of threads)
  if (m_nb_running_threads > m_max_nb_threads) {
    m_tasks_condvar.notify_all();
  }
}

} // namespace utils

} // namespace tacopie
<commit_msg>Update thread_pool.cpp, switch from notify_all to notify_one (#39)<commit_after>// MIT License
//
// Copyright (c) 2016-2017 Simon Ninon <simon.ninon@gmail.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#include <tacopie/utils/logger.hpp>
#include <tacopie/utils/thread_pool.hpp>

namespace tacopie {

namespace utils {

//!
//! ctor & dtor
//!

thread_pool::thread_pool(std::size_t nb_threads) {
  __TACOPIE_LOG(debug, "create thread_pool");
  set_nb_threads(nb_threads);
}

thread_pool::~thread_pool(void) {
  __TACOPIE_LOG(debug, "destroy thread_pool");
  stop();
}

//!
//! worker main loop
//!

void
thread_pool::run(void) {
  __TACOPIE_LOG(debug, "start run() worker");

  while (true) {
    auto res     = fetch_task_or_stop();
    bool stopped = res.first;
    task_t task  = res.second;

    //! if thread has been requested to stop, stop it here
    if (stopped) {
      break;
    }

    //! execute task
    if (task) {
      __TACOPIE_LOG(debug, "execute task");

      try {
        task();
      }
      catch (const std::exception&) {
        __TACOPIE_LOG(warn, "uncatched exception propagated up to the threadpool.")
      }

      __TACOPIE_LOG(debug, "execution complete");
    }
  }

  __TACOPIE_LOG(debug, "stop run() worker");
}

//!
//! stop the thread pool and wait for workers completion
//!

void
thread_pool::stop(void) {
  if (!is_running()) { return; }

  m_should_stop = true;
  m_tasks_condvar.notify_all();

  for (auto& worker : m_workers) { worker.join(); }

  m_workers.clear();

  __TACOPIE_LOG(debug, "thread_pool stopped");
}

//!
//! whether the thread_pool is running or not
//!
bool
thread_pool::is_running(void) const {
  return !m_should_stop;
}

//!
//! whether the current thread should stop or not
//!
bool
thread_pool::should_stop(void) const {
  return m_should_stop || m_nb_running_threads > m_max_nb_threads;
}

//!
//! retrieve a new task
//!

std::pair<bool, thread_pool::task_t>
thread_pool::fetch_task_or_stop(void) {
  std::unique_lock<std::mutex> lock(m_tasks_mtx);

  __TACOPIE_LOG(debug, "waiting to fetch task");

  m_tasks_condvar.wait(lock, [&] { return should_stop() || !m_tasks.empty(); });

  if (should_stop()) {
    --m_nb_running_threads;
    return {true, nullptr};
  }

  task_t task = std::move(m_tasks.front());
  m_tasks.pop();
  return {false, task};
}

//!
//! add tasks to thread pool
//!

void
thread_pool::add_task(const task_t& task) {
  std::lock_guard<std::mutex> lock(m_tasks_mtx);

  __TACOPIE_LOG(debug, "add task to thread_pool");

  m_tasks.push(task);
  m_tasks_condvar.notify_one();
}

thread_pool&
thread_pool::operator<<(const task_t& task) {
  add_task(task);

  return *this;
}

//!
//! adjust number of threads
//!
void
thread_pool::set_nb_threads(std::size_t nb_threads) {
  m_max_nb_threads = nb_threads;

  //! if we increased the number of threads, spawn them
  while (m_nb_running_threads < m_max_nb_threads) {
    ++m_nb_running_threads;
    m_workers.push_back(std::thread(std::bind(&thread_pool::run, this)));
  }

  //! otherwise, wake up threads to make them stop if necessary (until we get the right amount of threads)
  if (m_nb_running_threads > m_max_nb_threads) {
    m_tasks_condvar.notify_all();
  }
}

} // namespace utils

} // namespace tacopie
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko
 *
 * This library 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 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#ifndef MAPNIK_CONFIG_ERROR_INCLUDED
#define MAPNIK_CONFIG_ERROR_INCLUDED

#include <iostream>
#include <sstream>

namespace mapnik {

    class config_error : public std::exception
    {
        public:
            config_error() {}

            config_error( const std::string & what ) :
                what_( what )
            {
            }
            virtual ~config_error() throw() {};

            virtual const char * what() const throw()
            {
                std::ostringstream os;
                os << what_;
                if ( ! context_.empty() )
                {
                    os << std::endl << context_;
                }
                os << ".";
                return os.str().c_str();
            }

            void append_context(const std::string & ctx) const
            {
                if ( ! context_.empty() )
                {
                    context_ += " ";
                }
                context_ += ctx;
            }

        protected:
            std::string what_;
            mutable std::string context_;
    };
}

#endif // MAPNIK_CONFIG_ERROR_INCLUDED
<commit_msg> - found and fixed another wild pointer<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko
 *
 * This library 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 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#ifndef MAPNIK_CONFIG_ERROR_INCLUDED
#define MAPNIK_CONFIG_ERROR_INCLUDED

#include <iostream>
#include <sstream>

namespace mapnik {

    class config_error : public std::exception
    {
        public:
            config_error() {}

            config_error( const std::string & what ) :
                what_( what )
            {
            }
            virtual ~config_error() throw() {};

            virtual const char * what() const throw()
            {
                return what_.c_str();
            }

            void append_context(const std::string & ctx) const
            {
                what_ += " " + ctx;
            }

        protected:
            mutable std::string what_;
    };
}

#endif // MAPNIK_CONFIG_ERROR_INCLUDED
<|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_ASTITERATOR_HH__
#define __MINIZINC_ASTITERATOR_HH__

#include <minizinc/ast.hh>
#include <minizinc/hash.hh>

namespace MiniZinc {

  /**
   * \brief Bottom-up iterator for expressions
   */
  template<class T>
  class BottomUpIterator {
  protected:
    /// The visitor to call back during iteration
    T& _t;

    /// Stack item
    struct C {
      /// Expression on the stack
      Expression* _e;
      /// Whether this expression has been visited before
      bool _done;
      /// If part of a generator expression, which one it is
      int _gen_i;
      /// Constructor
      C(Expression* e) : _e(e), _done(false), _gen_i(-1) {}
      /// Constructor for generator expression
      C(Expression* e, int gen_i) : _e(e), _done(true), _gen_i(gen_i) {}
    };

    /// Push all elements of \a v onto \a stack
    template<class E>
    void pushVec(std::vector<C>& stack, ASTExprVec<E> v) {
      for (unsigned int i=0; i<v.size(); i++)
        stack.push_back(C(v[i]));
    }

  public:
    /// Constructor
    BottomUpIterator(T& t) : _t(t) {}
    /// Run iterator on expression \a e
    void run(Expression* e);
  };

  template<class T>
  void bottomUp(T& t, Expression* e) {
    BottomUpIterator<T>(t).run(e);
  }

  /**
   * \brief Leaf iterator for expressions
   */
  template<class T>
  class TopDownIterator {
  protected:
    /// The visitor to call back during iteration
    T& _t;

    /// Push all elements of \a v onto \a stack
    template<class E>
    static void pushVec(std::vector<Expression*>& stack, ASTExprVec<E> v) {
      for (unsigned int i=0; i<v.size(); i++)
        stack.push_back(v[i]);
    }

  public:
    /// Constructor
    TopDownIterator(T& t) : _t(t) {}
    /// Run iterator on expression \a e
    void run(Expression* e);
  };

  template<class T>
  void topDown(T& t, Expression* e) {
    TopDownIterator<T>(t).run(e);
  }

  /* IMPLEMENTATION */

  template<class T> void
  BottomUpIterator<T>::run(Expression* root) {
    std::vector<C> stack;
    if (_t.enter(root))
      stack.push_back(C(root));
    while (!stack.empty()) {
      C& c = stack.back();
      if (c._e==NULL) {
        stack.pop_back();
        continue;
      }
      if (c._done) {
        switch (c._e->eid()) {
        case Expression::E_INTLIT:
          _t.vIntLit(*c._e->template cast<IntLit>());
          break;
        case Expression::E_FLOATLIT:
          _t.vFloatLit(*c._e->template cast<FloatLit>());
          break;
        case Expression::E_SETLIT:
          _t.vSetLit(*c._e->template cast<SetLit>());
          break;
        case Expression::E_BOOLLIT:
          _t.vBoolLit(*c._e->template cast<BoolLit>());
          break;
        case Expression::E_STRINGLIT:
          _t.vStringLit(*c._e->template cast<StringLit>());
          break;
        case Expression::E_ID:
          _t.vId(*c._e->template cast<Id>());
          break;
        case Expression::E_ANON:
          _t.vAnonVar(*c._e->template cast<AnonVar>());
          break;
        case Expression::E_ARRAYLIT:
          _t.vArrayLit(*c._e->template cast<ArrayLit>());
          break;
        case Expression::E_ARRAYACCESS:
          _t.vArrayAccess(*c._e->template cast<ArrayAccess>());
          break;
        case Expression::E_COMP:
          if (c._gen_i >= 0) {
            _t.vComprehensionGenerator(*c._e->template cast<Comprehension>(), c._gen_i);
          } else {
            _t.vComprehension(*c._e->template cast<Comprehension>());
          }
          break;
        case Expression::E_ITE:
          _t.vITE(*c._e->template cast<ITE>());
          break;
        case Expression::E_BINOP:
          _t.vBinOp(*c._e->template cast<BinOp>());
          break;
        case Expression::E_UNOP:
          _t.vUnOp(*c._e->template cast<UnOp>());
          break;
        case Expression::E_CALL:
          _t.vCall(*c._e->template cast<Call>());
          break;
        case Expression::E_VARDECL:
          _t.vVarDecl(*c._e->template cast<VarDecl>());
          break;
        case Expression::E_LET:
          _t.vLet(*c._e->template cast<Let>());
          break;
        case Expression::E_TI:
          _t.vTypeInst(*c._e->template cast<TypeInst>());
          break;
        case Expression::E_TIID:
          _t.vTIId(*c._e->template cast<TIId>());
          break;
        }
        _t.exit(c._e);
        stack.pop_back();
      } else {
        c._done=true;
        Expression* ce = c._e;
        for (ExpressionSetIter it = ce->ann().begin(); it != ce->ann().end(); ++it) {
          if (_t.enter(*it))
            stack.push_back(C(*it));
        }
        if (_t.enter(ce)) {
          switch (ce->eid()) {
          case Expression::E_INTLIT:
          case Expression::E_FLOATLIT:
          case Expression::E_BOOLLIT:
          case Expression::E_STRINGLIT:
          case Expression::E_ANON:
          case Expression::E_ID:
          case Expression::E_TIID:
            break;
          case Expression::E_SETLIT:
            pushVec(stack, ce->template cast<SetLit>()->v());
            break;
          case Expression::E_ARRAYLIT:
            pushVec(stack, ce->template cast<ArrayLit>()->v());
            break;
          case Expression::E_ARRAYACCESS:
            pushVec(stack, ce->template cast<ArrayAccess>()->idx());
            stack.push_back(C(ce->template cast<ArrayAccess>()->v()));
            break;
          case Expression::E_COMP:
            {
              Comprehension* comp = ce->template cast<Comprehension>();
              stack.push_back(C(comp->e()));
              stack.push_back(C(comp->where()));
              for (unsigned int i=comp->n_generators(); i--; ) {
                for (unsigned int j=comp->n_decls(i); j--; ) {
                  stack.push_back(C(comp->decl(i, j)));
                }
                stack.push_back(C(comp,i));
                stack.push_back(C(comp->in(i)));
              }
            }
            break;
          case Expression::E_ITE:
            {
              ITE* ite = ce->template cast<ITE>();
              stack.push_back(C(ite->e_else()));
              for (int i=0; i<ite->size(); i++) {
                stack.push_back(C(ite->e_if(i)));
                stack.push_back(C(ite->e_then(i)));
              }
            }
            break;
          case Expression::E_BINOP:
            stack.push_back(C(ce->template cast<BinOp>()->rhs()));
            stack.push_back(C(ce->template cast<BinOp>()->lhs()));
            break;
          case Expression::E_UNOP:
            stack.push_back(C(ce->template cast<UnOp>()->e()));
            break;
          case Expression::E_CALL:
            pushVec(stack, ce->template cast<Call>()->args());
            break;
          case Expression::E_VARDECL:
            stack.push_back(C(ce->template cast<VarDecl>()->e()));
            stack.push_back(C(ce->template cast<VarDecl>()->ti()));
            break;
          case Expression::E_LET:
            stack.push_back(C(ce->template cast<Let>()->in()));
            pushVec(stack, ce->template cast<Let>()->let());
            break;
          case Expression::E_TI:
            stack.push_back(C(ce->template cast<TypeInst>()->domain()));
            pushVec(stack,ce->template cast<TypeInst>()->ranges());
            break;
          }
        } else {
          c._e = NULL;
        }
      }
    }
  }

  template<class T> void
  TopDownIterator<T>::run(Expression* root) {
    std::vector<Expression*> stack;
    if (_t.enter(root))
      stack.push_back(root);
    while (!stack.empty()) {
      Expression* e = stack.back();
      stack.pop_back();
      if (e==NULL) {
        continue;
      }
      switch (e->eid()) {
        case Expression::E_INTLIT:
        _t.vIntLit(*e->template cast<IntLit>());
        break;
        case Expression::E_FLOATLIT:
        _t.vFloatLit(*e->template cast<FloatLit>());
        break;
        case Expression::E_SETLIT:
        _t.vSetLit(*e->template cast<SetLit>());
        pushVec(stack, e->template cast<SetLit>()->v());
        break;
        case Expression::E_BOOLLIT:
        _t.vBoolLit(*e->template cast<BoolLit>());
        break;
        case Expression::E_STRINGLIT:
        _t.vStringLit(*e->template cast<StringLit>());
        break;
        case Expression::E_ID:
        _t.vId(*e->template cast<Id>());
        break;
        case Expression::E_ANON:
        _t.vAnonVar(*e->template cast<AnonVar>());
        break;
        case Expression::E_ARRAYLIT:
        _t.vArrayLit(*e->template cast<ArrayLit>());
        pushVec(stack, e->template cast<ArrayLit>()->v());
        break;
        case Expression::E_ARRAYACCESS:
        _t.vArrayAccess(*e->template cast<ArrayAccess>());
        pushVec(stack, e->template cast<ArrayAccess>()->idx());
        stack.push_back(e->template cast<ArrayAccess>()->v());
        break;
        case Expression::E_COMP:
        _t.vComprehension(*e->template cast<Comprehension>());
        {
          Comprehension* comp = e->template cast<Comprehension>();
          stack.push_back(comp->where());
          for (unsigned int i=comp->n_generators(); i--; ) {
            stack.push_back(comp->in(i));
            for (unsigned int j=comp->n_decls(i); j--; ) {
              stack.push_back(comp->decl(i, j));
            }
          }
          stack.push_back(comp->e());
        }
        break;
        case Expression::E_ITE:
        _t.vITE(*e->template cast<ITE>());
        {
          ITE* ite = e->template cast<ITE>();
          stack.push_back(ite->e_else());
          for (int i=0; i<ite->size(); i++) {
            stack.push_back(ite->e_if(i));
            stack.push_back(ite->e_then(i));
          }
        }
        break;
        case Expression::E_BINOP:
        _t.vBinOp(*e->template cast<BinOp>());
        stack.push_back(e->template cast<BinOp>()->rhs());
        stack.push_back(e->template cast<BinOp>()->lhs());
        break;
        case Expression::E_UNOP:
        _t.vUnOp(*e->template cast<UnOp>());
        stack.push_back(e->template cast<UnOp>()->e());
        break;
        case Expression::E_CALL:
        _t.vCall(*e->template cast<Call>());
        pushVec(stack, e->template cast<Call>()->args());
        break;
        case Expression::E_VARDECL:
        _t.vVarDecl(*e->template cast<VarDecl>());
        stack.push_back(e->template cast<VarDecl>()->e());
        stack.push_back(e->template cast<VarDecl>()->ti());
        break;
        case Expression::E_LET:
        _t.vLet(*e->template cast<Let>());
        stack.push_back(e->template cast<Let>()->in());
        pushVec(stack, e->template cast<Let>()->let());
        break;
        case Expression::E_TI:
        _t.vTypeInst(*e->template cast<TypeInst>());
        stack.push_back(e->template cast<TypeInst>()->domain());
        pushVec(stack,e->template cast<TypeInst>()->ranges());
        break;
        case Expression::E_TIID:
        _t.vTIId(*e->template cast<TIId>());
        break;
      }
    }
  }

}

#endif
<commit_msg>Add enter method to top down iterator (was not used properly before)<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_ASTITERATOR_HH__
#define __MINIZINC_ASTITERATOR_HH__

#include <minizinc/ast.hh>
#include <minizinc/hash.hh>

namespace MiniZinc {

  /**
   * \brief Bottom-up iterator for expressions
   */
  template<class T>
  class BottomUpIterator {
  protected:
    /// The visitor to call back during iteration
    T& _t;

    /// Stack item
    struct C {
      /// Expression on the stack
      Expression* _e;
      /// Whether this expression has been visited before
      bool _done;
      /// If part of a generator expression, which one it is
      int _gen_i;
      /// Constructor
      C(Expression* e) : _e(e), _done(false), _gen_i(-1) {}
      /// Constructor for generator expression
      C(Expression* e, int gen_i) : _e(e), _done(true), _gen_i(gen_i) {}
    };

    /// Push all elements of \a v onto \a stack
    template<class E>
    void pushVec(std::vector<C>& stack, ASTExprVec<E> v) {
      for (unsigned int i=0; i<v.size(); i++)
        stack.push_back(C(v[i]));
    }

  public:
    /// Constructor
    BottomUpIterator(T& t) : _t(t) {}
    /// Run iterator on expression \a e
    void run(Expression* e);
  };

  template<class T>
  void bottomUp(T& t, Expression* e) {
    BottomUpIterator<T>(t).run(e);
  }

  /**
   * \brief Leaf iterator for expressions
   */
  template<class T>
  class TopDownIterator {
  protected:
    /// The visitor to call back during iteration
    T& _t;

    /// Push all elements of \a v onto \a stack
    template<class E>
    static void pushVec(std::vector<Expression*>& stack, ASTExprVec<E> v) {
      for (unsigned int i=0; i<v.size(); i++)
        stack.push_back(v[i]);
    }

  public:
    /// Constructor
    TopDownIterator(T& t) : _t(t) {}
    /// Run iterator on expression \a e
    void run(Expression* e);
  };

  template<class T>
  void topDown(T& t, Expression* e) {
    TopDownIterator<T>(t).run(e);
  }

  /* IMPLEMENTATION */

  template<class T> void
  BottomUpIterator<T>::run(Expression* root) {
    std::vector<C> stack;
    if (_t.enter(root))
      stack.push_back(C(root));
    while (!stack.empty()) {
      C& c = stack.back();
      if (c._e==NULL) {
        stack.pop_back();
        continue;
      }
      if (c._done) {
        switch (c._e->eid()) {
        case Expression::E_INTLIT:
          _t.vIntLit(*c._e->template cast<IntLit>());
          break;
        case Expression::E_FLOATLIT:
          _t.vFloatLit(*c._e->template cast<FloatLit>());
          break;
        case Expression::E_SETLIT:
          _t.vSetLit(*c._e->template cast<SetLit>());
          break;
        case Expression::E_BOOLLIT:
          _t.vBoolLit(*c._e->template cast<BoolLit>());
          break;
        case Expression::E_STRINGLIT:
          _t.vStringLit(*c._e->template cast<StringLit>());
          break;
        case Expression::E_ID:
          _t.vId(*c._e->template cast<Id>());
          break;
        case Expression::E_ANON:
          _t.vAnonVar(*c._e->template cast<AnonVar>());
          break;
        case Expression::E_ARRAYLIT:
          _t.vArrayLit(*c._e->template cast<ArrayLit>());
          break;
        case Expression::E_ARRAYACCESS:
          _t.vArrayAccess(*c._e->template cast<ArrayAccess>());
          break;
        case Expression::E_COMP:
          if (c._gen_i >= 0) {
            _t.vComprehensionGenerator(*c._e->template cast<Comprehension>(), c._gen_i);
          } else {
            _t.vComprehension(*c._e->template cast<Comprehension>());
          }
          break;
        case Expression::E_ITE:
          _t.vITE(*c._e->template cast<ITE>());
          break;
        case Expression::E_BINOP:
          _t.vBinOp(*c._e->template cast<BinOp>());
          break;
        case Expression::E_UNOP:
          _t.vUnOp(*c._e->template cast<UnOp>());
          break;
        case Expression::E_CALL:
          _t.vCall(*c._e->template cast<Call>());
          break;
        case Expression::E_VARDECL:
          _t.vVarDecl(*c._e->template cast<VarDecl>());
          break;
        case Expression::E_LET:
          _t.vLet(*c._e->template cast<Let>());
          break;
        case Expression::E_TI:
          _t.vTypeInst(*c._e->template cast<TypeInst>());
          break;
        case Expression::E_TIID:
          _t.vTIId(*c._e->template cast<TIId>());
          break;
        }
        _t.exit(c._e);
        stack.pop_back();
      } else {
        c._done=true;
        Expression* ce = c._e;
        for (ExpressionSetIter it = ce->ann().begin(); it != ce->ann().end(); ++it) {
          if (_t.enter(*it))
            stack.push_back(C(*it));
        }
        if (_t.enter(ce)) {
          switch (ce->eid()) {
          case Expression::E_INTLIT:
          case Expression::E_FLOATLIT:
          case Expression::E_BOOLLIT:
          case Expression::E_STRINGLIT:
          case Expression::E_ANON:
          case Expression::E_ID:
          case Expression::E_TIID:
            break;
          case Expression::E_SETLIT:
            pushVec(stack, ce->template cast<SetLit>()->v());
            break;
          case Expression::E_ARRAYLIT:
            pushVec(stack, ce->template cast<ArrayLit>()->v());
            break;
          case Expression::E_ARRAYACCESS:
            pushVec(stack, ce->template cast<ArrayAccess>()->idx());
            stack.push_back(C(ce->template cast<ArrayAccess>()->v()));
            break;
          case Expression::E_COMP:
            {
              Comprehension* comp = ce->template cast<Comprehension>();
              stack.push_back(C(comp->e()));
              stack.push_back(C(comp->where()));
              for (unsigned int i=comp->n_generators(); i--; ) {
                for (unsigned int j=comp->n_decls(i); j--; ) {
                  stack.push_back(C(comp->decl(i, j)));
                }
                stack.push_back(C(comp,i));
                stack.push_back(C(comp->in(i)));
              }
            }
            break;
          case Expression::E_ITE:
            {
              ITE* ite = ce->template cast<ITE>();
              stack.push_back(C(ite->e_else()));
              for (int i=0; i<ite->size(); i++) {
                stack.push_back(C(ite->e_if(i)));
                stack.push_back(C(ite->e_then(i)));
              }
            }
            break;
          case Expression::E_BINOP:
            stack.push_back(C(ce->template cast<BinOp>()->rhs()));
            stack.push_back(C(ce->template cast<BinOp>()->lhs()));
            break;
          case Expression::E_UNOP:
            stack.push_back(C(ce->template cast<UnOp>()->e()));
            break;
          case Expression::E_CALL:
            pushVec(stack, ce->template cast<Call>()->args());
            break;
          case Expression::E_VARDECL:
            stack.push_back(C(ce->template cast<VarDecl>()->e()));
            stack.push_back(C(ce->template cast<VarDecl>()->ti()));
            break;
          case Expression::E_LET:
            stack.push_back(C(ce->template cast<Let>()->in()));
            pushVec(stack, ce->template cast<Let>()->let());
            break;
          case Expression::E_TI:
            stack.push_back(C(ce->template cast<TypeInst>()->domain()));
            pushVec(stack,ce->template cast<TypeInst>()->ranges());
            break;
          }
        } else {
          c._e = NULL;
        }
      }
    }
  }

  template<class T> void
  TopDownIterator<T>::run(Expression* root) {
    std::vector<Expression*> stack;
    if (_t.enter(root))
      stack.push_back(root);
    while (!stack.empty()) {
      Expression* e = stack.back();
      stack.pop_back();
      if (e==NULL) {
        continue;
      }
      if (!_t.enter(e))
        continue;
      switch (e->eid()) {
        case Expression::E_INTLIT:
        _t.vIntLit(*e->template cast<IntLit>());
        break;
        case Expression::E_FLOATLIT:
        _t.vFloatLit(*e->template cast<FloatLit>());
        break;
        case Expression::E_SETLIT:
        _t.vSetLit(*e->template cast<SetLit>());
        pushVec(stack, e->template cast<SetLit>()->v());
        break;
        case Expression::E_BOOLLIT:
        _t.vBoolLit(*e->template cast<BoolLit>());
        break;
        case Expression::E_STRINGLIT:
        _t.vStringLit(*e->template cast<StringLit>());
        break;
        case Expression::E_ID:
        _t.vId(*e->template cast<Id>());
        break;
        case Expression::E_ANON:
        _t.vAnonVar(*e->template cast<AnonVar>());
        break;
        case Expression::E_ARRAYLIT:
        _t.vArrayLit(*e->template cast<ArrayLit>());
        pushVec(stack, e->template cast<ArrayLit>()->v());
        break;
        case Expression::E_ARRAYACCESS:
        _t.vArrayAccess(*e->template cast<ArrayAccess>());
        pushVec(stack, e->template cast<ArrayAccess>()->idx());
        stack.push_back(e->template cast<ArrayAccess>()->v());
        break;
        case Expression::E_COMP:
        _t.vComprehension(*e->template cast<Comprehension>());
        {
          Comprehension* comp = e->template cast<Comprehension>();
          stack.push_back(comp->where());
          for (unsigned int i=comp->n_generators(); i--; ) {
            stack.push_back(comp->in(i));
            for (unsigned int j=comp->n_decls(i); j--; ) {
              stack.push_back(comp->decl(i, j));
            }
          }
          stack.push_back(comp->e());
        }
        break;
        case Expression::E_ITE:
        _t.vITE(*e->template cast<ITE>());
        {
          ITE* ite = e->template cast<ITE>();
          stack.push_back(ite->e_else());
          for (int i=0; i<ite->size(); i++) {
            stack.push_back(ite->e_if(i));
            stack.push_back(ite->e_then(i));
          }
        }
        break;
        case Expression::E_BINOP:
        _t.vBinOp(*e->template cast<BinOp>());
        stack.push_back(e->template cast<BinOp>()->rhs());
        stack.push_back(e->template cast<BinOp>()->lhs());
        break;
        case Expression::E_UNOP:
        _t.vUnOp(*e->template cast<UnOp>());
        stack.push_back(e->template cast<UnOp>()->e());
        break;
        case Expression::E_CALL:
        _t.vCall(*e->template cast<Call>());
        pushVec(stack, e->template cast<Call>()->args());
        break;
        case Expression::E_VARDECL:
        _t.vVarDecl(*e->template cast<VarDecl>());
        stack.push_back(e->template cast<VarDecl>()->e());
        stack.push_back(e->template cast<VarDecl>()->ti());
        break;
        case Expression::E_LET:
        _t.vLet(*e->template cast<Let>());
        stack.push_back(e->template cast<Let>()->in());
        pushVec(stack, e->template cast<Let>()->let());
        break;
        case Expression::E_TI:
        _t.vTypeInst(*e->template cast<TypeInst>());
        stack.push_back(e->template cast<TypeInst>()->domain());
        pushVec(stack,e->template cast<TypeInst>()->ranges());
        break;
        case Expression::E_TIID:
        _t.vTIId(*e->template cast<TIId>());
        break;
      }
    }
  }

}

#endif
<|endoftext|>