text:
//---------------------------------------------------------------------------//
//!
//! \file   Utility_MaxwellFissionDistribution.hpp
//! \author Aaron Tumulak
//! \brief  Maxwell Fission distribution class declaration. Modified by Alex
//!         Robison to accommodate units.
//!
//---------------------------------------------------------------------------//

#ifndef UTILITY_MAXWELLFISSION_DISTRIBUTION_HPP
#define UTILITY_MAXWELLFISSION_DISTRIBUTION_HPP

// Std Lib Includes
#include <limits>

// Boost Includes
#include <boost/units/physical_dimensions/energy.hpp>
#include <boost/units/dimensionless_type.hpp>

// FRENSIE Includes
#include "Utility_OneDDistribution.hpp"
#include "Utility_ParameterListCompatibleObject.hpp"

namespace Utility{

/*! The unit-aware Maxwell fission distribution class
 * \ingroup one_d_distributions
 */
template<typename IndependentUnit, typename DependentUnit = void>
class UnitAwareMaxwellFissionDistribution : public UnitAwareOneDDistribution<IndependentUnit,DependentUnit>,
					    public ParameterListCompatibleObject<UnitAwareMaxwellFissionDistribution<IndependentUnit,DependentUnit> >
{

  // Only allow construction when the independent unit corresponds to energy
  RESTRICT_UNIT_TO_BOOST_DIMENSION( IndependentUnit, energy_dimension );

private:

  // The distribution multiplier unit traits typedef
  typedef UnitTraits<typename UnitTraits<DependentUnit>::template GetMultipliedUnitType<typename UnitTraits<IndependentUnit>::template GetUnitToPowerType<1,-2>::type>::type> DistMultiplierUnitTraits;

  // The distribution multiplier quantity type
  typedef typename DistMultiplierUnitTraits::template GetQuantityType<double>::type DistMultiplierQuantity;

  // The distribution normalization quantity type
  typedef typename UnitAwareOneDDistribution<IndependentUnit,DependentUnit>::DistNormQuantity DistNormQuantity;

  // Typedef for QuantityTraits<double>
  typedef QuantityTraits<double> QT;

  // Typedef for QuantityTraits<IndepQuantity>
  typedef QuantityTraits<typename UnitAwareOneDDistribution<IndependentUnit,DependentUnit>::IndepQuantity> IQT;

  // Typedef for QuantityTraits<InverseIndepQuantity>
  typedef QuantityTraits<typename UnitAwareOneDDistribution<IndependentUnit,DependentUnit>::InverseIndepQuantity> IIQT;

  // Typedef for QuantityTraits<DepQuantity>
  typedef QuantityTraits<typename UnitAwareOneDDistribution<IndependentUnit,DependentUnit>::DepQuantity> DQT;

  // Typedef for QuantityTraits<DistMultiplierQuantity>
  typedef QuantityTraits<DistMultiplierQuantity> DMQT;

public:

  //! This distribution type
  typedef UnitAwareMaxwellFissionDistribution<IndependentUnit,DependentUnit> ThisType;

  //! The independent quantity type
  typedef typename UnitAwareOneDDistribution<IndependentUnit,DependentUnit>::IndepQuantity IndepQuantity;

  //! The inverse independent quantity type
  typedef typename UnitAwareOneDDistribution<IndependentUnit,DependentUnit>::InverseIndepQuantity InverseIndepQuantity;

  //! The dependent quantity type
  typedef typename UnitAwareOneDDistribution<IndependentUnit,DependentUnit>::DepQuantity DepQuantity;

  //! Default Constructor
  UnitAwareMaxwellFissionDistribution(
			const IndepQuantity incident_energy = IQT::one(),
			const IndepQuantity nuclear_temperature = IQT::one(),
			const IndepQuantity restriction_energy = IQT::zero(),
			const double constant_multiplier = 1.0 );

  //! Constructor
  template<typename InputIndepQuantityA,
	   typename InputIndepQuantityB,
	   typename InputIndepQuantityC>
  UnitAwareMaxwellFissionDistribution(
				const InputIndepQuantityA incident_energy,
				const InputIndepQuantityB nuclear_temperature,
				const InputIndepQuantityC restriction_energy,
				const double constant_multiplier = 1.0 );

  //! Copy constructor
  template<typename InputIndepUnit, typename InputDepUnit>
  UnitAwareMaxwellFissionDistribution( const UnitAwareMaxwellFissionDistribution<InputIndepUnit,InputDepUnit>& dist_instance );

  //! Construct distribution from a unitless dist. (potentially dangerous)
  static UnitAwareMaxwellFissionDistribution fromUnitlessDistribution( const UnitAwareMaxwellFissionDistribution<void,void>& unitless_distribution );

  //! Assignment operator
  UnitAwareMaxwellFissionDistribution& operator=( const UnitAwareMaxwellFissionDistribution& dist_instance );

  //! Destructor
  ~UnitAwareMaxwellFissionDistribution()
  { /* ... */ }

  //! Evaluate the distribution
  DepQuantity evaluate( const IndepQuantity indep_var_value ) const;

  //! Evaluate the PDF
  InverseIndepQuantity evaluatePDF( const IndepQuantity indep_var_value ) const;

  //! Return a random sample from the distribution
  IndepQuantity sample() const;

  //! Return a random sample from the distribution
  static IndepQuantity sample( const IndepQuantity incident_energy,
			       const IndepQuantity nuclear_temperature,
			       const IndepQuantity restriction_energy );

  //! Return a random sample from the distribution and record the number of trials
  IndepQuantity sampleAndRecordTrials( unsigned& trials ) const;

  //! Return a random sample from the corresponding CDF and record the number of trials
  static IndepQuantity sampleAndRecordTrials(
    const IndepQuantity incident_energy,
    const IndepQuantity nuclear_temperature,
    const IndepQuantity restriction_energy,
    unsigned& trials );

  //! Test if the distribution is continuous
  bool isContinuous() const;

  //! Return the upper bound of the distribution independent variable
  IndepQuantity getUpperBoundOfIndepVar() const;

  //! Return the lower bound of the distribution independent variable
  IndepQuantity getLowerBoundOfIndepVar() const;

  //! Return the distribution type
  OneDDistributionType getDistributionType() const;

  //! Method for placing the object in an output stream
  void toStream( std::ostream& os ) const;

  //! Method for initializing the object from an input stream
  void fromStream( std::istream& is );

  //! Method for testing if two objects are equivalent
  bool isEqual( const UnitAwareMaxwellFissionDistribution& other ) const;

protected:

  //! Copy constructor (copying from unitless distribution only)
  UnitAwareMaxwellFissionDistribution( const UnitAwareMaxwellFissionDistribution<void,void>& unitless_dist_instance, int );

private:

  // Calculate the normalization constant of the distribution
  void calculateNormalizationConstant();

  // All possible instantiations are friends
  template<typename FriendIndepUnit, typename FriendDepUnit>
  friend class UnitAwareMaxwellFissionDistribution;

  // The distribution type
  static const OneDDistributionType distribution_type = MAXWELLFISSION_DISTRIBUTION;

  // The incident neutron energy of the distribution
  IndepQuantity d_incident_energy;

  // The nuclear temperature of the distribution
  IndepQuantity d_nuclear_temperature;

  // The restriction energy of the distribution
  IndepQuantity d_restriction_energy;

  // The distribution multiplier
  DistMultiplierQuantity d_multiplier;

  // The distribution normalization constant
  DistNormQuantity d_norm_constant;
};

/*! The Maxwell fission distribution (unit-agnostic)
 * \ingroup one_d_distributions
 */
typedef UnitAwareMaxwellFissionDistribution<void,void> MaxwellFissionDistribution;

} // end Utility namespace

namespace Teuchos{

/*! Type name traits specialization for the Utility::MaxwellFissionDistribution
 *
 * \details The name function will set the type name that must be used in
 * xml files.
 */
template<>
class TypeNameTraits<Utility::MaxwellFissionDistribution>
{
public:
  static std::string name()
  {
    return "Maxwell Fission Distribution";
  }
  static std::string concreteName(
				const Utility::MaxwellFissionDistribution& instance )
  {
    return name();
  }
};

/*! \brief Type name traits partial specialization for the
 * Utility::UnitAwareMaxwellFissionDistribution
 *
 * \details The name function will set the type name that must be used in
 * xml files.
 */
template<typename U,typename V>
class TypeNameTraits<Utility::UnitAwareMaxwellFissionDistribution<U,V> >
{
public:
  static std::string name()
  {
    return "Unit-Aware Maxwell Fission Distribution (" +
      Utility::UnitTraits<U>::symbol() + "," +
      Utility::UnitTraits<V>::symbol() + ")";
  }
  static std::string concreteName(
	    const Utility::UnitAwareMaxwellFissionDistribution<U,V>& instance )
  {
    return name();
  }
};

} // end Teuchos namespace

//---------------------------------------------------------------------------//
// Template Includes
//---------------------------------------------------------------------------//

#include "Utility_MaxwellFissionDistribution_def.hpp"

//---------------------------------------------------------------------------//

#endif // end UTILITY_MAXWELLFISSION_DISTRIBUTION_HPP

//---------------------------------------------------------------------------//
// end Utility_MaxwellFissionDistribution.hpp
//---------------------------------------------------------------------------//


text:
#include "graph.hpp"
#include <iostream>
#include <set>
#include <fstream>
#include "data_type.hpp"

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/max_cardinality_matching.hpp>
#include <boost/graph/breadth_first_search.hpp>
#include <boost/graph/bipartite.hpp>
#include <boost/graph/strong_components.hpp>
#include <boost/property_map/property_map.hpp>
#include <boost/filesystem/fstream.hpp>
#include <regex>

#define MY_DEBUG

using namespace std;
using namespace boost;

#define MEMORYLATENCY 100002
#define FORCE_STOP 15000

/* Constructor */
Graph::Graph(uint64_t n, std::string ldstfile_path, string input_filestring,bool _is_stall_on_bloom , std::string _bloom_type, bool ishash2 , uint64_t mem_lat, int _mem_req_stack ):orig_graph(0) ,in_graph(0), graph_limit(n), m_stall_on_bloom(_is_stall_on_bloom)
{

  g_iter = 0;
  g_input_filestring = input_filestring;
  g_mem_req_stack = _mem_req_stack;
  cout<<"MSHR_SIZE: "<<_mem_req_stack<<endl;
  m_memory = new Memory(m_stall_on_bloom, _bloom_type,ishash2, mem_lat, g_mem_req_stack);
  std::string mlpstr;

  ldstfile.open(ldstfile_path.c_str(), fstream::in );
  if (!ldstfile.is_open())
  {
    cerr << "graph: Error Mem Dump ldst file not reached end Foey!\n";
  }

  cerr<<"ldst: "<<ldstfile_path.c_str()<<endl;

  read_memcsv(ldstfile);
  // D(print_memmap());
  g_en =true;
  g_mem_req_count =0;

  g_total_termination_cycles =0;
  g_total_bloom_yes_ld =0;
  g_total_bloom_yes_st =0;
  g_total_bloom_no_ld =0;
  g_total_bloom_no_st =0;
  g_total_bloom_fp=0;
  g_total_bloom_stall_cycles=0;

  g_total_memops=0;
  g_total_ldops=0;
  g_total_LiveOut =0;

  readGraph();
  //Create Global LSQ nodeids = g_LSQ -> m_memory
  if(g_total_memops*ITER_COUNT >= ITER_COUNT_MEM)
  {
    cerr<<"MEM OPS ARE GREATER THAN EXPECTED : CHANGE ITER_COUNT_MEM IN data_type.hpp\n";
    throw std::exception();

  }
  in_graph = orig_graph;
  this->set_state_maps();
}

Graph::~Graph()
{
}

  void
Graph::printstats()
{
  cout<<"Iter. # of Vertices: "<< num_vertices(in_graph)<<endl;
  cout<<"Iter. # of Edges:  "<< num_edges(in_graph)<<endl;
  cout<<"Iter. # of MemOps (excluding LiveOuts): "<< g_total_memops - g_total_LiveOut<<endl;
  cout<<"Iter. # of Store LiveOuts: "<< g_total_LiveOut<<endl;
  cout<<"Iter. # of Total Ld Ops: "<< g_total_ldops<<endl;

  cout<<"Cumm. Port Busy Cycles:  "<<m_memory->m_port_unavailable<<endl;
  cout<<"Cumm. Total Memory Requests: "<<g_mem_req_count<<endl;
  cout<<"Cumm. Total m_mshr_full_cycles:  "<<m_memory->m_mshr_full_cycles<<endl;

  cout<<"Cumm. TERMINATION CALLED :Total axc termination cycles: " <<g_total_termination_cycles<<endl;
  cout<<"Cumm. Memory:Bloom_filter_ld:Yes: "<< g_total_bloom_yes_ld <<endl;
  cout<<"Cumm. Memory:Bloom_filter_st:Yes: "<< g_total_bloom_yes_st <<endl;
  cout<<"Cumm. Memory:Bloom_filter_ld:NO: "<< g_total_bloom_no_ld <<endl;
  cout<<"Cumm. Memory:Bloom_filter_st:NO: "<< g_total_bloom_no_st <<endl;
  cout<<"Cumm. Memory:Bloom False Positive: "<<g_total_bloom_fp <<endl;
  cout<<"Cumm. Memory:Bloom False Positive percent : "<<
    g_total_bloom_fp/ (float)(g_total_bloom_yes_ld + g_total_bloom_yes_st )*100 <<endl;
  cout<<"Cumm. Memory:Bloom Total stall cycles : "<< g_total_bloom_stall_cycles<<endl;
}

/**
 * Loading dot file and load into BG
 */
  void
Graph::readGraph()
{
  D(cout<<"reading graph\n");
  boost::filesystem::ifstream input_file(g_input_filestring,ios::in);
  assert(input_file.is_open() && "Error! input_file File couldn't open");
  //Vertex dp

  boost::dynamic_properties dp(boost::ignore_other_properties);
  auto vname_dp = get(&vertex_prop::vname, orig_graph);
  dp.property("name", vname_dp);

  auto vir_dp = get(&vertex_prop::vir, orig_graph);
  dp.property("ir", vir_dp);

  auto vlabel_dp = get(&vertex_prop::vlabel, orig_graph);
  dp.property("label", vlabel_dp);

  auto vcolor_dp = get(&vertex_prop::vcolor, orig_graph);
  dp.property("color", vcolor_dp);

  auto vopcode_dp = get(&vertex_prop::vopcode, orig_graph);
  dp.property("opcode", vopcode_dp);

  //Edge dp
  auto ecolor_dp = get(&edge_prop::ecolor, orig_graph);
  dp.property("color",ecolor_dp);

  auto vlatency_dp = get(&vertex_prop::vlatency, orig_graph);
  dp.property("vlatency", vlatency_dp);

  auto vstate_dp = get(&vertex_prop::vstate, orig_graph);
  dp.property("vstate", vstate_dp);

  auto vissue_dp = get(&vertex_prop::vissue, orig_graph);
  dp.property("vissue", vissue_dp);

  auto elatency_dp = get(&edge_prop::elatency, orig_graph);
  dp.property("elatency",elatency_dp);

  auto estate_dp = get(&edge_prop::estate, orig_graph);
  dp.property("estate",estate_dp);

  //-----------------------------------------------------------------------------------
  try
  {
    read_graphviz(input_file, orig_graph, dp, "name");

  }
  catch(std::exception &err)
  {
    cerr << err.what() << endl;
    cerr << "read_graphviz failed \n";
    exit(0);
  }

  //-----------------------------------------------------------------------------------
  //TODO
  // Add termination vertex
  VERTEX u = boost::add_vertex(orig_graph);

  put(&vertex_prop::vstate,orig_graph,u,VNOT_READY);
  put(&vertex_prop::vname,orig_graph,u,99999999);
  put(&vertex_prop::vir,orig_graph,u,"END (TERMINATE)");
  put(&vertex_prop::vlatency,orig_graph,u,1);
  put(&vertex_prop::vopcode,orig_graph,u,"END");
  put(&vertex_prop::vlabel,orig_graph,u,"END");
  put(&vertex_prop::vcolor,orig_graph,u,"Black");

  std::pair<VERTEX_ITER, VERTEX_ITER> v;

  for (v = vertices(orig_graph); v.first != v.second; ++v.first)
  {
    auto EI = out_edges(*v.first,orig_graph);
    if(EI.first ==EI.second && *v.first != u)
    {
      boost::add_edge(*v.first,u,orig_graph);
    }
  }

  //Iterate over property maps of opcode and fill latency in property opcode

  //Add Vertex Properties : vstate based on opcode

  std::pair<VERTEX_ITER, VERTEX_ITER> vp;
  std::set<int> g_LSQ;

  for (vp = vertices(orig_graph); vp.first != vp.second; ++vp.first)
  {
    vlatency_dp[*vp.first] = getOpcodeStr(vopcode_dp[*vp.first]);
    vissue_dp[*vp.first] = false; //Only Used for memory ops

    //-------------
    if (vir_dp[*vp.first].find("!LO") != std::string::npos)
    {
      ++g_total_LiveOut;
      vlatency_dp[*vp.first] = 1; // Latency for Live Outs is 1 : which are store operations by default
      D(cerr<<"graph: LIveOuts \n "<< vir_dp[*vp.first] <<endl);
    }
    // if it is not a !LO  Live Out and it is  a Ld/St then store nodeids in g_LSQ
    else if (vopcode_dp[*vp.first] == "Load" || vopcode_dp[*vp.first] == "Store")
    {
      g_LSQ.insert(vname_dp[*vp.first]);

    }
    //--------------

    if( vopcode_dp[*vp.first] == "Arg" || vopcode_dp[*vp.first] == "Const"
        || vopcode_dp[*vp.first] == "BB")
    {
      vstate_dp[*vp.first] = VCOMPLETE  ;
    }
    else
    {
      vstate_dp[*vp.first] = VNOT_READY  ;
    }

  }

  //print g_LSQ
  std::cout << "g_LSQ contains:";
  for (auto it=g_LSQ.begin(); it!=g_LSQ.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << '\n';

  //Add Edge Properties: etate and elatency

  EDGE_ITER ei, ei_end;
  for (tie(ei, ei_end) = edges(orig_graph); ei != ei_end; ++ei)
  {

    VERTEX v = source(*ei,orig_graph);
    auto tmp_edge_latency = get(&vertex_prop::vlatency,orig_graph,v)  ;
    //Check if the source vertex is a live out then add latency=1 and not MEMORYLATENCY
    //since liveouts are connected to a fake termination edge
    auto tmp_ir = get(&vertex_prop::vir,orig_graph,v);

    //Set Edge Properties : Latency and ESTATE
    if(tmp_ir.find("!LO") == std::string::npos)
    {
      elatency_dp[*ei] = tmp_edge_latency;
    }
    else
      elatency_dp[*ei] = 1;//latency is 1 for Live Out stores

    estate_dp[*ei] = ENOT_READY;

  }

  try
  {
    D(cout<<" Constructed graph:"<<endl);
    D(write_graphviz_dp(std::cout, orig_graph, dp, "name"));
  }
  catch(std::exception &err)
  {
    cerr << err.what() << endl;
    // cerr << "read_graphviz failed for " << input_file << "\n";
    exit(0);
  }

  return;
}

  void
Graph::set_state_maps()
{

  //------------------------------------------------------------------------------------
  //Iterate over property maps of opcode and fill latency in property opcode

  //Add Vertex Properties : vstate based on opcode

  std::pair<VERTEX_ITER, VERTEX_ITER> vp;

  for (vp = vertices(in_graph); vp.first != vp.second; ++vp.first)
  {
    auto vopcode = get(&vertex_prop::vopcode,in_graph,*vp.first);

    if( vopcode == "Arg" || vopcode == "Const"
        || vopcode == "BB"   )
    {

      //Initialize Vertex State Maps
      vertex_state_map[VREADY].push_back(*vp.first);
    }
    else
    {
      //Initialize Vertex State Maps
      vertex_state_map[VNOT_READY].push_back(*vp.first);
    }

  }

  //Add Edge Properties: etate and elatency
  EDGE_ITER ei, ei_end;
  for (tie(ei, ei_end) = edges(in_graph); ei != ei_end; ++ei)
  {
    //Initialize all Edges to NOT_READY: EDGE STATE_MAPS
    edge_state_map[ENOT_READY].push_back(*ei);
  }
}

  void
Graph::initialize(uint64_t _iter)
{

  g_iter = _iter;
  global_clock=0;
  in_graph =0;

  // D(printGraph());

  for( auto &X : vertex_state_map)
  {
    X.clear();
  }
  for( auto &Y : edge_state_map)
  {
    Y.clear();
  }

  in_graph = orig_graph;
  this->set_state_maps();
  m_memory->initialize(m_stall_on_bloom);
  g_rdy = true;
}

/**
 * Writing BG into output file
 */
  void
Graph::printGraph()
{
  cout<<"Printing Graph \n";

  //Vertex dp

  boost::dynamic_properties dp(boost::ignore_other_properties);
  auto vname_dp = get(&vertex_prop::vname, in_graph);
  dp.property("vname", vname_dp);

  auto vir_dp = get(&vertex_prop::vir, in_graph);
  dp.property("vir", vir_dp);

  auto vlabel_dp = get(&vertex_prop::vlabel, in_graph);
  dp.property("vlabel", vlabel_dp);

  auto vcolor_dp = get(&vertex_prop::vcolor, in_graph);
  dp.property("vcolor", vcolor_dp);

  auto vopcode_dp = get(&vertex_prop::vopcode, in_graph);
  dp.property("vopcode", vopcode_dp);

  auto vlatency_dp = get(&vertex_prop::vlatency, in_graph);
  dp.property("vlatency", vlatency_dp);

  auto vstate_dp = get(&vertex_prop::vstate, in_graph);
  dp.property("vstate", vstate_dp);

  //Edge dp
  auto ecolor_dp = get(&edge_prop::ecolor, in_graph);
  dp.property("ecolor",ecolor_dp);

  auto elatency_dp = get(&edge_prop::elatency, in_graph);
  dp.property("elatency",elatency_dp);

  auto estop_dp = get(&edge_prop::estop_time, in_graph);
  dp.property("estop_time",estop_dp);

  auto estart_dp = get(&edge_prop::estart_time, in_graph);
  dp.property("estart_time",estart_dp);

  auto estate_dp = get(&edge_prop::estate, in_graph);
  dp.property("estate",estate_dp);
  //----------------------------------------------------

  auto vissue_dp = get(&vertex_prop::vissue, in_graph);
  dp.property("vissue", vissue_dp);

  //--------------------------

  try
  {
    write_graphviz_dp(std::cout, in_graph, dp, "vname");
  }
  catch(std::exception &err)
  {
    std::cerr << err.what() << endl;
    std::cerr << "wirte_graphviz failed : ";// << output_file << "\n";
    exit(0);
  }

  return;
}

  unsigned int
Graph::getOpcodeStr(string op_code)
{
  map<string, unsigned> mymap;
#define HANDLE_INST(N, OPCODE, CLASS) \
  mymap.insert({string(#OPCODE), N});

  unsigned int  FIRST_TERM_INST;
  unsigned int LAST_TERM_INST;

  unsigned int FIRST_BINARY_INST       ;
  unsigned int LAST_BINARY_INST        ;
  unsigned int FIRST_MEMORY_INST       ;
  unsigned int LAST_MEMORY_INST        ;
  unsigned int FIRST_CAST_INST         ;
  unsigned int LAST_CAST_INST          ;
  unsigned int FIRST_FUNCLETPAD_INST   ;
  unsigned int LAST_FUNCLETPAD_INST    ;
  unsigned int FIRST_OTHER_INST        ;
  unsigned int LAST_OTHER_INST         ;

#define FIRST_TERM_INST(num) \
  FIRST_TERM_INST = num;

#define LAST_TERM_INST(num) \
  LAST_TERM_INST = num;

#define     FIRST_BINARY_INST(num)            FIRST_BINARY_INST             = num;
#define     LAST_BINARY_INST(num)             LAST_BINARY_INST              = num;
#define     FIRST_MEMORY_INST(num)            FIRST_MEMORY_INST             = num;
#define     LAST_MEMORY_INST(num)             LAST_MEMORY_INST              = num;
#define     FIRST_CAST_INST(num)              FIRST_CAST_INST               = num;
#define     LAST_CAST_INST(num)               LAST_CAST_INST                = num;
#define     FIRST_FUNCLETPAD_INST(num)        FIRST_FUNCLETPAD_INST         = num;
#define     LAST_FUNCLETPAD_INST(num)         LAST_FUNCLETPAD_INST          = num;
#define     FIRST_OTHER_INST(num)             FIRST_OTHER_INST              = num;
#define     LAST_OTHER_INST(num)              LAST_OTHER_INST               = num;

  // #include "llvm/IR/Instruction.def"
  // llvm version 3.8
#include "Instruction.def"

  // string cur_opcode = SExt;
  unsigned int latency;
  unsigned int opcode_no = mymap[op_code];
  if (FIRST_BINARY_INST     <= opcode_no && opcode_no <= LAST_BINARY_INST \
      && FIRST_CAST_INST  <= opcode_no && opcode_no <= LAST_CAST_INST     \
      && FIRST_TERM_INST  <= opcode_no && opcode_no <= LAST_TERM_INST     \
      && FIRST_OTHER_INST <= opcode_no && opcode_no <= LAST_OTHER_INST    \
     )
  {
    // ("Add"), 11);
    // ("FAdd"), 12);
    // ("Sub"), 13);
    // ("FSub"), 14);
    // ("Mul"), 15);
    // ("FMul"), 16);
    // ("UDiv"), 17);
    // ("SDiv"), 18);
    // ("FDiv"), 19);
    // ("URem"), 20);
    // ("SRem"), 21);
    // ("FRem"), 22);

    if(op_code.compare("FDiv") == 0 )
      return latency = 20;

    else if(op_code.compare("FAdd") == 0 )
      return latency = 5;

    else if(op_code.compare("FMul") == 0 )
      return latency = 7;

    else if(op_code.compare("Mul") == 0 )
      return latency = 4;

    else if (op_code.find("Div") != std::string::npos)
      // else if(op_code.compare("Div") == 0 )
      return latency = 15;
    else
      return latency=1;
  }

  else if ( FIRST_FUNCLETPAD_INST <= opcode_no && opcode_no <= LAST_FUNCLETPAD_INST)
    return latency= 1;

  else if (FIRST_MEMORY_INST <= opcode_no && opcode_no <= LAST_MEMORY_INST)
  {
    if ( (op_code.compare("Load") == 0) ||
        // (op_code.compare("LoadInst") == 0) ||
        // (op_code.compare("StoreInst") == 0) ||
        (op_code.compare("Store") == 0)
       )
    {
      if(op_code.compare("Load") == 0)
        ++g_total_ldops;

      ++g_total_memops;
      return latency = MEMORYLATENCY;
    }
    else return latency = 1;
  }
  else
    return latency = 1;

}

  int
Graph::traverse_graph()
{
  //termination condition
  // while(1)
  // {
  //--------------------------------------------------------
  // Termination Condition
  if( vertex_state_map[VREADY].empty() && vertex_state_map[VWAIT].empty() &&
      edge_state_map[EWAIT].empty() && edge_state_map[ENOT_READY].empty()
      && edge_state_map[ECDE].empty()
    )

  {
    assert((m_memory->mem_req_stack == g_mem_req_stack /*MEM_MSHR_SIZE*/) && "memory request stack is not zero");
    D(print_states());
    D(cout<<"TERMINATION CALLED : Global Clock: " <<global_clock<<endl);
    D(cout<<"Memory:Bloom_filter_ld:Yes: "<<m_memory->bloom_yes_ld()<<endl);
    D(cout<<"Memory:Bloom_filter_st:Yes: "<<m_memory->bloom_yes_st()<<endl);
    D(cout<<"Memory:Bloom_filter_ld:No:  "<<m_memory->bloom_no_ld()<<endl);
    D(cout<<"Memory:Bloom_filter_st:No:  "<<m_memory->bloom_no_st()<<endl);

    //------- test ---------------------

    g_total_termination_cycles += global_clock;
    g_total_bloom_yes_ld += m_memory->bloom_yes_ld();
    g_total_bloom_yes_st += m_memory->bloom_yes_st();
    g_total_bloom_no_ld += m_memory->bloom_no_ld();
    g_total_bloom_no_st += m_memory->bloom_no_st();
    g_total_bloom_fp += m_memory->bloom_fp();
    g_total_bloom_stall_cycles += m_memory->bloom_stall_cycles();

    D(m_memory->print_mem_stats());
    g_rdy = false;
    m_prev_completion_cycles = global_clock;
    return global_clock;

  }

  // update_mlp_stats_1();

  // Iterate over all vertices and all Edges --
  // --------------------------------------------------------
  D(std::cout<< "Calling update_states_VNOT_READY_queue: \n");
  update_states_VNOT_READY_queue();
  D(print_states());

  // --------------------------------------------------------
  D(std::cout<< "Calling update_states_VWAIT_queue: \n");
  update_states_VWAIT_queue();
  D(print_states());

  // --------------------------------------------------------
  // Iterate over vertex in READY states
  D(cout<< "Calling update_states_VREADY_queue: \n");
  update_states_VREADY_queue();
  D(print_states());

  // --------------------------------------------------------
  D(cout<<"Calling update_states_VCOMPLETE_queue: \n");
  update_states_VCOMPLETE_queue();
  D(print_states());

  // Iterate over Edges in EWAIT states from Non Memory operations
  D(cout<< "Calling update_states_EWAIT_non_memory_queue: \n");
  update_states_EWAIT_non_memory_queue();
  D(print_states());

  // --------------------------------------------------------
  // Iterate over Edges in EWAIT states from Memory operations
  D(cout<< "Calling update_states_EWAIT_memory_queue: \n");
  update_states_EWAIT_memory_queue();
  D(print_states());

  //--------------------------------------------------------
  // Advance Clock

  // if(global_clock< min(next_event_time_vertex,next_event_time_edge))
  //   global_clock += min(next_event_time_vertex, next_event_time_edge);
  // else
  // cout<<"##   --- Global CLOCK:"<< global_clock++ << endl;

  // if(mlpfile.is_open())
  //   mlpfile<<mlp<<"\n";
  // else
  // {
  //   g_rdy = false;
  //   cerr<<"Error opening file \n";
  //
  //   assert(0 && "dafaxc: graph.cpp Error! File couldn't open");
  //   return -1;
  // }
  // global_clock++;

  //--------------------------------------------------------
  // Force Stop

  if(global_clock >= /*g_start_clock +*/  FORCE_STOP)
  {

    g_rdy = false;
    m_memory->print_mem_stats();
    print_states();
    cout<<"FORCE STOP AFTER "<<FORCE_STOP <<"cycles:\n";
    cerr<<"FORCE STOP AFTER "<<FORCE_STOP << "cycles:\n";
    printGraph();
    assert(0 && "FORCE STOP \n");
    return -1;
  }
  // }

  return 0;
}
  int
Graph::run_a_cycle()
{

  ++global_clock;
  if(g_en && g_rdy)
  {
    // cout<<"DAFAXC TRAVERSING GRAPH:"<<endl;
    return this->traverse_graph();
  }
  return 0;
}

  void
Graph:: update_states_VNOT_READY_queue()
{

  // Iterate over vertex in wait states
  // get values in array
  vector<VERTEX> vector_state_vnot_ready( vertex_state_map[VNOT_READY].begin(), vertex_state_map[VNOT_READY].end() );
  for (auto &IT: vector_state_vnot_ready)
  {

    // is_vertex_ready ?
    // If all in_edges are either in CDE or EComplete then vertex is ready
    //    mv V: NR -> W
    //    mv out_edges: NR -> W or NR-> CDE
    //    add start time and end time
    if(is_vertex_ready(IT))
    {

      // Update vertex states
      update_vertex_states(VNOT_READY,VWAIT,IT);

      // Update Edge States
      // OUt Edges mv : ENOT_READY -> EWAIT
      // OR
      // OUt Edges mv : ENOT_READY -> ECDE
      // add start and end time

      // Returns true if the edge is a CDE
      update_outedge_states_NR_to_CDE_or_EWAIT(ENOT_READY, EWAIT, IT);

      //Update next_event_vertex
      // next_event_time_vertex=global_clock+1;

    }
  }

}

  void
Graph:: update_states_VWAIT_queue()
{

  // Iterate over vertex in wait states
  // get values in array
  vector<VERTEX> vector_state_vwait( vertex_state_map[VWAIT].begin(), vertex_state_map[VWAIT].end() );
  for (auto &IT: vector_state_vwait)
  {

    // is_vertex_ready ?
    // If all in_edges are either in CDE or EComplete then vertex is ready
    //    mv V: W -> R
    //    mv out_edges: NR -> W or NR-> CDE
    //    add start time and end time
    if(is_vertex_ready(IT))
    {

      // Update vertex states
      update_vertex_states(VWAIT,VREADY,IT);

      // Update Edge States
      // OUt Edges mv : ENOT_READY -> EWAIT
      // OR
      // OUt Edges mv : ENOT_READY -> ECDE
      // add start and end time

      // Returns true if the edge is a CDE
      update_outedge_states_NR_to_CDE_or_EWAIT(ENOT_READY, EWAIT, IT);

      //Update next_event_vertex
      // next_event_time_vertex=global_clock+1;

    }
  }

}

  void
Graph::update_states_VREADY_queue()
{
  // Iterate over vertex in ready states
  // get values in array
  vector<VERTEX> vector_state_vready( vertex_state_map[VREADY].begin(), vertex_state_map[VREADY].end() );
  for (auto &IT: vector_state_vready)
  {

    // mv out_edges: NR -> W: Update State, queues,  add start time and end time
    // mv V: R ->C
    update_outedge_states_NR_to_CDE_or_EWAIT(ENOT_READY, EWAIT, IT);
    //Update Vertex State
    update_vertex_states(VREADY, VCOMPLETE, IT);

  }
}

  void
Graph::update_states_EWAIT_memory_queue()
{

  //-------------------------------------------------------------------------------------------
  // Response from Memory
  //insert ruby here --recv resp
  auto nodeid_list = m_memory->recv_resp(m_prev_completion_cycles);
  for( auto &n : nodeid_list)
  {
    D(cerr<<"graph: get resp from memory nodeid: "<<n<<endl);
  }

  //-------------------------------------------------------------------------------------------
  // ECDE EDGES COMING FROM MEMORY
  vector<EDGE> vector_state_ecde( edge_state_map[ECDE].begin(), edge_state_map[ECDE].end() );

  bool is_edge_cde = false;
  // Remember target vertex of CDE edges have already moved on
  for (auto &EI: vector_state_ecde)
  {

    auto src_nodeid = get(&vertex_prop::vname,in_graph,source_vertex);

    for( auto &n : nodeid_list)
    {
      if(src_nodeid == n)
      {
        is_edge_cde = true;
        break;
      }
    }

    if(is_edge_cde)
    {

      update_edge_state( ECDE, ECOMPLETE, EI) ;
    }

  }

  //-------------------------------------------------------------------------------------------
  // EWAIT EDGES COMING FROM MEMORY
  vector<EDGE> vector_state_ewait( edge_state_map[EWAIT].begin(), edge_state_map[EWAIT].end() );

  // Similarly for EWAIT memory edges
  for (auto &EI: vector_state_ewait)
  {

    auto src_nodeid = get(&vertex_prop::vname,in_graph,source_vertex);

    for( auto &n : nodeid_list)
    {
      if(src_nodeid == n)
      {
        is_edge_match = true;
        break;
      }
    }

    if(is_edge_match)
    {

      update_edge_state( EWAIT, ECOMPLETE, EI) ;
    }

  }

  //-------------------------------------------------------------------------------------------

}

  void
Graph::update_states_EWAIT_non_memory_queue()
{

  //-----------------------------------
  // Iterate over Edges in wait states
  // If End time == global_clock:
  //    mv E: W->C :
  //    mv targetV NR-> W:
  //    update next_event_edge
  //-----------------------------------
  vector<VERTEX> mv_target_vec_NR_to_W;
  vector<EDGE> vector_state_ewait( edge_state_map[EWAIT].begin(), edge_state_map[EWAIT].end() );

  for (auto &EI: vector_state_ewait)
  {
    bool is_edge_complete = false;
    auto estop_time = get(&edge_prop::estop_time,in_graph,EI);
    auto source_vertex = source(EI,in_graph);
    auto src_nodeid = get(&vertex_prop::vname,in_graph,source_vertex);
    auto src_opcode = get(&vertex_prop::vopcode,in_graph,source_vertex);

    auto target_vertex = target(EI,in_graph);
    auto tgt_nodeid = get(&vertex_prop::vname,in_graph,target_vertex);
    auto tgt_opcode = get(&vertex_prop::vopcode,in_graph,target_vertex);

    D(cout<<"update_states_EWAIT_non_memory_queue: nodeid: "<< src_nodeid
        <<" estop_time: "<<estop_time
        <<" global_clock: "<<global_clock
        <<endl;
     );

    //By default its false , if its a mem-op and there is a response from the memory
    //then check if the current edge's source node is the one that got response from the
    //memory.
    //If it is some other op- then just check it is retired

    bool is_mem = false;
    auto tmp_ir = get(&vertex_prop::vir,in_graph,source_vertex);

    //DO NOT SEND LIVE OUTS TO MEMORY
    if ( (src_opcode == "Load" || src_opcode =="Store")
        && (tmp_ir.find("!LO") == std::string::npos))
      is_mem = true;

    if( !is_mem && (estop_time <= global_clock) )
      is_edge_complete = true;

    // if(estop_time <= global_clock && is_edge_complete)
    if(is_edge_complete )
    {
      //Update edge state from EWAIT to ECOMP
      update_edge_state(EWAIT, ECOMPLETE, EI);

    }

}

  void
Graph::update_states_VCOMPLETE_queue()
{

  // Iterate over vertex in ready states
  // get values in array
  vector<VERTEX> vertex_mv_C_to_R;
  for (auto &IT: vertex_state_map[VCOMPLETE])
  {
    // mv out_edges: if not already completed, or not already in wait - NR -> W: Update State, queues,  add start time and end time
    update_outedge_states_NR_to_CDE_or_EWAIT( ENOT_READY, EWAIT,IT);
  }

  for (auto &VI : vertex_mv_C_to_R)
  {
    update_vertex_states( VCOMPLETE, VRETIRE, VI);
  }

}

  void
Graph::update_mlp_stats( uint64_t elatency)
{
  if(elatency == MEMORYLATENCY)
    mlp++;
  //
  // if(mlpfile.is_open())
  //   mlpfile<<mlp<<"\n";
  // else
  //   cerr<<"Error opening mlp_file\n";
  //
}

//   void
// Graph::update_mlp_stats_1()
// {
//
//   mlp=0;
//   for( auto &EI: edge_state_map[EWAIT])
//   {
//
//     if(get(&edge_prop::elatency,in_graph,EI) == MEMORYLATENCY)
//       mlp++;
//   }
//
//   if(mlpfile.is_open())
//     mlpfile<<mlp<<"\n";
//   else
//     cerr<<"Error opening mlp_file\n";
//
// }

  void
Graph::print_states()
{

  cout<<"-----------------------------------------\n";
  cout<<"VERTEX STATE MAP:\n";
  cout<<"-----------------------------------------\n";

  cout<<"VNOT_READY:\n";
  for( auto &VI: vertex_state_map[VNOT_READY])
  {
    cout<<get(&vertex_prop::vname,in_graph,VI) <<" ";
  }
  cout<<"\n";
  cout<<"-----------------------------------------\n";

  cout<<"VREADY:\n";
  for( auto &VI: vertex_state_map[VREADY])
  {
    cout<<get(&vertex_prop::vname,in_graph,VI) <<" ";
  }
  cout<<"\n";
  cout<<"-----------------------------------------\n";

  cout<<"VWAIT:\n";
  for( auto &VI: vertex_state_map[VWAIT])
  {
    cout<<get(&vertex_prop::vname,in_graph,VI) <<" ";
  }
  cout<<"\n";
  cout<<"-----------------------------------------\n";

  cout<<"VCOMPLETE:\n";
  for( auto &VI: vertex_state_map[VCOMPLETE])
  {
    cout<<get(&vertex_prop::vname,in_graph,VI) <<" ";
  }
  cout<<"\n";
  cout<<"-----------------------------------------\n";

  cout<<"VRETIRE:\n";
  for( auto &VI: vertex_state_map[VRETIRE])
  {
    cout<<get(&vertex_prop::vname,in_graph,VI) <<" ";
  }
  cout<<"\n";
  cout<<"-----------------------------------------\n";

  cout<<"-----------------------------------------\n";
  cout<<"EDGE STATE MAP:\n";
  cout<<"-----------------------------------------\n";

  cout<<"ENOT_READY:\n";
  for( auto &EI: edge_state_map[ENOT_READY])
  {

    auto target_vertex = target(EI, in_graph);
    auto source_vertex = source(EI, in_graph);

    cout<<"E:"<< get(&vertex_prop::vname,in_graph,source_vertex)
      << "->"
      << get(&vertex_prop::vname,in_graph,target_vertex)
      <<"\n";
  }
  cout<<"\n";
  cout<<"----------------------------------\n";

  cout<<"EWAIT:\n";
  for( auto &EI: edge_state_map[EWAIT])
  {

    auto target_vertex = target(EI, in_graph);
    auto source_vertex = source(EI, in_graph);

    cout<<"E:"<< get(&vertex_prop::vname,in_graph,source_vertex)
      << "->"
      << get(&vertex_prop::vname,in_graph,target_vertex)
      <<"\n";
  }
  cout<<"\n";
  cout<<"----------------------------------\n";

  cout<<"ECOMPLETE:\n";
  for( auto &EI: edge_state_map[ECOMPLETE])
  {

    auto target_vertex = target(EI, in_graph);
    auto source_vertex = source(EI, in_graph);

    cout<<"E:"<< get(&vertex_prop::vname,in_graph,source_vertex)
      << "->"
      << get(&vertex_prop::vname,in_graph,target_vertex)
      <<"\n";
  }
  cout<<"\n";
  cout<<"----------------------------------\n";

  cout<<"ECDE:\n";
  for( auto &EI: edge_state_map[ECDE])
  {

    auto target_vertex = target(EI, in_graph);
    auto source_vertex = source(EI, in_graph);

    cout<<"E:"<< get(&vertex_prop::vname,in_graph,source_vertex)
      << "->"
      << get(&vertex_prop::vname,in_graph,target_vertex)
      <<"\n";
  }
  cout<<"\n";
  cout<<"----------------------------------\n";

}

  void
Graph::print_memmap()
{
  m_memory->print_global_memaddr_map();
}
//----------------------------------
  void
Graph::read_memcsv(std::ifstream& file)
{
  boost::iostreams::filtering_streambuf<boost::iostreams::input> inbuf;
  inbuf.push(boost::iostreams::gzip_decompressor());
  inbuf.push(file);

  //Convert streambuf to istream
  std::istream instream(&inbuf);

  regex mem_parse("^([[:digit:]]+),([^,]*),([[:digit:]]+),([[:digit:]]+).*$");
  smatch match;

  std::string line;
  while(std::getline(instream, line) && m_memory->global_memaddr_map_size() < ITER_COUNT_MEM ){
    regex_search(line, match, mem_parse);

    uint64_t iter;
    uint64_t nodeid;
    string   opcode;
    bool isWrite =false;
    uint64_t addr;

    iter = stoi(match[1]);
    opcode = match[2];
    nodeid = stoi(match[3]);
    if(opcode == "Store")
      isWrite = true;
    else
      isWrite = false;
    addr = stoll(match[4]);

    //FIXME
    m_memory->fill_global_memaddr_map( iter, nodeid , MemValue {isWrite,addr});
  }
  cout<<"read_memcsv is complete: Loaded Memory iteration table \n";
}

// Checks for all the in_edges, if all in_Edges are in ECDE or ECOMPLETE
// then the vertex is ready
bool
Graph::is_vertex_ready( VERTEX _vertex)
{
  bool is_vertex_ready = true;
  auto EI = in_edges(_vertex,in_graph);
  for (auto ES = EI.first, EE = EI.second; ES != EE; ES++)
  {
    // if( get(&edge_prop::estate,*ES,in_graph) != ECOMPLETE)
    // auto S = source(*ES, BG);
    auto cur_estate = get(&edge_prop::estate,in_graph,*ES);
    if( !(cur_estate == ECOMPLETE || cur_estate == ECDE) )
    {
      is_vertex_ready = false;
      break;
    }
  }
  return is_vertex_ready;
}

void
Graph::update_vertex_states(VSTATE _From_state,VSTATE  _To_state,VERTEX  _Vertex)
{

      //Update vertex states
      put(&vertex_prop::vstate,in_graph,_Vertex,_To_state);

      //Update vertex state maps
      //move vertex from wait to ready queue
      //delete entry from VWAIT -- without deleting the object
      vertex_state_map[_To_state].push_back(_Vertex);
      vertex_state_map[_From_state].erase(find(vertex_state_map[_From_state].begin(),
            vertex_state_map[_From_state].end(),_Vertex));

}

  bool
Graph::update_outedge_states_NR_to_CDE_or_EWAIT(ESTATE _From_state,ESTATE _To_state, VERTEX _Vertex)
{
  auto _From_state = ENOT_READY;
  auto _To_state = EWAIT;

  vector<EDGE> edge_mv_From_to_To;
  vector<EDGE> edge_mv_From_to_CDE;

  auto EO = out_edges(_Vertex,in_graph);

  // FOR all OUT EDGES
  for (auto ES = EO.first, EE = EO.second; ES != EE; ES++)
  {

    auto estate = get(&edge_prop::estate,in_graph,*ES);
    // update_mlp_stats( get(&edge_prop::elatency,in_graph,*ES));
    //insert ruby here  -- send request
    //FIXME add iteration no
    auto vopcode = get(&vertex_prop::vopcode,in_graph,_Vertex);

    //DO NOT SEND LIVE OUTS TO MEMORY
    auto tmp_ir = get(&vertex_prop::vir,in_graph,_Vertex);
    auto tmp_vissue = get(&vertex_prop::vissue,in_graph,_Vertex);
    auto is_mem = false;

    //CHECK IF ITS A CDE
    if ( (vopcode == "Load" || vopcode =="Store")
        && (tmp_ir.find("!LO") == std::string::npos)
        && tmp_vissue == false)
    {
      is_mem = true;
      put(&vertex_prop::vissue,in_graph,_Vertex,true);
      m_memory->send_req(g_iter,get(&vertex_prop::vname,in_graph,_Vertex));
      D(cerr<<"Sending to Memory nodeid: "<<get(&vertex_prop::vname,in_graph,_Vertex)<<" :VWAIT" <<endl);
      ++g_mem_req_count;
    }

    // bool check_ifCDE(*ES)

    auto target_vertex = target(*ES,in_graph);
    auto tgt_nodeid = get(&vertex_prop::vname,in_graph,target_vertex);
    auto tgt_opcode = get(&vertex_prop::vopcode,in_graph,target_vertex);
    auto tmp_tgt_ir = get(&vertex_prop::vir,in_graph,target_vertex);
    auto is_tgt_mem = false;

    if ( (tgt_opcode == "Load" || tgt_opcode =="Store")
        && (tmp_tgt_ir.find("!LO") == std::string::npos)
       )
    {

      is_tgt_mem = true;
    }

    auto elatency = get(&edge_prop::elatency,in_graph,*ES);

    //UPDATE STATE TO CDE
    if(is_mem && is_tgt_mem)
      put(&edge_prop::estate,in_graph,*ES,ECDE);

    //UPDATE STATE TO _To_STATE
    else
      put(&edge_prop::estate,in_graph,*ES,_To_state);

    put(&edge_prop::estart_time,in_graph,*ES,global_clock);
    put(&edge_prop::estop_time,in_graph,*ES,global_clock+elatency);

    if(find( edge_mv_From_to_To.begin(),edge_mv_From_to_To.end(),*ES) == edge_mv_From_to_To.end() && !(is_mem && is_tgt_mem) )
      edge_mv_From_to_To.push_back(*ES);
    else if(find( edge_mv_From_to_CDE.begin(),edge_mv_From_to_CDE.end(),*ES) == edge_mv_From_to_CDE.end() && is_mem && is_tgt_mem)
      edge_mv_From_to_CDE.push_back(*ES);

  }

  //Update Edge Queues
  for(auto &ED : edge_mv_From_to_To)
  {

    edge_state_map[_To_state].push_back(ED);
    edge_state_map[_From_state].erase( find( edge_state_map[_From_state].begin(),
          edge_state_map[_From_state].end(), ED));
  }

  //Update Edge Queues
  for(auto &ED : edge_mv_From_to_CDE)
  {

    edge_state_map[ECDE].push_back(ED);
    edge_state_map[_From_state].erase( find( edge_state_map[_From_state].begin(),
          edge_state_map[_From_state].end(), ED));
  }

  if(is_mem && is_tgt_mem)
    return true;
  else
    return false;

}

void
Graph::update_edge_state(ESTATE _From_state, ESTATE _To_state, & EDGE EI)
{
      put(&edge_prop::estate,in_graph,EI,_To_state);

      //Update states
      edge_state_map[_To_state].push_back(EI);
      //update queues
      edge_state_map[_From_state].erase(find(edge_state_map[_From_state].begin(),
            edge_state_map[_From_state].end(),EI));

}

ext: cpp


text:
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

// From Apache Impala (incubating) as of 2016-01-29

#include <cstdint>
#include <cstring>
#include <random>
#include <vector>

#include <gtest/gtest.h>

#include <boost/utility.hpp>  // IWYU pragma: export

#include "arrow/util/bit-stream-utils.h"
#include "arrow/util/bit-util.h"
#include "arrow/util/rle-encoding.h"

using std::vector;

namespace arrow {
namespace util {

const int MAX_WIDTH = 32;

TEST(BitArray, TestBool) {
  const int len = 8;
  uint8_t buffer[len];

  BitUtil::BitWriter writer(buffer, len);

  // Write alternating 0's and 1's
  for (int i = 0; i < 8; ++i) {
    bool result = writer.PutValue(i % 2, 1);
    EXPECT_TRUE(result);
  }
  writer.Flush();
  EXPECT_EQ((int)buffer[0], BOOST_BINARY(1 0 1 0 1 0 1 0));

  // Write 00110011
  for (int i = 0; i < 8; ++i) {
    bool result = false;
    switch (i) {
      case 0:
      case 1:
      case 4:
      case 5:
        result = writer.PutValue(false, 1);
        break;
      default:
        result = writer.PutValue(true, 1);
        break;
    }
    EXPECT_TRUE(result);
  }
  writer.Flush();

  // Validate the exact bit value
  EXPECT_EQ((int)buffer[0], BOOST_BINARY(1 0 1 0 1 0 1 0));
  EXPECT_EQ((int)buffer[1], BOOST_BINARY(1 1 0 0 1 1 0 0));

  // Use the reader and validate
  BitUtil::BitReader reader(buffer, len);
  for (int i = 0; i < 8; ++i) {
    bool val = false;
    bool result = reader.GetValue(1, &val);
    EXPECT_TRUE(result);
    EXPECT_EQ(val, (i % 2) != 0);
  }

  for (int i = 0; i < 8; ++i) {
    bool val = false;
    bool result = reader.GetValue(1, &val);
    EXPECT_TRUE(result);
    switch (i) {
      case 0:
      case 1:
      case 4:
      case 5:
        EXPECT_EQ(val, false);
        break;
      default:
        EXPECT_EQ(val, true);
        break;
    }
  }
}

// Writes 'num_vals' values with width 'bit_width' and reads them back.
void TestBitArrayValues(int bit_width, int num_vals) {
  int len = static_cast<int>(BitUtil::BytesForBits(bit_width * num_vals));
  EXPECT_GT(len, 0);
  const uint64_t mod = bit_width == 64 ? 1 : 1LL << bit_width;

  std::vector<uint8_t> buffer(len);
  BitUtil::BitWriter writer(buffer.data(), len);
  for (int i = 0; i < num_vals; ++i) {
    bool result = writer.PutValue(i % mod, bit_width);
    EXPECT_TRUE(result);
  }
  writer.Flush();
  EXPECT_EQ(writer.bytes_written(), len);

  BitUtil::BitReader reader(buffer.data(), len);
  for (int i = 0; i < num_vals; ++i) {
    int64_t val = 0;
    bool result = reader.GetValue(bit_width, &val);
    EXPECT_TRUE(result);
    EXPECT_EQ(val, i % mod);
  }
  EXPECT_EQ(reader.bytes_left(), 0);
}

TEST(BitArray, TestValues) {
  for (int width = 1; width <= MAX_WIDTH; ++width) {
    TestBitArrayValues(width, 1);
    TestBitArrayValues(width, 2);
    // Don't write too many values
    TestBitArrayValues(width, (width < 12) ? (1 << width) : 4096);
    TestBitArrayValues(width, 1024);
  }
}

// Test some mixed values
TEST(BitArray, TestMixed) {
  const int len = 1024;
  uint8_t buffer[len];
  bool parity = true;

  BitUtil::BitWriter writer(buffer, len);
  for (int i = 0; i < len; ++i) {
    bool result;
    if (i % 2 == 0) {
      result = writer.PutValue(parity, 1);
      parity = !parity;
    } else {
      result = writer.PutValue(i, 10);
    }
    EXPECT_TRUE(result);
  }
  writer.Flush();

  parity = true;
  BitUtil::BitReader reader(buffer, len);
  for (int i = 0; i < len; ++i) {
    bool result;
    if (i % 2 == 0) {
      bool val;
      result = reader.GetValue(1, &val);
      EXPECT_EQ(val, parity);
      parity = !parity;
    } else {
      int val;
      result = reader.GetValue(10, &val);
      EXPECT_EQ(val, i);
    }
    EXPECT_TRUE(result);
  }
}

// Validates encoding of values by encoding and decoding them.  If
// expected_encoding != NULL, also validates that the encoded buffer is
// exactly 'expected_encoding'.
// if expected_len is not -1, it will validate the encoded size is correct.
void ValidateRle(const vector<int>& values, int bit_width, uint8_t* expected_encoding,
                 int expected_len) {
  const int len = 64 * 1024;
  uint8_t buffer[len];
  EXPECT_LE(expected_len, len);

  RleEncoder encoder(buffer, len, bit_width);
  for (size_t i = 0; i < values.size(); ++i) {
    bool result = encoder.Put(values[i]);
    EXPECT_TRUE(result);
  }
  int encoded_len = encoder.Flush();

  if (expected_len != -1) {
    EXPECT_EQ(encoded_len, expected_len);
  }
  if (expected_encoding != NULL) {
    EXPECT_EQ(memcmp(buffer, expected_encoding, expected_len), 0);
  }

  // Verify read
  {
    RleDecoder decoder(buffer, len, bit_width);
    for (size_t i = 0; i < values.size(); ++i) {
      uint64_t val;
      bool result = decoder.Get(&val);
      EXPECT_TRUE(result);
      EXPECT_EQ(values[i], val);
    }
  }

  // Verify batch read
  {
    RleDecoder decoder(buffer, len, bit_width);
    vector<int> values_read(values.size());
    ASSERT_EQ(values.size(),
              decoder.GetBatch(values_read.data(), static_cast<int>(values.size())));
    EXPECT_EQ(values, values_read);
  }
}

// A version of ValidateRle that round-trips the values and returns false if
// the returned values are not all the same
bool CheckRoundTrip(const vector<int>& values, int bit_width) {
  const int len = 64 * 1024;
  uint8_t buffer[len];
  RleEncoder encoder(buffer, len, bit_width);
  for (size_t i = 0; i < values.size(); ++i) {
    bool result = encoder.Put(values[i]);
    if (!result) {
      return false;
    }
  }
  int encoded_len = encoder.Flush();
  int out = 0;

  {
    RleDecoder decoder(buffer, encoded_len, bit_width);
    for (size_t i = 0; i < values.size(); ++i) {
      EXPECT_TRUE(decoder.Get(&out));
      if (values[i] != out) {
        return false;
      }
    }
  }

  // Verify batch read
  {
    RleDecoder decoder(buffer, len, bit_width);
    vector<int> values_read(values.size());
    if (static_cast<int>(values.size()) !=
        decoder.GetBatch(values_read.data(), static_cast<int>(values.size()))) {
      return false;
    }
    if (values != values_read) {
      return false;
    }
  }

  return true;
}

TEST(Rle, SpecificSequences) {
  const int len = 1024;
  uint8_t expected_buffer[len];
  vector<int> values;

  // Test 50 0' followed by 50 1's
  values.resize(100);
  for (int i = 0; i < 50; ++i) {
    values[i] = 0;
  }
  for (int i = 50; i < 100; ++i) {
    values[i] = 1;
  }

  // expected_buffer valid for bit width <= 1 byte
  expected_buffer[0] = (50 << 1);
  expected_buffer[1] = 0;
  expected_buffer[2] = (50 << 1);
  expected_buffer[3] = 1;
  for (int width = 1; width <= 8; ++width) {
    ValidateRle(values, width, expected_buffer, 4);
  }

  for (int width = 9; width <= MAX_WIDTH; ++width) {
    ValidateRle(values, width, NULL,
                2 * (1 + static_cast<int>(BitUtil::CeilDiv(width, 8))));
  }

  // Test 100 0's and 1's alternating
  for (int i = 0; i < 100; ++i) {
    values[i] = i % 2;
  }
  int num_groups = static_cast<int>(BitUtil::CeilDiv(100, 8));
  expected_buffer[0] = static_cast<uint8_t>((num_groups << 1) | 1);
  for (int i = 1; i <= 100 / 8; ++i) {
    expected_buffer[i] = BOOST_BINARY(1 0 1 0 1 0 1 0);
  }
  // Values for the last 4 0 and 1's. The upper 4 bits should be padded to 0.
  expected_buffer[100 / 8 + 1] = BOOST_BINARY(0 0 0 0 1 0 1 0);

  // num_groups and expected_buffer only valid for bit width = 1
  ValidateRle(values, 1, expected_buffer, 1 + num_groups);
  for (int width = 2; width <= MAX_WIDTH; ++width) {
    int num_values = static_cast<int>(BitUtil::CeilDiv(100, 8)) * 8;
    ValidateRle(values, width, NULL,
                1 + static_cast<int>(BitUtil::CeilDiv(width * num_values, 8)));
  }
}

// ValidateRle on 'num_vals' values with width 'bit_width'. If 'value' != -1, that value
// is used, otherwise alternating values are used.
void TestRleValues(int bit_width, int num_vals, int value = -1) {
  const uint64_t mod = (bit_width == 64) ? 1 : 1LL << bit_width;
  vector<int> values;
  for (int v = 0; v < num_vals; ++v) {
    values.push_back((value != -1) ? value : static_cast<int>(v % mod));
  }
  ValidateRle(values, bit_width, NULL, -1);
}

TEST(Rle, TestValues) {
  for (int width = 1; width <= MAX_WIDTH; ++width) {
    TestRleValues(width, 1);
    TestRleValues(width, 1024);
    TestRleValues(width, 1024, 0);
    TestRleValues(width, 1024, 1);
  }
}

TEST(Rle, BitWidthZeroRepeated) {
  uint8_t buffer[1];
  const int num_values = 15;
  buffer[0] = num_values << 1;  // repeated indicator byte
  RleDecoder decoder(buffer, sizeof(buffer), 0);
  uint8_t val;
  for (int i = 0; i < num_values; ++i) {
    bool result = decoder.Get(&val);
    EXPECT_TRUE(result);
    EXPECT_EQ(val, 0);  // can only encode 0s with bit width 0
  }
  EXPECT_FALSE(decoder.Get(&val));
}

TEST(Rle, BitWidthZeroLiteral) {
  uint8_t buffer[1];
  const int num_groups = 4;
  buffer[0] = num_groups << 1 | 1;  // literal indicator byte
  RleDecoder decoder = RleDecoder(buffer, sizeof(buffer), 0);
  const int num_values = num_groups * 8;
  uint8_t val;
  for (int i = 0; i < num_values; ++i) {
    bool result = decoder.Get(&val);
    EXPECT_TRUE(result);
    EXPECT_EQ(val, 0);  // can only encode 0s with bit width 0
  }
  EXPECT_FALSE(decoder.Get(&val));
}

// Test that writes out a repeated group and then a literal
// group but flush before finishing.
TEST(BitRle, Flush) {
  vector<int> values;
  for (int i = 0; i < 16; ++i) values.push_back(1);
  values.push_back(0);
  ValidateRle(values, 1, NULL, -1);
  values.push_back(1);
  ValidateRle(values, 1, NULL, -1);
  values.push_back(1);
  ValidateRle(values, 1, NULL, -1);
  values.push_back(1);
  ValidateRle(values, 1, NULL, -1);
}

// Test some random sequences.
TEST(BitRle, Random) {
  int niters = 50;
  int ngroups = 1000;
  int max_group_size = 16;
  vector<int> values(ngroups + max_group_size);

  // prng setup
  std::random_device rd;
  std::uniform_int_distribution<int> dist(1, 20);

  for (int iter = 0; iter < niters; ++iter) {
    // generate a seed with device entropy
    uint32_t seed = rd();
    std::mt19937 gen(seed);

    bool parity = 0;
    values.resize(0);

    for (int i = 0; i < ngroups; ++i) {
      int group_size = dist(gen);
      if (group_size > max_group_size) {
        group_size = 1;
      }
      for (int i = 0; i < group_size; ++i) {
        values.push_back(parity);
      }
      parity = !parity;
    }
    if (!CheckRoundTrip(values, BitUtil::NumRequiredBits(values.size()))) {
      FAIL() << "failing seed: " << seed;
    }
  }
}

// Test a sequence of 1 0's, 2 1's, 3 0's. etc
// e.g. 011000111100000
TEST(BitRle, RepeatedPattern) {
  vector<int> values;
  const int min_run = 1;
  const int max_run = 32;

  for (int i = min_run; i <= max_run; ++i) {
    int v = i % 2;
    for (int j = 0; j < i; ++j) {
      values.push_back(v);
    }
  }

  // And go back down again
  for (int i = max_run; i >= min_run; --i) {
    int v = i % 2;
    for (int j = 0; j < i; ++j) {
      values.push_back(v);
    }
  }

  ValidateRle(values, 1, NULL, -1);
}

TEST(BitRle, Overflow) {
  for (int bit_width = 1; bit_width < 32; bit_width += 3) {
    int len = RleEncoder::MinBufferSize(bit_width);
    std::vector<uint8_t> buffer(len);
    int num_added = 0;
    bool parity = true;

    RleEncoder encoder(buffer.data(), len, bit_width);
    // Insert alternating true/false until there is no space left
    while (true) {
      bool result = encoder.Put(parity);
      parity = !parity;
      if (!result) break;
      ++num_added;
    }

    int bytes_written = encoder.Flush();
    EXPECT_LE(bytes_written, len);
    EXPECT_GT(num_added, 0);

    RleDecoder decoder(buffer.data(), bytes_written, bit_width);
    parity = true;
    uint32_t v;
    for (int i = 0; i < num_added; ++i) {
      bool result = decoder.Get(&v);
      EXPECT_TRUE(result);
      EXPECT_EQ(v != 0, parity);
      parity = !parity;
    }
    // Make sure we get false when reading past end a couple times.
    EXPECT_FALSE(decoder.Get(&v));
    EXPECT_FALSE(decoder.Get(&v));
  }
}

}  // namespace util
}  // namespace arrow

ext: cc

max_stars_repo_name: thaining/arrow

max_issues_repo_name: thaining/arrow

max_forks_repo_name: thaining/arrow


text:
/*======================================================================
Copyright 2019 Google LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
======================================================================*/

#include <iostream>
#include <cstring>

#include <Eigen/Dense>

#include "Gather.h"

using namespace std;
using namespace Eigen;

Gather::Gather( char const *filename, int const num_samples )
  :numC_(0),numD_(0),gatherCount_(0)
{
  zero_();
  reset( filename, num_samples );

  /* NEED TO IMPLEMENT A MODERN THREAD MANAGEMENT...

  // CREATE STACK FOR save() THREAD
  int   SAVETHREAD_STACKSIZE = ( 1024 * 32 );
  SaveThread_Stack_ = calloc(SAVETHREAD_STACKSIZE, sizeof(char));
  */
}

void
Gather::filename_set_(char const *filename)
{
  strcpy(filename_,filename);
  if( strlen(filename_)>FILENAME_MAX-4 ) // SAVE ROOM FOR FILE EXTENTION
  { filename_[FILENAME_MAX-5] = 0;
  }
  strcat(filename_,".csv");
}

void
Gather::zero_()
{
  numC_ = 0;
  numD_ = 0;

  filename_[0] = 0;
  max_samples_ = 0;
  gatherCount_ = 0;

  state_=GATHER_STATE_EMPTY;
}

void
Gather::reset()
{
  reset( filename_, max_samples_ );
}

void
Gather::reset( char const *filename, int const num_samples )
{
  freeData_();
  zero_();
  filename_set_(filename);
  max_samples_ = num_samples;
  data("t",t_);
}

void
Gather::constant(char const *name, Float const &dataIn)
{
  if( &dataIn == NULL )
  { cout << "Gather: '" << name << "' is NULL pointer" << endl;
    return;
  }
  strcpy(C_[numC_].name,name);
  C_[numC_].dataIn = NULL; // CONSTANT, so NOW not LATER
  C_[numC_].row  = 1;
  C_[numC_].col  = 1;
  C_[numC_].data = new Float[C_[numC_].row];

  int i;
  for( i=0 ; i<C_[numC_].row ; i++ )
    C_[numC_].data[i] =  dataIn;

  ++numC_;
}

void
Gather::constant(char const *name, VectorXd const &dataIn)
{
  if( &dataIn == NULL )
  { cout << "Gather: '"<< name <<"' is NULL pointer" << endl;
    return;
  }
  strcpy(C_[numC_].name,name);
  C_[numC_].dataIn = NULL; // CONSTANT, so NOW not LATER
  C_[numC_].row  = dataIn.size();
  C_[numC_].col  = 1;
  C_[numC_].data = new Float[C_[numC_].row];

  int i;
  for( i=0 ; i<C_[numC_].row ; i++ )
    C_[numC_].data[i] =  dataIn[i];

  ++numC_;
}

void
Gather::constant(char const *name, MatrixXd const &dataIn)
{
  if( &dataIn == NULL )
  { cout << "Gather: '"<< name <<"' is NULL pointer" << endl;
    return;
  }
  strcpy(C_[numC_].name,name);
  C_[numC_].dataIn = NULL; // CONSTANT, so NOW not LATER
  C_[numC_].row  = dataIn.row();
  C_[numC_].col  = dataIn.column();
  C_[numC_].data = new Float[C_[numC_].row * C_[numC_].col];

  for(int i=0 ; i<(C_[numC_].row*C_[numC_].col) ; ++i)
  { C_[numC_].data[i] = dataIn.data()[i];
  }

  ++numC_;
}

void
Gather::data(char const *name, Float const &dataIn)
{
  if( &dataIn == NULL )
  { cout << "Gather: '"<< name <<"' is NULL pointer" << endl;
    return;
  }
  strcpy(D_[numD_].name,name);
  D_[numD_].dataIn = (Float *)&dataIn;
  D_[numD_].row = 1;
  D_[numD_].col = 1;
  D_[numD_].data = new Float[max_samples_];
  ++numD_;
}

void
Gather::data(char const *name, VectorXd const &dataIn)
{
  if( &dataIn == NULL )
  { cout << "Gather: '"<< name <<"' is NULL pointer" << endl;
    return;
  }
  strcpy(D_[numD_].name,name);
  D_[numD_].dataIn = dataIn.data();
  D_[numD_].row = dataIn.size();
  D_[numD_].col = 1;
  D_[numD_].data = new Float[max_samples_ * D_[numD_].row];
  ++numD_;
}

void
Gather::data(char const *name, MatrixXd const &dataIn)
{
  if( &dataIn == NULL )
  { cout << "Gather: '"<< name <<"' is NULL pointer" << endl;
    return;
  }
  strcpy(D_[numD_].name,name);
  D_[numD_].dataIn = dataIn.data();
  D_[numD_].row = dataIn.row();
  D_[numD_].col = dataIn.column();
  D_[numD_].data = new Float[max_samples_ *
                            D_[numD_].row * D_[numD_].col];
  ++numD_;
}

Gather::~Gather()
{
  freeData_();
  /* NEED TO IMPLEMENT A MODERN WAY TO SAVE VIA A THREAD
 free(SaveThread_Stack_);
  */
}

void
Gather::freeData_()
{
  int i;

  for(i=0 ; i<numC_ ; ++i)
  { delete[] C_[i].data;
    C_[i].data = NULL;
  }
  numC_ = 0;

  for(i=0 ; i<numD_ ; ++i)
  { delete[] D_[i].data;
    D_[i].data = NULL;
  }
  numD_ = 0;
}

void
Gather::gather(double const time)
{
  int i,k;

  switch(state_)
  {
    case GATHER_STATE_FULL:   // DO NOTHING WHEN gather() IS CALLED
    case GATHER_STATE_SAVING: // DO NOTHING WHEN gather() IS CALLED
    case GATHER_STATE_WRITTEN:// DO NOTHING WHEN gather() IS CALLED
    case GATHER_STATE_ERROR:  // DO NOTHING WHEN gather() IS CALLED
    break;

    case GATHER_STATE_EMPTY:
      state_ = GATHER_STATE_READY; // NOTE: NO break; CONTINUE AND GATHER...
    case GATHER_STATE_READY:
      // GATHER TIME  (TIME IS FIRST DATA)
      t_ = time;

      // GATHER DATA
      for(k=0 ; k<numD_ ; ++k)
      { int vsize = D_[k].row * D_[k].col;
        for(i=0 ; i<vsize ; ++i)
        { D_[k].data[gatherCount_*vsize+i] = D_[k].dataIn[i];
        }
      }
      // CHECK IF DONE GATHERING
      if ( ++gatherCount_ >= max_samples_)
      { state_ = GATHER_STATE_FULL;
      }
      break;

    default:
      cout << "error: unknown Gather() state =  " << state_ << endl;
      state_ = GATHER_STATE_ERROR;
      break;
  }
}

void
Gather::save()
{
  // DON'T SAVE WHEN EMPTY, DON'T SAVE MORE THAN ONCE
  if( state_ == GATHER_STATE_READY || state_ == GATHER_STATE_FULL )
  {
    // MAKE SURE ONLY ONE THREAD STARTS
    state_ = GATHER_STATE_SAVING;

    /*  NEED TO IMPLEMENT A MODERN WAY TO SAVE USING A TREAD...
    static timer_handle_t  saveThread_h;
    static timer_thread    saveThread_obj;

    timer_thread_create(PRIORITY_GATHER,
                      saveThread_,
                      (unsigned int) this,
                      "saveThread",
                      SaveThread_Stack_,
                      SAVETHREAD_STACKSIZE,
                      &saveThread_h,
                      &saveThread_obj );

    timer_thread_resume( saveThread_h );
    */
  }
}

#define MAX_FILE_LINE_LEN  ( (10+2)*(40*6 + 25) ) // DIGITS*(VECTORS*SIZE+CONSTANTS)
#define FMT  ",%g"

#ifdef ecos
#include <tftp_support.h>    //USE SIMPLE ECOS FILESYSTEM
#endif

void saveThread_(unsigned int obj)
{
  Gather* gObj = (Gather*)obj;
  static char s[MAX_FILE_LINE_LEN+1];
  int slen;
  char tok[30];  // LARGE ENOUGH FOR A COMMA AND ONE DIGIT
  T_Data  *v;    // SHORTHAND to SAVE ME FROM TYPOs

  // OPEN FILE
#ifdef ecos
  extern struct tftpd_fileops dummy_fileops;
  int fd;
  fd = dummy_fileops.open( gObj->filename_, O_WRONLY );
#else
  FILE *file;
  file = fopen( gObj->filename_, "w" );
#endif

    s[0]=0;
    slen=0;

    // WRITE DATA LABELS
  for(int k=0 ; k<gObj->numD_ ; ++k)
  { v = &gObj->D_[k];
    char *r_fmt = "_%1d";char *c_fmt = "%1d";
    if( v->row>10 || v->col>10)
    { r_fmt = "_%02d"; c_fmt = "_%02d"; }
    for(int kr=0 ; kr<v->row ; ++kr)
      for(int kc=0 ; kc<v->col ; ++kc)
      { slen += sprintf( tok, ",%s", v->name );
        strcat( s, tok );       // NAME
        if( v->row > 1 )
        { slen += sprintf( tok, r_fmt, kr+1 );
          strcat( s, tok );   // ROW if VECTOR or MATRIX
        }
        if( v->col > 1 )
        { slen += sprintf( tok, c_fmt, kc+1 );
          strcat( s, tok );   // COL if MATRIX
        }
      }
  }

    // WRITE CONSTANT LABELS
  for(int k=0 ; k<gObj->numC_ ; ++k)
  { v = &gObj->C_[k];
    char *r_fmt = "_%1d";char *c_fmt = "%1d";
    if( v->row>10 || v->col>10)
    { r_fmt = "_%02d"; c_fmt = "_%02d"; }
    for(int kr=0 ; kr<v->row ; ++kr)
      for(int kc=0 ; kc<v->col ; ++kc)
      { slen += sprintf( tok, ",%s", v->name );
        strcat( s, tok );       // NAME
        if( v->row > 1 )
        { slen += sprintf( tok, r_fmt, kr+1 );
          strcat( s, tok );   // ROW if VECTOR or MATRIX
        }
          if( v->col > 1 )
        { slen += sprintf( tok, c_fmt, kc+1 );
          strcat( s, tok );   // COL if MATRIX
        }
      }
  }

  slen++;
  strcat( s, "\n" );     // END OF LINE

  // SAVE LINE TO FILE (skip first comma)
#ifdef ecos
  dummy_fileops.write( fd, s+1, slen-1 );
#else
  fputs ( s+1, file );
#endif

  // WRITE VALUES
  for(int idx=0; idx<gObj->gatherCount_ ; ++idx)
  {
    s[0]=0;
    slen=0;

      // WRITE DATA
    for(int k=0 ; k<gObj->numD_ ; ++k)
    { v = &gObj->D_[k];
      for(int kr=0 ; kr<v->row ; ++kr)
        for(int kc=0 ; kc<v->col ; ++kc)
        { slen += sprintf( tok, FMT ,
            v->data[idx*v->row*v->col + kr*v->col + kc ] );
          strcat( s, tok );
        }
    }
      // WRITE CONSTANTS
  if( idx == 0 )     // (ON THE FIRST PASS THRU ONLY)
  { for(int k=0 ; k<gObj->numC_ ; ++k)
    { v = &gObj->C_[k];
      for(int kr=0 ; kr<v->row ; ++kr)
        for(int kc=0 ; kc<v->col ; ++kc)
        { slen += sprintf( tok, FMT,
            v->data[idx*v->row*v->col + kr*v->col + kc ] );
          strcat( s, tok );
        }
    }
  } // CONSTANTS ONLY FOR idx==0

    slen++;
    strcat( s, "\n" );     // END OF LINE
    assert( slen < MAX_FILE_LINE_LEN ); // BAIL IF NOT LONG ENOUGH

    // SAVE LINE TO FILE (skip first comma)
#ifdef ecos
    dummy_fileops.write( fd, s+1, slen-1 );
#else
    fputs ( s+1, file );
#endif

  } // THE LOOP idx

  // CLOSE FILE
#ifdef ecos
  dummy_fileops.close( fd );
#else
  fclose( file );
#endif

  cout << "Save end:  " << gObj->gatherCount_ <<
          "samples written to '" <<  gObj->filename_  << "'." << endl;

  gObj->state_ = GATHER_STATE_WRITTEN;

#ifdef ecos
  timer_thread_exit();
#endif

  return;
} // END: SaveThread

// SINGLETON
static Gather *sp_gObj = NULL;

Gather *
Gather::HandleGet( char const *filename, int const max_num_samples )
{
  if( !sp_gObj ) // ONLY USE ARGS ON CREATION
  {
    sp_gObj = new Gather( filename, max_num_samples );
  }
                // IGNORE ARGS IF SINGLETON EXISTS
  return sp_gObj;
}

#ifdef ecos //*********  tftp _server_start ********//

#include <network.h>
#include <tftp_support.h>

void
Gather::tftp_server_start(void)
{
  extern struct tftpd_fileops dummy_fileops;
  int tftp_id;

  init_all_network_interfaces();
#ifdef  CYGHWR_NET_DRIVER_ETH0
  if( eth0_up )
  { tftp_id = tftpd_start(69, &dummy_fileops);
    cout << "start tftp server 0x" << tftp_id << endl; //TODO: output hex
    if( tftp_id <= 0 )
    { cout << "Failed to start tftp server!" << endl;
      return;
    }
  }
  else
  { cout << "Failed to bring up interface eth0!" << endl;
    return;
  }
#else
  cout << "Failed to define interface eth0!" << endl;
#endif //CYGHWR_NET_DRIVER_ETH0

  return;
}

#else        //***** DUMMY tftp _server_start  *****//

void
Gather::tftp_server_start(void)
{
  cout << "\nGather::tftp_server_start:  NOT IMPLEMENTED !!!" << endl;
  cout << "Gathered files will be saved in native filesystem instead.\n" << endl;
}

#endif // ecos

max_stars_repo_name: google/powered-caster-vehicle

max_issues_repo_name: google/powered-caster-vehicle

max_forks_repo_name: google/powered-caster-vehicle


text:
#include <fc/interprocess/file_mutex.hpp>
//#include <fc/thread/mutex.hpp>
#include <fc/thread/mutex.hpp>
#include <fc/filesyCC.hpp>
#include <boost/interprocess/sync/file_lock.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <boost/atomic.hpp>

#include <fc/thread/thread.hpp>
#include <fc/log/logger.hpp>

namespace fc {
  namespace bip = boost::interprocess;

  void yield();

  namespace detail {
     class file_mutex_impl  {
        public:
          file_mutex_impl( const char* f )
          :_file_mutex( f ),_reader_count(0){}

          fc::mutex  _write_lock;
          bip::file_lock       _file_mutex;
          boost::atomic<int>   _reader_count;
     };
  }

  file_mutex::file_mutex( const fc::path& file )
  {
     my.reset( new detail::file_mutex_impl( file.generic_string().c_str() ) );
  }

  file_mutex::~file_mutex() {
  }

  int  file_mutex::readers()const {
    return my->_reader_count.load();
  }

  bool file_mutex::try_lock() {
     return false;
     if( my->_write_lock.try_lock() ) {
        if( my->_file_mutex.try_lock() )
           return true;
     }
     if( my->_file_mutex.try_lock() ) {
        if( my->_write_lock.try_lock() ) {
          return true;
        } else {
          my->_file_mutex.unlock();
        }
     }
     return false;
  }

  bool file_mutex::try_lock_for( const microseconds& rel_time ) {
     return false;
  }

  bool file_mutex::try_lock_until( const time_point& abs_time ) {
     return false;
  }

  void file_mutex::lock() {
     my->_write_lock.lock();
     while( my->_reader_count.load() > 0 ) {
        fc::usleep( fc::microseconds(10) );
     }
     my->_file_mutex.lock();
  }

  void file_mutex::unlock() {
     my->_file_mutex.unlock();
     my->_write_lock.unlock();
  }

  void file_mutex::lock_shared() {
    bip::scoped_lock< fc::mutex > lock( my->_write_lock );
    if( 0 == my->_reader_count.fetch_add( 1, boost::memory_order_relaxed ) )
       my->_file_mutex.lock_sharable();
  }

  void file_mutex::unlock_shared() {
    if( 1 == my->_reader_count.fetch_add( -1, boost::memory_order_relaxed ) )
       my->_file_mutex.unlock_sharable();
  }

  bool file_mutex::try_lock_shared() {
    return false;
    if( my->_write_lock.try_lock() ) {
       if( my->_reader_count.load() == 0 && my->_file_mutex.try_lock_sharable() ) {
          my->_reader_count++;
       }
       my->_write_lock.unlock();
    }
    return false;
  }

} // namespace fc

max_stars_repo_name: DunnCreativeSS/ccd

max_issues_repo_name: DunnCreativeSS/ccd

max_forks_repo_name: DunnCreativeSS/ccd


text:
// g++ -std=c++11 Hangman.cpp Game.cpp -o hangman -lboost_regex
#include "Game.h"
#include <boost/regex.hpp>
#include <chrono>
#include <iostream>
#include <list>
#include <fstream>
#include <set>
#include <unordered_map>
#include <algorithm>
using namespace std;

// iterates through all possibilities and guessed characters to find most common character in
// possible words that is not already guessed.
char findNextGuess(set<char> const guessed, list<string> const poss)
{
	unsigned int totalCounts[256] = {0};

	for (auto const& word: poss)
	{
		// letters should only count once per word
		// eg: in "shah", the h should only count once.
		set<char> string_set;
		for (auto c : word)
			string_set.insert(c);

		for (auto c : string_set)
			if (guessed.find(c) == guessed.end())
				totalCounts[(unsigned char)c]++;
	}

	unsigned int max = 0;
	char nextGuess;
	for (int i = 0; i < 256; i++)
		if (totalCounts[i] > max)
		{
			max = totalCounts[i];
			nextGuess = (char)i;
		}

	return nextGuess;
}

// we guessed the wrong character; iterate through possibilities, remove impossible elements
void trimPoss(list<string>* poss, char const wrong_char)
{

 	for(list<string>::iterator it = poss->begin(); it != poss->end(); )
 		if ((*it).find(wrong_char) != string::npos)
  		    it = poss->erase(it);
  		else
  			++it;
}

void trimPoss(list<string>* poss, string curr)
{
	curr.insert(0,"^");
	curr.insert(curr.length(),"$");

	boost::regex expr{curr};
	for(list<string>::iterator it = poss->begin(); it != poss->end(); )
		if (!boost::regex_match(*it, expr))
			it = poss->erase(it);
		else
			++it;

}

unordered_map<int, list<string>> readDict()
{
	unordered_map<int, list<string>> lenDic;
	string line;
	ifstream myfile ("words_50000.txt");
	if (myfile.is_open())
	{
		while (getline (myfile,line))
			if (lenDic.emplace(make_pair<int, list<string>>(int(line.length()), list<string>{string(line)})).second == false)
				lenDic[line.length()].push_back(line);
		myfile.close();
	}
	else
		cout << "Unable to open file";

	return lenDic;
}

State play_game(string const word, unordered_map<int, list<string>> lenDic)
// State play_game(string const word)
{
	Game g (word);
	list<string> poss = lenDic[word.length()];
	// k4 c6 a7 b1 s1 p1 d1 m2 l2 t2
	// list<string> poss;
	// poss.push_back("back");
	// poss.push_back("sack");
	// poss.push_back("pack");
	// poss.push_back("deck");
	// poss.push_back("mace");
	// poss.push_back("lace");
	// poss.push_back("mate");
	// poss.push_back("late");

	while (g._state == PLAYING)
	{
		char guess = findNextGuess(g._guessed, poss);
		Result r = g.guess_letter(guess);
		if (r == GUESS_EXISTS)
			trimPoss(&poss, g._curr);
		else if (r == GUESS_DNE)
			trimPoss(&poss, guess);
		else
			break;
		// cout << guess << endl << g << endl;
		// for (auto w : poss)
		// 	cout << w << " ";
	}
	return g._state;
}

int main(int argc, char *argv[])
{
	unordered_map<int, list<string>> lenDic = readDict();
	if (argc == 2)
		// play_game(argv[1]);
		play_game(argv[1], lenDic);
	if (argc == 1)
	{
		int wrong = 0; int total = 0;
		typedef chrono::high_resolution_clock Clock;
		auto t1 = Clock::now();
		for (int i = 0; i < lenDic.size(); i++)
		{
			total += lenDic[i].size();
			for (auto const w : lenDic[i])
				if (play_game(w, lenDic) == LOST)
					wrong ++;
		}
		auto t2 = Clock::now();
		auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(t2-t1).count();
		int correct = total-wrong;
		cout << "Number of words tested: " << total << endl
			<< "Number of words guessed correctly: " << correct << endl
			<< "Correct Guesses (\%): " << double(correct/total) << endl
			<< "Time to run: " << duration << " ms" << endl;
	}

	return 0;
}


text:
/*******************************************************************************
Copyright(c) 2015-2020 Parker Hannifin Corp. All rights reserved.

MIT Licensed. See the included LICENSE.txt for a copy of the full MIT License.
*******************************************************************************/
#include "mscl/MicroStrain/Matrix.h"
#include "mscl/MicroStrain/ByteStream.h"

#include <boost/test/unit_test.hpp>

using namespace mscl;

BOOST_AUTO_TEST_SUITE(Matrix_Test)

BOOST_AUTO_TEST_CASE(Matrix_defaultConstructor)
{
    Matrix m;

    //check the matrix initialized correctly
    BOOST_CHECK_EQUAL(m.rows(), 0);
    BOOST_CHECK_EQUAL(m.columns(), 0);
}

BOOST_AUTO_TEST_CASE(Matrix_valuesType)
{
    ByteStream b;
    Matrix m(0, 0, valueType_float, b);

    //check that the value type is correct
    BOOST_CHECK_EQUAL(m.valuesType(), valueType_float);

    Matrix m2(0, 0, valueType_int32, b);

    //check that the value type is correct
    BOOST_CHECK_EQUAL(m2.valuesType(), valueType_int32);
}

BOOST_AUTO_TEST_CASE(Matrix_rows_columns)
{
    ByteStream b;
    Matrix m(10, 12, valueType_float, b);

    //check that the number of rows is correct
    BOOST_CHECK_EQUAL(m.rows(), 10);

    //check that the number of columns is correct
    BOOST_CHECK_EQUAL(m.columns(), 12);
}

BOOST_AUTO_TEST_CASE(Matrix_atFloat)
{
    //add 6 floats to the Matrix
    ByteStream b;
    b.append_float(1.0f);    //row 0, col 0
    b.append_float(2.0f);    //row 0, col 1
    b.append_float(3.0f);    //row 0, col 2
    b.append_float(5.0f);    //row 1, col 0
    b.append_float(6.0f);    //row 1, col 1
    b.append_float(1.234f);    //row 1, col 2

    //create a 2x3 Matrix
    Matrix m(2, 3, valueType_float, b);

    //check that the values are correct at the given indices
    BOOST_CHECK_CLOSE(m.as_floatAt(0, 0), 1.0, 0.001);
    BOOST_CHECK_CLOSE(m.as_floatAt(0, 1), 2.0, 0.001);
    BOOST_CHECK_CLOSE(m.as_floatAt(0, 2), 3.0, 0.001);
    BOOST_CHECK_CLOSE(m.as_floatAt(1, 0), 5.0, 0.001);
    BOOST_CHECK_CLOSE(m.as_floatAt(1, 1), 6.0, 0.001);
    BOOST_CHECK_CLOSE(m.as_floatAt(1, 2), 1.234, 0.001);

    //check that asking for an invalid index throws an exception
    BOOST_CHECK_THROW(m.as_floatAt(0, 3), std::out_of_range);
    BOOST_CHECK_THROW(m.as_floatAt(2, 0), std::out_of_range);
}

BOOST_AUTO_TEST_CASE(Matrix_atUint16)
{
    //add 8 values to the Matrix
    ByteStream b;
    b.append_uint16(1);        //row 0, col 0
    b.append_uint16(2);        //row 0, col 1
    b.append_uint16(3);        //row 1, col 0
    b.append_uint16(4);        //row 1, col 1
    b.append_uint16(5);        //row 2, col 0
    b.append_uint16(6);        //row 2, col 1
    b.append_uint16(7);        //row 3, col 0
    b.append_uint16(12345);    //row 3, col 1

    //create a 4x2 Matrix
    Matrix m(4, 2, valueType_uint16, b);

    //check that the values are correct at the given indices
    BOOST_CHECK_EQUAL(m.as_uint16At(0, 0), 1);
    BOOST_CHECK_EQUAL(m.as_uint16At(0, 1), 2);
    BOOST_CHECK_EQUAL(m.as_uint16At(1, 0), 3);
    BOOST_CHECK_EQUAL(m.as_uint16At(1, 1), 4);
    BOOST_CHECK_EQUAL(m.as_uint16At(2, 0), 5);
    BOOST_CHECK_EQUAL(m.as_uint16At(2, 1), 6);
    BOOST_CHECK_EQUAL(m.as_uint16At(3, 0), 7);
    BOOST_CHECK_EQUAL(m.as_uint16At(3, 1), 12345);

    //check that asking for an invalid index throws an exception
    BOOST_CHECK_THROW(m.as_uint16At(0, 2), std::out_of_range);
    BOOST_CHECK_THROW(m.as_uint16At(4, 0), std::out_of_range);
}

BOOST_AUTO_TEST_CASE(Matrix_as_uint8At)
{
    //add 8 values to the Matrix
    ByteStream b;
    b.append_uint8(1);        //row 0, col 0
    b.append_uint8(2);        //row 0, col 1
    b.append_uint8(3);        //row 1, col 0
    b.append_uint8(4);        //row 1, col 1
    b.append_uint8(5);        //row 2, col 0
    b.append_uint8(6);        //row 2, col 1
    b.append_uint8(7);        //row 3, col 0
    b.append_uint8(8);        //row 3, col 1

    //create a 4x2 Matrix
    Matrix m(4, 2, valueType_uint8, b);

    //check that the values are correct at the given indices
    BOOST_CHECK_EQUAL(m.as_uint8At(0, 0), 1);
    BOOST_CHECK_EQUAL(m.as_uint8At(0, 1), 2);
    BOOST_CHECK_EQUAL(m.as_uint8At(1, 0), 3);
    BOOST_CHECK_EQUAL(m.as_uint8At(1, 1), 4);
    BOOST_CHECK_EQUAL(m.as_uint8At(2, 0), 5);
    BOOST_CHECK_EQUAL(m.as_uint8At(2, 1), 6);
    BOOST_CHECK_EQUAL(m.as_uint8At(3, 0), 7);
    BOOST_CHECK_EQUAL(m.as_uint8At(3, 1), 8);

    //check that asking for an invalid index throws an exception
    BOOST_CHECK_THROW(m.as_uint8At(0, 2), std::out_of_range);
    BOOST_CHECK_THROW(m.as_uint8At(4, 0), std::out_of_range);
}

BOOST_AUTO_TEST_SUITE_END()

max_stars_repo_name: contagon/MSCL

max_stars_repo_licenses: BSL-1.0 OpenSSL MIT

max_issues_repo_name: contagon/MSCL

max_issues_repo_licenses: BSL-1.0 OpenSSL MIT

max_forks_repo_name: contagon/MSCL

max_forks_repo_licenses: BSL-1.0 OpenSSL MIT


text:
#include <Parsers/ASTBackupQuery.h>
#include <Parsers/ASTSetQuery.h>
#include <IO/Operators.h>
#include <Common/assert_cast.h>
#include <Common/quoteString.h>
#include <boost/range/algorithm_ext/erase.hpp>

namespace DB
{
namespace
{
    using Kind = ASTBackupQuery::Kind;
    using Element = ASTBackupQuery::Element;
    using ElementType = ASTBackupQuery::ElementType;

    void formatPartitions(const ASTs & partitions, const IAST::FormatSettings & format)
    {
        format.ostr << " " << (format.hilite ? IAST::hilite_keyword : "") << ((partitions.size() == 1) ? "PARTITION" : "PARTITIONS") << " "
                    << (format.hilite ? IAST::hilite_none : "");
        bool need_comma = false;
        for (const auto & partition : partitions)
        {
            if (std::exchange(need_comma, true))
                format.ostr << ",";
            format.ostr << " ";
            partition->format(format);
        }
    }

    void formatExceptDatabases(const std::set<String> & except_databases, const IAST::FormatSettings & format)
    {
        if (except_databases.empty())
            return;

        format.ostr << (format.hilite ? IAST::hilite_keyword : "") << " EXCEPT "
                    << (except_databases.size() == 1 ? "DATABASE" : "DATABASES") << " " << (format.hilite ? IAST::hilite_none : "");

        bool need_comma = false;
        for (const auto & database_name : except_databases)
        {
            if (std::exchange(need_comma, true))
                format.ostr << ",";
            format.ostr << backQuoteIfNeed(database_name);
        }
    }

    void formatExceptTables(const std::set<DatabaseAndTableName> & except_tables, const IAST::FormatSettings & format)
    {
        if (except_tables.empty())
            return;

        format.ostr << (format.hilite ? IAST::hilite_keyword : "") << " EXCEPT " << (except_tables.size() == 1 ? "TABLE" : "TABLES") << " "
                    << (format.hilite ? IAST::hilite_none : "");

        bool need_comma = false;
        for (const auto & table_name : except_tables)
        {
            if (std::exchange(need_comma, true))
                format.ostr << ", ";

            if (!table_name.first.empty())
                format.ostr << backQuoteIfNeed(table_name.first) << ".";
            format.ostr << backQuoteIfNeed(table_name.second);
        }
    }

    void formatElement(const Element & element, const IAST::FormatSettings & format)
    {
        switch (element.type)
        {
            case ElementType::TABLE:
            {
                format.ostr << (format.hilite ? IAST::hilite_keyword : "") << "TABLE " << (format.hilite ? IAST::hilite_none : "");

                if (!element.database_name.empty())
                    format.ostr << backQuoteIfNeed(element.database_name) << ".";
                format.ostr << backQuoteIfNeed(element.table_name);

                if ((element.new_table_name != element.table_name) || (element.new_database_name != element.database_name))
                {
                    format.ostr << (format.hilite ? IAST::hilite_keyword : "") << " AS " << (format.hilite ? IAST::hilite_none : "");
                    if (!element.new_database_name.empty())
                        format.ostr << backQuoteIfNeed(element.new_database_name) << ".";
                    format.ostr << backQuoteIfNeed(element.new_table_name);
                }

                if (element.partitions)
                    formatPartitions(*element.partitions, format);
                break;
            }

            case ElementType::TEMPORARY_TABLE:
            {
                format.ostr << (format.hilite ? IAST::hilite_keyword : "") << "TEMPORARY TABLE " << (format.hilite ? IAST::hilite_none : "");
                format.ostr << backQuoteIfNeed(element.table_name);

                if (element.new_table_name != element.table_name)
                {
                    format.ostr << (format.hilite ? IAST::hilite_keyword : "") << " AS " << (format.hilite ? IAST::hilite_none : "");
                    format.ostr << backQuoteIfNeed(element.new_table_name);
                }
                break;
            }

            case ElementType::DATABASE:
            {
                format.ostr << (format.hilite ? IAST::hilite_keyword : "");
                format.ostr << "DATABASE ";
                format.ostr << (format.hilite ? IAST::hilite_none : "");
                format.ostr << backQuoteIfNeed(element.database_name);

                if (element.new_database_name != element.database_name)
                {
                    format.ostr << (format.hilite ? IAST::hilite_keyword : "") << " AS " << (format.hilite ? IAST::hilite_none : "");
                    format.ostr << backQuoteIfNeed(element.new_database_name);
                }

                formatExceptTables(element.except_tables, format);
                break;
            }

            case ElementType::ALL:
            {
                format.ostr << (format.hilite ? IAST::hilite_keyword : "") << "ALL" << (format.hilite ? IAST::hilite_none : "");
                formatExceptDatabases(element.except_databases, format);
                formatExceptTables(element.except_tables, format);
                break;
            }
        }
    }

    void formatElements(const std::vector<Element> & elements, const IAST::FormatSettings & format)
    {
        bool need_comma = false;
        for (const auto & element : elements)
        {
            if (std::exchange(need_comma, true))
                format.ostr << ", ";
            formatElement(element, format);
        }
    }

    void formatSettings(const ASTPtr & settings, const ASTPtr & base_backup_name, const ASTPtr & cluster_host_ids, const IAST::FormatSettings & format)
    {
        if (!settings && !base_backup_name && !cluster_host_ids)
            return;

        format.ostr << (format.hilite ? IAST::hilite_keyword : "") << " SETTINGS " << (format.hilite ? IAST::hilite_none : "");
        bool empty = true;

        if (base_backup_name)
        {
            format.ostr << "base_backup = ";
            base_backup_name->format(format);
            empty = false;
        }

        if (settings)
        {
            if (!empty)
                format.ostr << ", ";
            settings->format(format);
            empty = false;
        }

        if (cluster_host_ids)
        {
            if (!empty)
                format.ostr << ", ";
            format.ostr << "cluster_host_ids = ";
            cluster_host_ids->format(format);
        }
    }

    ASTPtr rewriteSettingsWithoutOnCluster(ASTPtr settings, const WithoutOnClusterASTRewriteParams & params)
    {
        SettingsChanges changes;
        if (settings)
            changes = assert_cast<ASTSetQuery *>(settings.get())->changes;

        boost::remove_erase_if(
            changes,
            [](const SettingChange & change)
            {
                const String & name = change.name;
                return (name == "internal") || (name == "async") || (name == "host_id");
            });

        changes.emplace_back("internal", true);
        changes.emplace_back("async", false);
        changes.emplace_back("host_id", params.host_id);

        auto out_settings = std::make_shared<ASTSetQuery>();
        out_settings->changes = std::move(changes);
        out_settings->is_standalone = false;
        return out_settings;
    }
}

void ASTBackupQuery::Element::setCurrentDatabase(const String & current_database)
{
    if (current_database.empty())
        return;

    if (type == ASTBackupQuery::TABLE)
    {
        if (database_name.empty())
            database_name = current_database;
        if (new_database_name.empty())
            new_database_name = current_database;
    }
    else if (type == ASTBackupQuery::ALL)
    {
        for (auto it = except_tables.begin(); it != except_tables.end();)
        {
            const auto & except_table = *it;
            if (except_table.first.empty())
            {
                except_tables.emplace(DatabaseAndTableName{current_database, except_table.second});
                it = except_tables.erase(it);
            }
            else
            {
                ++it;
            }
        }
    }
}

void ASTBackupQuery::setCurrentDatabase(ASTBackupQuery::Elements & elements, const String & current_database)
{
    for (auto & element : elements)
        element.setCurrentDatabase(current_database);
}

String ASTBackupQuery::getID(char) const
{
    return (kind == Kind::BACKUP) ? "BackupQuery" : "RestoreQuery";
}

ASTPtr ASTBackupQuery::clone() const
{
    return std::make_shared<ASTBackupQuery>(*this);
}

void ASTBackupQuery::formatImpl(const FormatSettings & format, FormatState &, FormatStateStacked) const
{
    format.ostr << (format.hilite ? hilite_keyword : "") << ((kind == Kind::BACKUP) ? "BACKUP " : "RESTORE ")
                << (format.hilite ? hilite_none : "");

    formatElements(elements, format);
    formatOnCluster(format);

    format.ostr << (format.hilite ? hilite_keyword : "") << ((kind == Kind::BACKUP) ? " TO " : " FROM ") << (format.hilite ? hilite_none : "");
    backup_name->format(format);

    if (settings || base_backup_name)
        formatSettings(settings, base_backup_name, cluster_host_ids, format);
}

ASTPtr ASTBackupQuery::getRewrittenASTWithoutOnCluster(const WithoutOnClusterASTRewriteParams & params) const
{
    auto new_query = std::static_pointer_cast<ASTBackupQuery>(clone());
    new_query->cluster.clear();
    new_query->settings = rewriteSettingsWithoutOnCluster(new_query->settings, params);
    new_query->setCurrentDatabase(new_query->elements, params.default_database);
    return new_query;
}

}


text:
#include "simulation_parser.hpp"

#include "exceptions.hpp"
#include "modules/abstract_module.hpp"
#include "modules/module_factory.hpp"

#include <iomanip>
#include <fstream>
#include <thread>

#include <boost/filesystem.hpp>
#include <termcolor/termcolor.hpp>
#include <range/v3/algorithm/find.hpp>
#include <range/v3/algorithm/find_if.hpp>

namespace neon
{
int simulation_parser::threads = std::thread::hardware_concurrency();

simulation_parser::simulation_parser(std::string const& input_file_name)
    : input_file_name(input_file_name)
{
    if (input_file_name == "" || input_file_name.empty())
    {
        throw std::domain_error("No input file found.  An input file needs to be provided: "
                                "\"<filename>.neon\"\n");
    }

    boost::filesystem::path input_path(input_file_name);

    // Strip the extension from the filename
    std::string extension = boost::filesystem::extension(input_path);
    std::string base_name = boost::filesystem::basename(input_path);

    if (extension != ".json")
    {
        throw std::domain_error("Extension \"" + extension + "\" is not supported, use \".neon\"");
    }
    this->parse();
}

simulation_parser::~simulation_parser() = default;

void simulation_parser::parse()
{
    auto start = std::chrono::high_resolution_clock::now();

    this->print_banner();

    std::cout << std::string(2, ' ') << termcolor::bold << "Preprocessing mesh and simulation data\n"
              << termcolor::reset;

    {
        std::ifstream file(input_file_name);
        file >> root;
    }

    this->check_input_fields();

    if (root.count("Cores"))
    {
        threads = root["Cores"];
    }

    auto const material_names = this->parse_material_names(root["Material"]);
    auto const part_names = this->parse_part_names(root["Part"], material_names);

    // Add in the parts and populate the mesh stores
    for (auto const& part : root["Part"])
    {
        auto const material = *ranges::find_if(root["Material"], [&part](auto const& material) {
            return material["Name"] == part["Material"];
        });

        auto const read_start = std::chrono::high_resolution_clock::now();

        std::ifstream mesh_input_stream(part["Name"].get<std::string>() + ".mesh");

        json mesh_file;

        mesh_input_stream >> mesh_file;

        auto const read_end = std::chrono::high_resolution_clock::now();

        std::cout << std::string(4, ' ') << "Parsed " << part["Name"] << " mesh from file in "
                  << std::chrono::duration<double>(read_end - read_start).count() << "s\n";

        mesh_store.try_emplace(part["Name"], mesh_file, material);

        std::cout << std::string(4, ' ') << "Allocated internal storage for " << part["Name"]
                  << " in "
                  << std::chrono::duration<double>(std::chrono::high_resolution_clock::now()
                                                   - read_end)
                         .count()
                  << "s\n";
    }

    // Build a list of all the load steps for a given mesh
    for (auto const& simulation : root["SimulationCases"])
    {
        // Ensure the required fields exist
        for (auto required_field : {"Name", "Time", "Solution", "LinearSolver"})
        {
            if (!simulation.count(required_field))
            {
                throw std::runtime_error("A simulation case needs a \""
                                         + std::string(required_field) + "\" field\n");
            }
        }
        // Multibody simulations not (yet) supported
        assert(simulation["Mesh"].size() == 1);

        // Make sure the simulation mesh exists in the mesh store
        if (mesh_store.find(simulation["Mesh"][0]["Name"]) == mesh_store.end())
        {
            throw std::runtime_error("Mesh name \"" + simulation["Mesh"][0]["Name"].get<std::string>()
                                     + "\" was not found in the mesh store");
        }
    }
    build_simulation_tree();

    auto const end = std::chrono::high_resolution_clock::now();
    std::chrono::duration<double> elapsed_seconds = end - start;

    std::cout << termcolor::bold << termcolor::green << std::string(2, ' ')
              << "Preprocessing complete in " << elapsed_seconds.count() << "s\n"
              << termcolor::reset << std::endl;
}

void simulation_parser::start()
{
    // Allocate the modules storage, which automatically checks for correct input
    // and throws the appropriate exception when an error is detected
    for (auto const& [name, simulations] : multistep_simulations)
    {
        for (auto const& simulation : simulations)
        {
            modules.emplace_back(make_module(simulation, mesh_store));
        }
    }
    for (auto const& module : modules) module->perform_simulation();
}

void simulation_parser::build_simulation_tree()
{
    // For each simulation step, the total number of subsequent relationships
    // need to be determined, such that an analysis can be performed in order
    // Build a list of all the load steps for a given mesh
    for (auto const& simulation : root["SimulationCases"])
    {
        if (!simulation.count("Inherits"))
        {
            multistep_simulations[simulation["Name"]].emplace_front(simulation);
            find_children(simulation["Name"], simulation["Name"]);
        }
    }

    for (auto const& [name, queue] : multistep_simulations)
    {
        std::cout << std::string(4, ' ') << "Simulation \"" << name << "\" is continued by:\n";
        for (auto const& item : queue)
        {
            std::cout << std::string(4, ' ') << item["Name"] << std::endl;
        }
    }
}

void simulation_parser::find_children(std::string const& parent_name,
                                      std::string const& next_parent_name)
{
    for (auto const& simulation : root["SimulationCases"])
    {
        if (!simulation.count("Inherits")) continue;

        if (simulation["Inherits"].get<std::string>() == next_parent_name)
        {
            multistep_simulations[parent_name].push_back(simulation);
            // Recursive step
            find_children(parent_name, simulation["Name"]);
        }
    }
}

void simulation_parser::print_banner() const
{
    std::string const welcome_message("neon - a non-linear finite element code");

    std::cout << termcolor::bold;
    std::cout << std::setw(welcome_message.length() + 9) << std::setfill('=') << "\n";
    std::cout << std::string(4, ' ') << welcome_message << "\n";
    std::cout << std::setw(welcome_message.length() + 9) << std::setfill('=') << "\n";
    std::cout << termcolor::reset << std::endl << std::setfill(' ');
}

void simulation_parser::check_input_fields() const
{
    // Check the important fields exist before anything else is done
    if (!root.count("Part"))
    {
        throw std::runtime_error("Part is not in input file");
    }
    if (!root.count("Name"))
    {
        throw std::runtime_error("Name is not in input file");
    }
    if (!root.count("Material"))
    {
        throw std::runtime_error("Material is not in input file");
    }
    if (!root.count("SimulationCases"))
    {
        throw std::runtime_error("SimulationCases is not in input file");
    }
}

std::unordered_set<std::string> simulation_parser::parse_material_names(json const& materials) const
{
    std::unordered_set<std::string> material_names;

    for (auto const& material : root["Material"])
    {
        if (!material.count("Name"))
        {
            throw std::runtime_error("Material: Name is missing");
        }

        auto const [it, inserted] = material_names.emplace(material["Name"].get<std::string>());

        if (!inserted) throw std::domain_error("Material");
    }
    return material_names;
}

std::unordered_set<std::string> simulation_parser::parse_part_names(
    json const& parts,
    std::unordered_set<std::string> const& material_names) const
{
    std::unordered_set<std::string> part_names;

    // Load in all the part names and error check
    for (auto const& part : root["Part"])
    {
        if (!part.count("Name"))
        {
            throw std::domain_error("Part: Name is missing");
        }

        if (ranges::find(material_names, part["Material"].get<std::string>()) == material_names.end())
        {
            throw std::domain_error("The part material was not found in the provided "
                                    "materials\n");
        }

        auto const [it, inserted] = part_names.emplace(part["Name"].get<std::string>());

        if (!inserted) throw std::domain_error("Part is defined more than once");
    }
    return part_names;
}
}

max_stars_repo_name: annierhea/neon

max_issues_repo_name: annierhea/neon

max_forks_repo_name: annierhea/neon