<commit_before>// commodconverter.cc
// Implements the CommodConverter class
#include "commodconverter.h"

namespace commodconverter {

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CommodConverter::CommodConverter(cyclus::Context* ctx)
    : cyclus::Facility(ctx) {
  cyclus::Warn<cyclus::EXPERIMENTAL_WARNING>("the CommodConverter is experimental.");
    };

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// pragmas

#pragma cyclus def schema commodconverter::CommodConverter

#pragma cyclus def annotations commodconverter::CommodConverter

#pragma cyclus def initinv commodconverter::CommodConverter

#pragma cyclus def snapshotinv commodconverter::CommodConverter

#pragma cyclus def infiletodb commodconverter::CommodConverter

#pragma cyclus def snapshot commodconverter::CommodConverter

#pragma cyclus def clone commodconverter::CommodConverter

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CommodConverter::InitFrom(CommodConverter* m) {

  #pragma cyclus impl initfromcopy commodconverter::CommodConverter

  cyclus::toolkit::CommodityProducer::Copy(m);
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CommodConverter::InitFrom(cyclus::QueryableBackend* b){

  #pragma cyclus impl initfromdb commodconverter::CommodConverter

  using cyclus::toolkit::Commodity;
  Commodity commod = Commodity(out_commod);
  cyclus::toolkit::CommodityProducer::Add(commod);
  cyclus::toolkit::CommodityProducer::SetCapacity(commod, capacity);
  cyclus::toolkit::CommodityProducer::SetCost(commod, cost);
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CommodConverter::EnterNotify() {
  Facility::EnterNotify();

  using cyclus::toolkit::Commodity;
  Commodity commod = Commodity(out_commod);
  cyclus::toolkit::CommodityProducer::Add(commod);
  cyclus::toolkit::CommodityProducer::SetCapacity(commod, capacity);
  cyclus::toolkit::CommodityProducer::SetCost(commod, cost);
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
std::string CommodConverter::str() {
  std::stringstream ss;
  std::string ans;
  if (cyclus::toolkit::CommodityProducer::
      Produces(cyclus::toolkit::Commodity(out_commod_()))){
    ans = "yes";
  } else {
    ans = "no";
  }
  ss << cyclus::Facility::str();
  ss << " has facility parameters {" << "\n"
     << "     Input Commodity = " << in_commod_() << ",\n"
     << "     Output Commodity = " << out_commod_() << ",\n"
     << "     Process Time = " << process_time_() << ",\n"
     << "     Capacity = " << capacity_() << ",\n"
     << " commod producer members: " << " produces "
     << out_commod << "?:" << ans
     << " capacity: " << cyclus::toolkit::CommodityProducer::Capacity(out_commod_())
     << " cost: " << cyclus::toolkit::CommodityProducer::Cost(out_commod_())
     << "'}";
  return ss.str();
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CommodConverter::Tick() {
  LOG(cyclus::LEV_INFO3, "ComCnv") << prototype() << " is ticking {";

  if (current_capacity() > cyclus::eps()) {
    LOG(cyclus::LEV_INFO4, "ComCnv") << " has capacity for " << current_capacity()
                                       << " kg of " << in_commod
                                       << " recipe: " << in_recipe << ".";
  }

  LOG(cyclus::LEV_INFO3, "ComCnv") << "}";
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CommodConverter::Tock() {
  LOG(cyclus::LEV_INFO3, "ComCnv") << prototype() << " is tocking {";

  BeginProcessing_(); // place unprocessed inventory into processing

  if( ready() >= 0 || process_time_() == 0 ) {
    Convert_(capacity_()); // place processing into stocks
  }

  LOG(cyclus::LEV_INFO3, "ComCnv") << "}";
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
std::set<cyclus::RequestPortfolio<cyclus::Material>::Ptr>
CommodConverter::GetMatlRequests() {
  using cyclus::CapacityConstraint;
  using cyclus::Material;
  using cyclus::RequestPortfolio;
  using cyclus::Request;

  std::set<RequestPortfolio<Material>::Ptr> ports;

  RequestPortfolio<Material>::Ptr port(new RequestPortfolio<Material>());
  Material::Ptr mat = Request_();
  double amt = mat->quantity();

  if (amt > cyclus::eps()) {
    //CapacityConstraint<Material> cc(amt);
    //port->AddConstraint(cc);

    port->AddRequest(mat, this, in_commod_());

    ports.insert(port);
  }

  return ports;
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CommodConverter::AcceptMatlTrades(
  const std::vector< std::pair<cyclus::Trade<cyclus::Material>,
  cyclus::Material::Ptr> >& responses) {
  std::vector< std::pair<cyclus::Trade<cyclus::Material>,
      cyclus::Material::Ptr> >::const_iterator it;
  for (it = responses.begin(); it != responses.end(); ++it) {
    AddMat_(it->second);
  }
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
std::set<cyclus::BidPortfolio<cyclus::Material>::Ptr>
CommodConverter::GetMatlBids(cyclus::CommodMap<cyclus::Material>::type&
                          commod_requests) {
  using cyclus::BidPortfolio;
  using cyclus::Material;

  std::set<BidPortfolio<Material>::Ptr> ports;

  std::set<std::string>::const_iterator it;
  BidPortfolio<Material>::Ptr port = GetBids_(commod_requests,
                                              out_commod,
                                              &stocks);
  if (!port->bids().empty()) {
    ports.insert(port);
  }

  return ports;

}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CommodConverter::GetMatlTrades(
  const std::vector< cyclus::Trade<cyclus::Material> >& trades,
  std::vector<std::pair<cyclus::Trade<cyclus::Material>,
  cyclus::Material::Ptr> >& responses) {
  using cyclus::Material;
  using cyclus::Trade;

  // for each trade, respond
  std::vector< Trade<Material> >::const_iterator it;
  for (it = trades.begin(); it != trades.end(); ++it) {
    std::string commodity = it->request->commodity();
    //double qty = it->amt;
    double qty = stocks.quantity();
    // create a material pointer representing what you can offer
    Material::Ptr response = TradeResponse_(qty, &stocks);

    responses.push_back(std::make_pair(*it, response));
    LOG(cyclus::LEV_INFO5, "ComCnv") << prototype()
                                  << " just received an order"
                                  << " for " << it->amt
                                  << " of " << commodity;
  }

}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CommodConverter::AddMat_(cyclus::Material::Ptr mat) {
  // Here we do not check that the recipe matches the input recipe.

  LOG(cyclus::LEV_INFO5, "ComCnv") << prototype() << " is initially holding "
                                << inventory.quantity() << " total.";

  try {
    inventory.Push(mat);
  } catch (cyclus::Error& e) {
    e.msg(Agent::InformErrorMsg(e.msg()));
    throw e;
  }

  LOG(cyclus::LEV_INFO5, "ComCnv") << prototype() << " added " << mat->quantity()
                                << " of " << in_commod_()
                                << " to its inventory, which is holding "
                                << inventory.quantity() << " total.";

}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
cyclus::Material::Ptr CommodConverter::Request_() {
  double qty = std::max(0.0, current_capacity());
  LOG(cyclus::LEV_INFO5, "ComCnv") << prototype()
                                  << " just requested "
                                  << current_capacity()
                                  << " of commodity: " << in_commod
                                  << " with recipe: " << in_recipe;
  return cyclus::Material::CreateUntracked(qty,
                                        context()->GetRecipe(in_recipe));
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
cyclus::BidPortfolio<cyclus::Material>::Ptr CommodConverter::GetBids_(
    cyclus::CommodMap<cyclus::Material>::type& commod_requests,
    std::string commod,
    cyclus::toolkit::ResourceBuff* buffer) {
  using cyclus::Bid;
  using cyclus::BidPortfolio;
  using cyclus::CapacityConstraint;
  using cyclus::Composition;
  using cyclus::Converter;
  using cyclus::Material;
  using cyclus::Request;
  using cyclus::ResCast;
  using cyclus::toolkit::ResourceBuff;

  BidPortfolio<Material>::Ptr port(new BidPortfolio<Material>());

  if (commod_requests.count(commod) > 0 && buffer->quantity() > 0) {
    std::vector<Request<Material>*>& requests = commod_requests.at(commod);

    // get offer composition
    Material::Ptr back = ResCast<Material>(buffer->Pop(ResourceBuff::BACK));
    Composition::Ptr comp = back->comp();
    buffer->Push(back);

    std::vector<Request<Material>*>::iterator it;
    for (it = requests.begin(); it != requests.end(); ++it) {
      Request<Material>* req = *it;
      double qty = std::min(req->target()->quantity(), buffer->quantity());
      Material::Ptr offer = Material::CreateUntracked(qty, comp);
      port->AddBid(req, offer, this);
    }

    //CapacityConstraint<Material> cc(buffer->quantity());
    //port->AddConstraint(cc);
  }

  return port;
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
cyclus::Material::Ptr CommodConverter::TradeResponse_(
    double qty,
    cyclus::toolkit::ResourceBuff* buffer) {
  using cyclus::Material;
  using cyclus::ResCast;

  std::vector<Material::Ptr> manifest;
  try {
    // pop amount from inventory and blob it into one material
    manifest = ResCast<Material>(buffer->PopQty(qty));
  } catch(cyclus::Error& e) {
    e.msg(Agent::InformErrorMsg(e.msg()));
    throw e;
  }

  Material::Ptr response = manifest[0];
  for (int i = 1; i < manifest.size(); i++) {
    response->Absorb(manifest[i]);
  }
  return response;
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CommodConverter::BeginProcessing_(){
  if( inventory.count() > 0 ){
    try {
      processing[context()->time()].Push(inventory.Pop());
      LOG(cyclus::LEV_DEBUG2, "ComCnv") << "CommodConverter " << prototype()
                                      << " added resources to processing at t= "
                                      << context()->time();
    } catch (cyclus::Error& e) {
      e.msg(Agent::InformErrorMsg(e.msg()));
      throw e;
    }
  }
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CommodConverter::Convert_(double cap){
  using cyclus::Material;
  using cyclus::ResCast;
  using cyclus::toolkit::ResourceBuff;
  using cyclus::toolkit::Manifest;

  int t = ready();
  if ( ProcessingAmt_(t) > 0 ){
    try {
      double to_pop = std::min(cap, processing[t].quantity());
      // pop appropriate amount of material from processing
      std::vector<Material::Ptr> to_conv =
        ResCast<Material>(processing[t].PopQty(to_pop));
      // if an out_recipe was provided, transmute it
      std::vector<Material::Ptr>::iterator mat;
      if( out_recipe == "" ){
        // if no out recipe, then no transmute needed
        stocks.PushAll(to_conv);
      } else {
        // transmute each mat
        for(mat=to_conv.begin(); mat!=to_conv.end(); ++mat) {
          (*mat)->Transmute(context()->GetRecipe(out_recipe));
          // put it in the stocks
          stocks.Push(*mat);
        }
      }
      AdvanceUnconverted_(t);
      LOG(cyclus::LEV_INFO1, "ComCnv") << "CommodConverter " << prototype()
                                        << " converted quantity : " << to_pop
                                        << " from " << in_commod
                                        << " to " << out_commod;
    } catch (cyclus::Error& e) {
      e.msg(Agent::InformErrorMsg(e.msg()));
      throw e;
    }
  }
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
double CommodConverter::ProcessingAmt_(int time) {
  using cyclus::toolkit::ResourceBuff;
  double to_ret = 0;
  std::map<int, ResourceBuff>::iterator proc = processing.find(time);
  if ( proc!=processing.end() &&
      proc->second.quantity() > 0 ) {
    to_ret = proc->second.quantity();
  }
  return to_ret;
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CommodConverter::AdvanceUnconverted_(int time){
  using cyclus::Material;
  using cyclus::ResCast;

  double to_pop = ProcessingAmt_(time);
  if ( to_pop > 0 ) {
    try {
      std::vector<Material::Ptr> to_advance =
      ResCast<Material>(processing[time].PopQty(to_pop));
      processing[time+1].PushAll(to_advance);
    } catch (cyclus::Error& e) {
      e.msg(Agent::InformErrorMsg(e.msg()));
      throw e;
    }
  }
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
extern "C" cyclus::Agent* ConstructCommodConverter(cyclus::Context* ctx) {
  return new CommodConverter(ctx);
}

} // namespace commodconverter
<commit_msg>fixed popqty seg fault when qty = 0<commit_after>// commodconverter.cc
// Implements the CommodConverter class
#include "commodconverter.h"

namespace commodconverter {

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CommodConverter::CommodConverter(cyclus::Context* ctx)
    : cyclus::Facility(ctx) {
  cyclus::Warn<cyclus::EXPERIMENTAL_WARNING>("the CommodConverter is experimental.");
    };

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// pragmas

#pragma cyclus def schema commodconverter::CommodConverter

#pragma cyclus def annotations commodconverter::CommodConverter

#pragma cyclus def initinv commodconverter::CommodConverter

#pragma cyclus def snapshotinv commodconverter::CommodConverter

#pragma cyclus def infiletodb commodconverter::CommodConverter

#pragma cyclus def snapshot commodconverter::CommodConverter

#pragma cyclus def clone commodconverter::CommodConverter

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CommodConverter::InitFrom(CommodConverter* m) {

  #pragma cyclus impl initfromcopy commodconverter::CommodConverter

  cyclus::toolkit::CommodityProducer::Copy(m);
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CommodConverter::InitFrom(cyclus::QueryableBackend* b){

  #pragma cyclus impl initfromdb commodconverter::CommodConverter

  using cyclus::toolkit::Commodity;
  Commodity commod = Commodity(out_commod);
  cyclus::toolkit::CommodityProducer::Add(commod);
  cyclus::toolkit::CommodityProducer::SetCapacity(commod, capacity);
  cyclus::toolkit::CommodityProducer::SetCost(commod, cost);
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CommodConverter::EnterNotify() {
  Facility::EnterNotify();

  using cyclus::toolkit::Commodity;
  Commodity commod = Commodity(out_commod);
  cyclus::toolkit::CommodityProducer::Add(commod);
  cyclus::toolkit::CommodityProducer::SetCapacity(commod, capacity);
  cyclus::toolkit::CommodityProducer::SetCost(commod, cost);
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
std::string CommodConverter::str() {
  std::stringstream ss;
  std::string ans;
  if (cyclus::toolkit::CommodityProducer::
      Produces(cyclus::toolkit::Commodity(out_commod_()))){
    ans = "yes";
  } else {
    ans = "no";
  }
  ss << cyclus::Facility::str();
  ss << " has facility parameters {" << "\n"
     << "     Input Commodity = " << in_commod_() << ",\n"
     << "     Output Commodity = " << out_commod_() << ",\n"
     << "     Process Time = " << process_time_() << ",\n"
     << "     Capacity = " << capacity_() << ",\n"
     << " commod producer members: " << " produces "
     << out_commod << "?:" << ans
     << " capacity: " << cyclus::toolkit::CommodityProducer::Capacity(out_commod_())
     << " cost: " << cyclus::toolkit::CommodityProducer::Cost(out_commod_())
     << "'}";
  return ss.str();
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CommodConverter::Tick() {
  LOG(cyclus::LEV_INFO3, "ComCnv") << prototype() << " is ticking {";

  if (current_capacity() > cyclus::eps()) {
    LOG(cyclus::LEV_INFO4, "ComCnv") << " has capacity for " << current_capacity()
                                       << " kg of " << in_commod
                                       << " recipe: " << in_recipe << ".";
  }

  LOG(cyclus::LEV_INFO3, "ComCnv") << "}";
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CommodConverter::Tock() {
  LOG(cyclus::LEV_INFO3, "ComCnv") << prototype() << " is tocking {";

  BeginProcessing_(); // place unprocessed inventory into processing

  if( ready() >= 0 || process_time_() == 0 ) {
    Convert_(capacity_()); // place processing into stocks
  }

  LOG(cyclus::LEV_INFO3, "ComCnv") << "}";
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
std::set<cyclus::RequestPortfolio<cyclus::Material>::Ptr>
CommodConverter::GetMatlRequests() {
  using cyclus::CapacityConstraint;
  using cyclus::Material;
  using cyclus::RequestPortfolio;
  using cyclus::Request;

  std::set<RequestPortfolio<Material>::Ptr> ports;

  RequestPortfolio<Material>::Ptr port(new RequestPortfolio<Material>());
  Material::Ptr mat = Request_();
  double amt = mat->quantity();

  if (amt > cyclus::eps()) {
    //CapacityConstraint<Material> cc(amt);
    //port->AddConstraint(cc);

    port->AddRequest(mat, this, in_commod_());

    ports.insert(port);
  }

  return ports;
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CommodConverter::AcceptMatlTrades(
  const std::vector< std::pair<cyclus::Trade<cyclus::Material>,
  cyclus::Material::Ptr> >& responses) {
  std::vector< std::pair<cyclus::Trade<cyclus::Material>,
      cyclus::Material::Ptr> >::const_iterator it;
  for (it = responses.begin(); it != responses.end(); ++it) {
    AddMat_(it->second);
  }
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
std::set<cyclus::BidPortfolio<cyclus::Material>::Ptr>
CommodConverter::GetMatlBids(cyclus::CommodMap<cyclus::Material>::type&
                          commod_requests) {
  using cyclus::BidPortfolio;
  using cyclus::Material;

  std::set<BidPortfolio<Material>::Ptr> ports;

  std::set<std::string>::const_iterator it;
  BidPortfolio<Material>::Ptr port = GetBids_(commod_requests,
                                              out_commod,
                                              &stocks);
  if (!port->bids().empty()) {
    ports.insert(port);
  }

  return ports;

}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CommodConverter::GetMatlTrades(
  const std::vector< cyclus::Trade<cyclus::Material> >& trades,
  std::vector<std::pair<cyclus::Trade<cyclus::Material>,
  cyclus::Material::Ptr> >& responses) {
  using cyclus::Material;
  using cyclus::Trade;

  // for each trade, respond
  std::vector< Trade<Material> >::const_iterator it;
  for (it = trades.begin(); it != trades.end(); ++it) {
    std::string commodity = it->request->commodity();
    //double qty = it->amt;
    double qty = stocks.quantity();
    // create a material pointer representing what you can offer
    if ( qty > 0 ) {
      Material::Ptr response = TradeResponse_(qty, &stocks);
      responses.push_back(std::make_pair(*it, response));
    }
    LOG(cyclus::LEV_INFO5, "ComCnv") << prototype()
                                  << " just received an order"
                                  << " for " << it->amt
                                  << " of " << commodity;
  }

}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CommodConverter::AddMat_(cyclus::Material::Ptr mat) {
  // Here we do not check that the recipe matches the input recipe.

  LOG(cyclus::LEV_INFO5, "ComCnv") << prototype() << " is initially holding "
                                << inventory.quantity() << " total.";

  try {
    inventory.Push(mat);
  } catch (cyclus::Error& e) {
    e.msg(Agent::InformErrorMsg(e.msg()));
    throw e;
  }

  LOG(cyclus::LEV_INFO5, "ComCnv") << prototype() << " added " << mat->quantity()
                                << " of " << in_commod_()
                                << " to its inventory, which is holding "
                                << inventory.quantity() << " total.";

}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
cyclus::Material::Ptr CommodConverter::Request_() {
  double qty = std::max(0.0, current_capacity());
  LOG(cyclus::LEV_INFO5, "ComCnv") << prototype()
                                  << " just requested "
                                  << current_capacity()
                                  << " of commodity: " << in_commod
                                  << " with recipe: " << in_recipe;
  return cyclus::Material::CreateUntracked(qty,
                                        context()->GetRecipe(in_recipe));
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
cyclus::BidPortfolio<cyclus::Material>::Ptr CommodConverter::GetBids_(
    cyclus::CommodMap<cyclus::Material>::type& commod_requests,
    std::string commod,
    cyclus::toolkit::ResourceBuff* buffer) {
  using cyclus::Bid;
  using cyclus::BidPortfolio;
  using cyclus::CapacityConstraint;
  using cyclus::Composition;
  using cyclus::Converter;
  using cyclus::Material;
  using cyclus::Request;
  using cyclus::ResCast;
  using cyclus::toolkit::ResourceBuff;

  BidPortfolio<Material>::Ptr port(new BidPortfolio<Material>());

  if (commod_requests.count(commod) > 0 && buffer->quantity() > 0) {
    std::vector<Request<Material>*>& requests = commod_requests.at(commod);

    // get offer composition
    Material::Ptr back = ResCast<Material>(buffer->Pop(ResourceBuff::BACK));
    Composition::Ptr comp = back->comp();
    buffer->Push(back);

    std::vector<Request<Material>*>::iterator it;
    for (it = requests.begin(); it != requests.end(); ++it) {
      Request<Material>* req = *it;
      double qty = std::min(req->target()->quantity(), buffer->quantity());
      Material::Ptr offer = Material::CreateUntracked(qty, comp);
      port->AddBid(req, offer, this);
    }

    //CapacityConstraint<Material> cc(buffer->quantity());
    //port->AddConstraint(cc);
  }

  return port;
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
cyclus::Material::Ptr CommodConverter::TradeResponse_(
    double qty,
    cyclus::toolkit::ResourceBuff* buffer) {
  using cyclus::Material;
  using cyclus::ResCast;

  std::vector<Material::Ptr> manifest;
  try {
    // pop amount from inventory and blob it into one material
    manifest = ResCast<Material>(buffer->PopQty(qty));
    Material::Ptr response = manifest[0];
    for (int i = 1; i < manifest.size(); i++) {
      response->Absorb(manifest[i]);
    }
    return response;
  } catch(cyclus::Error& e) {
    e.msg(Agent::InformErrorMsg(e.msg()));
    throw e;
  }

}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CommodConverter::BeginProcessing_(){
  if( inventory.count() > 0 ){
    try {
      processing[context()->time()].Push(inventory.Pop());
      LOG(cyclus::LEV_DEBUG2, "ComCnv") << "CommodConverter " << prototype()
                                      << " added resources to processing at t= "
                                      << context()->time();
    } catch (cyclus::Error& e) {
      e.msg(Agent::InformErrorMsg(e.msg()));
      throw e;
    }
  }
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CommodConverter::Convert_(double cap){
  using cyclus::Material;
  using cyclus::ResCast;
  using cyclus::toolkit::ResourceBuff;
  using cyclus::toolkit::Manifest;

  int t = ready();
  if ( ProcessingAmt_(t) > 0 ){
    try {
      double to_pop = std::min(cap, processing[t].quantity());
      // pop appropriate amount of material from processing
      std::vector<Material::Ptr> to_conv =
        ResCast<Material>(processing[t].PopQty(to_pop));
      // if an out_recipe was provided, transmute it
      std::vector<Material::Ptr>::iterator mat;
      if( out_recipe == "" ){
        // if no out recipe, then no transmute needed
        stocks.PushAll(to_conv);
      } else {
        // transmute each mat
        for(mat=to_conv.begin(); mat!=to_conv.end(); ++mat) {
          (*mat)->Transmute(context()->GetRecipe(out_recipe));
          // put it in the stocks
          stocks.Push(*mat);
        }
      }
      AdvanceUnconverted_(t);
      LOG(cyclus::LEV_INFO1, "ComCnv") << "CommodConverter " << prototype()
                                        << " converted quantity : " << to_pop
                                        << " from " << in_commod
                                        << " to " << out_commod
                                        << " at t= " << context()->time();
    } catch (cyclus::Error& e) {
      e.msg(Agent::InformErrorMsg(e.msg()));
      throw e;
    }
  }
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
double CommodConverter::ProcessingAmt_(int time) {
  using cyclus::toolkit::ResourceBuff;
  double to_ret = 0;
  std::map<int, ResourceBuff>::iterator proc = processing.find(time);
  if ( proc!=processing.end() &&
      proc->second.quantity() > 0 ) {
    to_ret = proc->second.quantity();
  }
  return to_ret;
}

//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CommodConverter::AdvanceUnconverted_(int time){
  using cyclus::Material;
  using cyclus::ResCast;

  double to_pop = ProcessingAmt_(time);
  if ( to_pop > 0 ) {
    try {
      std::vector<Material::Ptr> to_advance =
      ResCast<Material>(processing[time].PopQty(to_pop));
      processing[time+1].PushAll(to_advance);
    } catch (cyclus::Error& e) {
      e.msg(Agent::InformErrorMsg(e.msg()));
      throw e;
    }
  }
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
extern "C" cyclus::Agent* ConstructCommodConverter(cyclus::Context* ctx) {
  return new CommodConverter(ctx);
}

} // namespace commodconverter
<|endoftext|>


<commit_before>/*
 *   karm
 *   This file only: Copyright (C) 1999  Espen Sand, espensa@online.no
 *   Modifications (see CVS log) Copyright (C) 2000 Klarlvdalens
 *   Datakonsult AB <kalle@dalheimer.de>, Jesper Pedersen <blackie@kde.org>
 *
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * $Id$
 */
#include <qlabel.h>
#include <qlineedit.h>
#include <qlayout.h>
#include <qregexp.h>
#include <qhbox.h>
#include <kapplication.h>
#include <klocale.h>
#include <qcombobox.h>
#include <kdebug.h>
#include <qradiobutton.h>
#include <qbuttongroup.h>
#include <qpixmap.h>
#include <kiconloader.h>
#include <qwhatsthis.h>
#include "adddlg.h"
#include "karm.h"
#include "ktimewidget.h"
#include <qpushbutton.h>

AddTaskDialog::AddTaskDialog(QString caption, bool editDlg)
  :KDialogBase(0, "AddTaskDialog", true, caption, Ok|Cancel, Ok, true )
{
  QWidget *page = new QWidget( this );
  setMainWidget(page);

	QVBoxLayout *lay1 = new QVBoxLayout(page);

	QHBoxLayout *lay2 = new QHBoxLayout();
	lay1->addLayout(lay2);

	// The name of the widget
  QLabel *label = new QLabel( i18n("Task name:"), page, "name" );
  lay2->addWidget( label );
	lay2->addSpacing(5);

  _name = new QLineEdit( page, "lineedit" );

  _name->setMinimumWidth(fontMetrics().maxWidth()*15);
  lay2->addWidget( _name );

	// The "Edit Absolut" radio button
	lay1->addSpacing(10);lay1->addStretch(1);
	_absoluteRB = new QRadioButton( i18n( "Edit absolute" ), page, "_absoluteRB" );
	lay1->addWidget( _absoluteRB );
	connect( _absoluteRB, SIGNAL( clicked() ), this, SLOT(slotAbsolutePressed()) );

	// Absolute times
	QHBoxLayout *lay5 = new QHBoxLayout();
	lay1->addLayout(lay5);
	lay5->addSpacing(20);
	QGridLayout *lay3 = new QGridLayout( 2, 2, -1, "lay3" );
	lay5->addLayout(lay3);

	// Total Time
  _totalLA = new QLabel( i18n("Total:"), page, "time" );
  lay3->addWidget( _totalLA, 0, 0 );

	_totalTW = new KTimeWidget( page, "_totalTW" );
	lay3->addWidget( _totalTW, 0, 1 );

	// Session
  _sessionLA = new QLabel( i18n("Session time:"), page, "session time" );
  lay3->addWidget( _sessionLA, 1, 0 );

	_sessionTW = new KTimeWidget( page, "_sessionTW" );
  lay3->addWidget( _sessionTW, 1, 1 );

	// The "Edit relative" radio button
	lay1->addSpacing(10);lay1->addStretch(1);
	_relativeRB = new QRadioButton( i18n( "Edit relative (Apply to both session and total)" ), page, "_relativeRB" );
	lay1->addWidget( _relativeRB );
	connect( _relativeRB, SIGNAL( clicked() ), this, SLOT(slotRelativePressed()) );

	// The relative times
	QHBoxLayout *lay4 = new QHBoxLayout();
	lay1->addLayout( lay4 );
	lay4->addSpacing(20);

	_operator	= new QComboBox(page);
	_operator->insertItem( QString::fromLatin1( "+" ) );
	_operator->insertItem( QString::fromLatin1( "-" ) );
	lay4->addWidget( _operator );

	lay4->addSpacing(5);

	_diffTW = new KTimeWidget( page, "_sessionAddTW" );
	lay4->addWidget( _diffTW );

  KIconLoader loader;

  QPixmap whatsThisIM = loader.loadIcon(QString::fromLatin1("contexthelp"), KIcon::Toolbar);
  QPushButton* whatsThisBU = new QPushButton(page, "whatsThisLA");
  whatsThisBU->setFocusPolicy(NoFocus);

  connect(whatsThisBU, SIGNAL(clicked()), this, SLOT(enterWhatsThis()));
  whatsThisBU->setPixmap( whatsThisIM );
  lay4->addWidget(whatsThisBU);

	lay1->addStretch(1);

	if ( editDlg ) {
		// This is an edit dialog.
		_operator->setFocus();
	}
	else {
		// This is an initial dialog
		_name->setFocus();
	}
	origTotal = 0;
	origSession = 0;

	slotRelativePressed();

  // Whats this help.
  QWhatsThis::add(_name, i18n("Enter the name of the task here. This name is for your eyes only."));
  QWhatsThis::add(_absoluteRB, i18n("If you select this radio button, you specify that you want "
                                    "to enter the time as absolute values. For example: "
                                    "total for this task is 20 hours and 15 minutes.\n\n"
                                    "The time is specified for the session time and for the total time "
                                    "separately."));
  QWhatsThis::add(_relativeRB, i18n("If you select this radio button, you specify that you want "
                                    "to add or subtract time for the task. For example: I've worked 2 hours "
                                    "and 20 minutes more on this task (without having the timer "
                                    "running.)\n\n"
                                    "This time will be added or subtracted for both the "
                                    "session time and the total time."));
  QWhatsThis::add(_totalTW, i18n("This is the overall time this task has been running."));
  QWhatsThis::add(_sessionTW, i18n("This is the time the task has been running this session."));
  QWhatsThis::add(_diffTW, i18n("Specify how much time to add or subtract to the overall and "
                                "session time"));

}

void AddTaskDialog::enterWhatsThis()
{
  QWhatsThis::enterWhatsThisMode ();
}

void AddTaskDialog::slotAbsolutePressed()
{
	_relativeRB->setChecked( false );
	_absoluteRB->setChecked( true );

	_operator->setEnabled( false );
	_diffTW->setEnabled( false );

	_totalLA->setEnabled( true );
	_sessionLA->setEnabled( true );
	_totalTW->setEnabled( true );
	_sessionTW->setEnabled( true );
}

void AddTaskDialog::slotRelativePressed()
{
	_relativeRB->setChecked( true );
	_absoluteRB->setChecked( false );

	_operator->setEnabled( true );
	_diffTW->setEnabled( true );

	_totalLA->setEnabled( false );
	_sessionLA->setEnabled( false );
	_totalTW->setEnabled( false );
	_sessionTW->setEnabled( false );
}

void AddTaskDialog::setTask( const QString &name, long total, long session )
{
  _name->setText( name );

	_totalTW->setTime( total / 60, total % 60 );
	_sessionTW->setTime( session / 60, session % 60 );
	origTotal = total;
	origSession = session;
}

QString AddTaskDialog::taskName( void ) const
{
  return( _name->text() );
}

void AddTaskDialog::status( long *total, long *totalDiff, long *session, long *sessionDiff ) const
{
	if ( _absoluteRB->isChecked() ) {
		*total = _totalTW->time();
		*session = _sessionTW->time();
	}
	else {
		int diff = _diffTW->time();
		if ( _operator->currentItem() == 1) {
			diff = -diff;
		}
		*total = origTotal + diff;
		*session = origSession + diff;
	}

	*totalDiff = *total - origTotal;
	*sessionDiff = *session - origSession;
}

#include "adddlg.moc"
<commit_msg>GUI: accels and buddies for the "add/edit task" dialog<commit_after>/*
 *   karm
 *   This file only: Copyright (C) 1999  Espen Sand, espensa@online.no
 *   Modifications (see CVS log) Copyright (C) 2000 Klarlvdalens
 *   Datakonsult AB <kalle@dalheimer.de>, Jesper Pedersen <blackie@kde.org>
 *
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * $Id$
 */
#include <qlabel.h>
#include <qlineedit.h>
#include <qlayout.h>
#include <qregexp.h>
#include <qhbox.h>
#include <kapplication.h>
#include <klocale.h>
#include <qcombobox.h>
#include <kdebug.h>
#include <qradiobutton.h>
#include <qbuttongroup.h>
#include <qpixmap.h>
#include <kiconloader.h>
#include <qwhatsthis.h>
#include "adddlg.h"
#include "karm.h"
#include "ktimewidget.h"
#include <qpushbutton.h>

AddTaskDialog::AddTaskDialog(QString caption, bool editDlg)
  :KDialogBase(0, "AddTaskDialog", true, caption, Ok|Cancel, Ok, true )
{
  QWidget *page = new QWidget( this );
  setMainWidget(page);

	QVBoxLayout *lay1 = new QVBoxLayout(page);

	QHBoxLayout *lay2 = new QHBoxLayout();
	lay1->addLayout(lay2);

	// The name of the widget
  QLabel *label = new QLabel( i18n("Task &name:"), page, "name" );
  lay2->addWidget( label );
	lay2->addSpacing(5);

  _name = new QLineEdit( page, "lineedit" );

  _name->setMinimumWidth(fontMetrics().maxWidth()*15);
  lay2->addWidget( _name );
  label->setBuddy( _name );

	// The "Edit Absolut" radio button
	lay1->addSpacing(10);lay1->addStretch(1);
	_absoluteRB = new QRadioButton( i18n( "Edit &absolute" ), page, "_absoluteRB" );
	lay1->addWidget( _absoluteRB );
	connect( _absoluteRB, SIGNAL( clicked() ), this, SLOT(slotAbsolutePressed()) );

	// Absolute times
	QHBoxLayout *lay5 = new QHBoxLayout();
	lay1->addLayout(lay5);
	lay5->addSpacing(20);
	QGridLayout *lay3 = new QGridLayout( 2, 2, -1, "lay3" );
	lay5->addLayout(lay3);

	// Total Time
  _totalLA = new QLabel( i18n("&Total:"), page, "time" );
  lay3->addWidget( _totalLA, 0, 0 );

	_totalTW = new KTimeWidget( page, "_totalTW" );
	lay3->addWidget( _totalTW, 0, 1 );
  _totalLA->setBuddy( _totalTW );

	// Session
  _sessionLA = new QLabel( i18n("&Session time:"), page, "session time" );
  lay3->addWidget( _sessionLA, 1, 0 );

	_sessionTW = new KTimeWidget( page, "_sessionTW" );
  lay3->addWidget( _sessionTW, 1, 1 );
  _sessionLA->setBuddy( _sessionTW );

	// The "Edit relative" radio button
	lay1->addSpacing(10);lay1->addStretch(1);
	_relativeRB = new QRadioButton( i18n( "Edit &relative (Apply to both session and total)" ), page, "_relativeRB" );
	lay1->addWidget( _relativeRB );
	connect( _relativeRB, SIGNAL( clicked() ), this, SLOT(slotRelativePressed()) );

	// The relative times
	QHBoxLayout *lay4 = new QHBoxLayout();
	lay1->addLayout( lay4 );
	lay4->addSpacing(20);

	_operator	= new QComboBox(page);
	_operator->insertItem( QString::fromLatin1( "+" ) );
	_operator->insertItem( QString::fromLatin1( "-" ) );
	lay4->addWidget( _operator );

	lay4->addSpacing(5);

	_diffTW = new KTimeWidget( page, "_sessionAddTW" );
	lay4->addWidget( _diffTW );

  KIconLoader loader;

  QPixmap whatsThisIM = loader.loadIcon(QString::fromLatin1("contexthelp"), KIcon::Toolbar);
  QPushButton* whatsThisBU = new QPushButton(page, "whatsThisLA");
  whatsThisBU->setFocusPolicy(NoFocus);

  connect(whatsThisBU, SIGNAL(clicked()), this, SLOT(enterWhatsThis()));
  whatsThisBU->setPixmap( whatsThisIM );
  lay4->addWidget(whatsThisBU);

	lay1->addStretch(1);

	if ( editDlg ) {
		// This is an edit dialog.
		_operator->setFocus();
	}
	else {
		// This is an initial dialog
		_name->setFocus();
	}
	origTotal = 0;
	origSession = 0;

	slotRelativePressed();

  // Whats this help.
  QWhatsThis::add(_name, i18n("Enter the name of the task here. This name is for your eyes only."));
  QWhatsThis::add(_absoluteRB, i18n("If you select this radio button, you specify that you want "
                                    "to enter the time as absolute values. For example: "
                                    "total for this task is 20 hours and 15 minutes.\n\n"
                                    "The time is specified for the session time and for the total time "
                                    "separately."));
  QWhatsThis::add(_relativeRB, i18n("If you select this radio button, you specify that you want "
                                    "to add or subtract time for the task. For example: I've worked 2 hours "
                                    "and 20 minutes more on this task (without having the timer "
                                    "running.)\n\n"
                                    "This time will be added or subtracted for both the "
                                    "session time and the total time."));
  QWhatsThis::add(_totalTW, i18n("This is the overall time this task has been running."));
  QWhatsThis::add(_sessionTW, i18n("This is the time the task has been running this session."));
  QWhatsThis::add(_diffTW, i18n("Specify how much time to add or subtract to the overall and "
                                "session time"));

}

void AddTaskDialog::enterWhatsThis()
{
  QWhatsThis::enterWhatsThisMode ();
}

void AddTaskDialog::slotAbsolutePressed()
{
	_relativeRB->setChecked( false );
	_absoluteRB->setChecked( true );

	_operator->setEnabled( false );
	_diffTW->setEnabled( false );

	_totalLA->setEnabled( true );
	_sessionLA->setEnabled( true );
	_totalTW->setEnabled( true );
	_sessionTW->setEnabled( true );
}

void AddTaskDialog::slotRelativePressed()
{
	_relativeRB->setChecked( true );
	_absoluteRB->setChecked( false );

	_operator->setEnabled( true );
	_diffTW->setEnabled( true );

	_totalLA->setEnabled( false );
	_sessionLA->setEnabled( false );
	_totalTW->setEnabled( false );
	_sessionTW->setEnabled( false );
}

void AddTaskDialog::setTask( const QString &name, long total, long session )
{
  _name->setText( name );

	_totalTW->setTime( total / 60, total % 60 );
	_sessionTW->setTime( session / 60, session % 60 );
	origTotal = total;
	origSession = session;
}

QString AddTaskDialog::taskName( void ) const
{
  return( _name->text() );
}

void AddTaskDialog::status( long *total, long *totalDiff, long *session, long *sessionDiff ) const
{
	if ( _absoluteRB->isChecked() ) {
		*total = _totalTW->time();
		*session = _sessionTW->time();
	}
	else {
		int diff = _diffTW->time();
		if ( _operator->currentItem() == 1) {
			diff = -diff;
		}
		*total = origTotal + diff;
		*session = origSession + diff;
	}

	*totalDiff = *total - origTotal;
	*sessionDiff = *session - origSession;
}

#include "adddlg.moc"
<|endoftext|>


<commit_before>#pragma once

#include <QString>
#include <QtGlobal>

#define CHATTERINO_VERSION "2.2.3-beta2"

#if defined(Q_OS_WIN)
#    define CHATTERINO_OS "win"
#elif defined(Q_OS_MACOS)
#    define CHATTERINO_OS "macos"
#elif defined(Q_OS_LINUX)
#    define CHATTERINO_OS "linux"
#elif defined(Q_OS_FREEBSD)
#    define CHATTERINO_OS "freebsd"
#else
#    define CHATTERINO_OS "unknown"
#endif

namespace chatterino {

class Version
{
public:
    static const Version &instance();

    const QString &version() const;
    const QString &commitHash() const;
    const QString &dateOfBuild() const;
    const QString &fullVersion() const;
    const bool &isSupportedOS() const;

private:
    Version();

    QString version_;
    QString commitHash_;
    QString dateOfBuild_;
    QString fullVersion_;
    bool isSupportedOS_;
};

};  // namespace chatterino
<commit_msg>bumped version<commit_after>#pragma once

#include <QString>
#include <QtGlobal>

#define CHATTERINO_VERSION "2.3"

#if defined(Q_OS_WIN)
#    define CHATTERINO_OS "win"
#elif defined(Q_OS_MACOS)
#    define CHATTERINO_OS "macos"
#elif defined(Q_OS_LINUX)
#    define CHATTERINO_OS "linux"
#elif defined(Q_OS_FREEBSD)
#    define CHATTERINO_OS "freebsd"
#else
#    define CHATTERINO_OS "unknown"
#endif

namespace chatterino {

class Version
{
public:
    static const Version &instance();

    const QString &version() const;
    const QString &commitHash() const;
    const QString &dateOfBuild() const;
    const QString &fullVersion() const;
    const bool &isSupportedOS() const;

private:
    Version();

    QString version_;
    QString commitHash_;
    QString dateOfBuild_;
    QString fullVersion_;
    bool isSupportedOS_;
};

};  // namespace chatterino
<|endoftext|>


<commit_before>#pragma once

#include <http_parser.h>
// #include <iostream> // TODO: remove
#include <stdexcept>
#include <string>
#include <map>
#include <sstream>
#include <deque>
#include <type_traits>
#include <functional>
#include <iterator>
#include <cassert>

namespace http {

class Request;

using Headers = std::map<std::string, std::string>;
using RequestConsumer = std::function<void(Request&&)>;

namespace detail {

template<typename ParserT>
struct Callbacks
{
	static int onMessageBegin(http_parser* p)
			{ return ((ParserT*) p->data)->onMessageBegin(); }
	static int onUrl(http_parser* p, const char *data, size_t length)
			{ return ((ParserT*) p->data)->onUrl(data, length); }
	static int onStatus(http_parser* p, const char *data, size_t length)
			{ return ((ParserT*) p->data)->onStatus(data, length); }
	static int onHeaderField(http_parser* p, const char *data, size_t length)
			{ return ((ParserT*) p->data)->onHeaderField(data, length); }
	static int onHeaderValue(http_parser* p, const char *data, size_t length)
			{ return ((ParserT*) p->data)->onHeaderValue(data, length); }
	static int onHeadersComplete(http_parser* p)
			{ return ((ParserT*) p->data)->onHeadersComplete(); }
	static int onMessageComplete(http_parser* p)
			{ return ((ParserT*) p->data)->onMessageComplete(); }
	static int onBody(http_parser* p, const char *data, size_t length)
			{ return ((ParserT*) p->data)->onBody(data, length); }
	static int onChunkHeader(http_parser* p)
			{ return ((ParserT*) p->data)->onChunkHeader(); }
	static int onChunkComplete(http_parser* p)
			{ return ((ParserT*) p->data)->onChunkComplete(); }
};

template<typename ParserT>
struct ParserSettings
{
	http_parser_settings s;

public:
	static ParserSettings& get()
	{
		static ParserSettings instance;
		return instance;
	}

	ParserSettings(const ParserSettings&) = delete;
	ParserSettings(ParserSettings&&) = delete;

private:
	ParserSettings()
	{
		http_parser_settings_init(&s);
		s.on_message_begin = &Callbacks<ParserT>::onMessageBegin;
		s.on_url = &Callbacks<ParserT>::onUrl;
		s.on_status = &Callbacks<ParserT>::onStatus;
		s.on_header_field = &Callbacks<ParserT>::onHeaderField;
		s.on_header_value = &Callbacks<ParserT>::onHeaderValue;
		s.on_headers_complete = &Callbacks<ParserT>::onHeadersComplete;
		s.on_body = &Callbacks<ParserT>::onBody;
		s.on_message_complete = &Callbacks<ParserT>::onMessageComplete;
		s.on_chunk_header = &Callbacks<ParserT>::onChunkHeader;
		s.on_chunk_complete = &Callbacks<ParserT>::onChunkComplete;
	}
};

class HeaderAssembler
{
	Headers &headers;
	std::string currentHeaderField;
	std::string currentHeaderValue;
	bool currentHeaderFieldComplete = false;

public:
	HeaderAssembler(Headers &headers): headers(headers) {}
	HeaderAssembler(const HeaderAssembler&) = delete;
	HeaderAssembler(HeaderAssembler&&) = delete;
	HeaderAssembler& operator=(const HeaderAssembler&) = delete;
	HeaderAssembler& operator=(HeaderAssembler&&) = delete;

	void reset()
	{
		currentHeaderField.clear();
		currentHeaderValue.clear();
		currentHeaderFieldComplete = false;
	}

	void onHeaderField(const char *data, std::size_t length)
	{
		if (currentHeaderFieldComplete) {
			onSingleHeaderComplete();
		}
		currentHeaderField.append(data, length);
	}

	void onHeaderValue(const char *data, std::size_t length)
	{
		currentHeaderValue.append(data, length);
		currentHeaderFieldComplete = true;
	}

	void onHeadersComplete()
	{
		onSingleHeaderComplete();
	}

private:
	void onSingleHeaderComplete()
	{
		std::string& headerValue = headers[currentHeaderField];
		if (headerValue.empty()) {
			headerValue = std::move(currentHeaderValue);
		} else if (!currentHeaderValue.empty()) {
			headerValue.reserve(1 + currentHeaderValue.size());
			headerValue.append(",");
			headerValue.append(currentHeaderValue);
		}
		currentHeaderField.clear();
		currentHeaderValue.clear();
		currentHeaderFieldComplete = false;
	}
};

} /* namespace detail */

class ParseError: public std::runtime_error
{
public:
	ParseError(const std::string& msg): std::runtime_error(msg) {}
};

template <typename IterT>
struct IsContiguousMemoryForwardIterator: std::is_pointer<IterT> {};

template <>
struct IsContiguousMemoryForwardIterator
		<typename std::vector<char>::iterator>: std::true_type {};
template <>
struct IsContiguousMemoryForwardIterator
		<typename std::vector<char>::const_iterator>: std::true_type {};

#ifdef HTTP_PARSER_CPP_IS_CONTIGUOUS_MEMORY_FORWARD_ITERATOR_EXTRA_SPECIALIZATIONS
HTTP_PARSER_CPP_IS_CONTIGUOUS_MEMORY_FORWARD_ITERATOR_EXTRA_SPECIALIZATIONS
#endif

struct Request
{
	using Type = enum http_method;
public:
	Type type = HTTP_HEAD;
	std::string url;
	std::string body;
	Headers headers;
public:
	Request() = default;
	Request(const Request&) = default;
	Request(Request&&) = default;
	Request& operator=(const Request&) = default;
	Request& operator=(Request&&) = default;
};

class Parser
{
protected:
	http_parser p;
	http_parser_settings &parserSettings;
	std::size_t totalConsumedLength;

	Parser(http_parser_type parserType, http_parser_settings &parserSettings)
		: parserSettings(parserSettings), totalConsumedLength(0)
	{
		http_parser_init(&p, parserType);
		p.data = this;
	}

	virtual ~Parser() {}

public:
	Parser(const Parser&) = delete;
	Parser& operator=(const Parser&) = delete;

	void feed(const char *input, std::size_t inputLength)
	{
		std::size_t consumedLength = http_parser_execute(
				&p, &parserSettings, input, inputLength);
		totalConsumedLength += consumedLength;
		if (consumedLength != inputLength) {
			std::ostringstream errMsg;
			errMsg << "HTTP Parse error on character "
					<< totalConsumedLength << " (character " << p.nread
					<< " in current request)";
			throw ParseError(errMsg.str().c_str());
		}
	}

	template<typename IterT>
	typename std::enable_if<std::is_same<
			typename std::iterator_traits<IterT>::value_type, char>::value>::type
	feed(IterT begin, IterT end) { feedIter(begin, end); }

	void feedEof() { (void) feed(nullptr, 0); }

private:
	template<typename IterT>
	typename std::enable_if<!IsContiguousMemoryForwardIterator<IterT>::value>::type
	feedIter(IterT begin, IterT end)
	{
		for (IterT it = begin; it != end; ++it) {
			char c = *it;
			feed(&c, 1);
		}
	}
	template<typename IterT>
	typename std::enable_if<IsContiguousMemoryForwardIterator<IterT>::value>::type
	feedIter(IterT begin, IterT end)
	{
		const char *buf = &(*begin);
		const std::size_t len = end - begin;
		feed(buf, len);
	}
};

class RequestParser: public Parser
{
	Request currentRequest;
	detail::HeaderAssembler headerAssembler;
	RequestConsumer requestConsumer;

public:
	std::deque<Request> parsedRequests;

public:
	RequestParser()
		: Parser(HTTP_REQUEST, detail::ParserSettings<RequestParser>::get().s),
			headerAssembler(currentRequest.headers) {}

	RequestParser(RequestConsumer requestConsumer)
		: Parser(HTTP_REQUEST, detail::ParserSettings<RequestParser>::get().s),
			headerAssembler(currentRequest.headers), requestConsumer(requestConsumer) {}

private:
	friend struct detail::Callbacks<RequestParser>;

	int onMessageBegin()
	{
		//std::cout << __FUNCTION__ << std::endl;
		currentRequest = Request();
		headerAssembler.reset();
		return 0;
	}

	int onUrl(const char *data, std::size_t length)
	{
		//std::cout << __FUNCTION__ << " (" << std::string(data, length) << ")" << std::endl;
		currentRequest.url.append(data, length);
		return 0;
	}

	int onStatus(const char *data, std::size_t length)
	{
		//std::cout << __FUNCTION__ << " (" << std::string(data, length) << ")" << std::endl;
		assert(false); // not reached
		return 0;
	}

	int onHeaderField(const char *data, std::size_t length)
	{
		//std::cout << __FUNCTION__ << " (" << std::string(data, length) << ")" << std::endl;
		headerAssembler.onHeaderField(data, length);
		return 0;
	}

	int onHeaderValue(const char *data, std::size_t length)
	{
		// std::cout << __FUNCTION__ << " (" << std::string(data, length) << ")" << std::endl;
		headerAssembler.onHeaderValue(data, length);
		return 0;
	}

	int onHeadersComplete()
	{
		// std::cout << __FUNCTION__ << std::endl;
		headerAssembler.onHeadersComplete();
		return 0;
	}

	int onBody(const char *data, std::size_t length)
	{
		//std::cout << __FUNCTION__ << " (" << std::string(data, length) << ")" << std::endl;
		currentRequest.body.append(data, length);
		return 0;
	}

	int onMessageComplete()
	{
		//std::cout << __FUNCTION__ << std::endl;
		currentRequest.type = static_cast<Request::Type>(p.method);
		if (requestConsumer) {
			requestConsumer(std::move(currentRequest));
		} else {
			parsedRequests.push_back(std::move(currentRequest));
		}
		return 0;
	}

	int onChunkHeader()
	{
		// std::cout << __FUNCTION__ << " (" << p.content_length << ")" << std::endl;
		// TODO
		return 0;
	}

	int onChunkComplete()
	{
		// std::cout << __FUNCTION__ << std::endl;
		// TODO
		return 0;
	}
};

} /* namespace http */

template<typename StreamT>
StreamT& operator<<(StreamT& stream, http::Request::Type reqType)
{
	stream << http_method_str(reqType);
	return stream;
}

template<typename StreamT>
StreamT& operator<<(StreamT& stream, const http::Request& req)
{
	stream << "HTTP " << req.type << " request\n"
			<< "\turl: '" << req.url << "'\n"
			<< "\theaders:\n";
	for (const auto& fvPair: req.headers) {
		stream << "\t\t'" << fvPair.first << "': '" << fvPair.second << "'\n";
	}
	stream << "\tbody is " << req.body.size() << " bytes long.";
	return stream;
}
<commit_msg>Fixed some formatting inconsistencies<commit_after>#pragma once

#include <http_parser.h>
// #include <iostream> // TODO: remove
#include <stdexcept>
#include <string>
#include <map>
#include <sstream>
#include <deque>
#include <type_traits>
#include <functional>
#include <iterator>
#include <cassert>

namespace http {

class Request;

using Headers = std::map<std::string, std::string>;
using RequestConsumer = std::function<void(Request&&)>;

namespace detail {

template<typename ParserT>
struct Callbacks
{
	static int onMessageBegin(http_parser* p)
			{ return ((ParserT*) p->data)->onMessageBegin(); }
	static int onUrl(http_parser* p, const char* data, size_t length)
			{ return ((ParserT*) p->data)->onUrl(data, length); }
	static int onStatus(http_parser* p, const char* data, size_t length)
			{ return ((ParserT*) p->data)->onStatus(data, length); }
	static int onHeaderField(http_parser* p, const char* data, size_t length)
			{ return ((ParserT*) p->data)->onHeaderField(data, length); }
	static int onHeaderValue(http_parser* p, const char* data, size_t length)
			{ return ((ParserT*) p->data)->onHeaderValue(data, length); }
	static int onHeadersComplete(http_parser* p)
			{ return ((ParserT*) p->data)->onHeadersComplete(); }
	static int onMessageComplete(http_parser* p)
			{ return ((ParserT*) p->data)->onMessageComplete(); }
	static int onBody(http_parser* p, const char* data, size_t length)
			{ return ((ParserT*) p->data)->onBody(data, length); }
	static int onChunkHeader(http_parser* p)
			{ return ((ParserT*) p->data)->onChunkHeader(); }
	static int onChunkComplete(http_parser* p)
			{ return ((ParserT*) p->data)->onChunkComplete(); }
};

template<typename ParserT>
struct ParserSettings
{
	http_parser_settings s;

public:
	static ParserSettings& get()
	{
		static ParserSettings instance;
		return instance;
	}

	ParserSettings(const ParserSettings&) = delete;
	ParserSettings(ParserSettings&&) = delete;

private:
	ParserSettings()
	{
		http_parser_settings_init(&s);
		s.on_message_begin = &Callbacks<ParserT>::onMessageBegin;
		s.on_url = &Callbacks<ParserT>::onUrl;
		s.on_status = &Callbacks<ParserT>::onStatus;
		s.on_header_field = &Callbacks<ParserT>::onHeaderField;
		s.on_header_value = &Callbacks<ParserT>::onHeaderValue;
		s.on_headers_complete = &Callbacks<ParserT>::onHeadersComplete;
		s.on_body = &Callbacks<ParserT>::onBody;
		s.on_message_complete = &Callbacks<ParserT>::onMessageComplete;
		s.on_chunk_header = &Callbacks<ParserT>::onChunkHeader;
		s.on_chunk_complete = &Callbacks<ParserT>::onChunkComplete;
	}
};

class HeaderAssembler
{
	Headers& headers;
	std::string currentHeaderField;
	std::string currentHeaderValue;
	bool currentHeaderFieldComplete = false;

public:
	HeaderAssembler(Headers& headers): headers(headers) {}
	HeaderAssembler(const HeaderAssembler&) = delete;
	HeaderAssembler(HeaderAssembler&&) = delete;
	HeaderAssembler& operator=(const HeaderAssembler&) = delete;
	HeaderAssembler& operator=(HeaderAssembler&&) = delete;

	void reset()
	{
		currentHeaderField.clear();
		currentHeaderValue.clear();
		currentHeaderFieldComplete = false;
	}

	void onHeaderField(const char* data, std::size_t length)
	{
		if (currentHeaderFieldComplete) {
			onSingleHeaderComplete();
		}
		currentHeaderField.append(data, length);
	}

	void onHeaderValue(const char* data, std::size_t length)
	{
		currentHeaderValue.append(data, length);
		currentHeaderFieldComplete = true;
	}

	void onHeadersComplete()
	{
		onSingleHeaderComplete();
	}

private:
	void onSingleHeaderComplete()
	{
		std::string& headerValue = headers[currentHeaderField];
		if (headerValue.empty()) {
			headerValue = std::move(currentHeaderValue);
		} else if (!currentHeaderValue.empty()) {
			headerValue.reserve(1 + currentHeaderValue.size());
			headerValue.append(",");
			headerValue.append(currentHeaderValue);
		}
		currentHeaderField.clear();
		currentHeaderValue.clear();
		currentHeaderFieldComplete = false;
	}
};

} /* namespace detail */

class ParseError: public std::runtime_error
{
public:
	ParseError(const std::string& msg): std::runtime_error(msg) {}
};

template <typename IterT>
struct IsContiguousMemoryForwardIterator: std::is_pointer<IterT> {};

template <>
struct IsContiguousMemoryForwardIterator
		<typename std::vector<char>::iterator>: std::true_type {};
template <>
struct IsContiguousMemoryForwardIterator
		<typename std::vector<char>::const_iterator>: std::true_type {};

#ifdef HTTP_PARSER_CPP_IS_CONTIGUOUS_MEMORY_FORWARD_ITERATOR_EXTRA_SPECIALIZATIONS
HTTP_PARSER_CPP_IS_CONTIGUOUS_MEMORY_FORWARD_ITERATOR_EXTRA_SPECIALIZATIONS
#endif

struct Request
{
	using Type = enum http_method;
public:
	Type type = HTTP_HEAD;
	std::string url;
	std::string body;
	Headers headers;
public:
	Request() = default;
	Request(const Request&) = default;
	Request(Request&&) = default;
	Request& operator=(const Request&) = default;
	Request& operator=(Request&&) = default;
};

class Parser
{
protected:
	http_parser p;
	http_parser_settings& parserSettings;
	std::size_t totalConsumedLength;

	Parser(http_parser_type parserType, http_parser_settings& parserSettings)
		: parserSettings(parserSettings), totalConsumedLength(0)
	{
		http_parser_init(&p, parserType);
		p.data = this;
	}

	virtual ~Parser() {}

public:
	Parser(const Parser&) = delete;
	Parser& operator=(const Parser&) = delete;

	void feed(const char* input, std::size_t inputLength)
	{
		std::size_t consumedLength = http_parser_execute(
				&p, &parserSettings, input, inputLength);
		totalConsumedLength += consumedLength;
		if (consumedLength != inputLength) {
			std::ostringstream errMsg;
			errMsg << "HTTP Parse error on character "
					<< totalConsumedLength << " (character " << p.nread
					<< " in current request)";
			throw ParseError(errMsg.str().c_str());
		}
	}

	template<typename IterT>
	typename std::enable_if<std::is_same<
			typename std::iterator_traits<IterT>::value_type, char>::value>::type
	feed(IterT begin, IterT end) { feedIter(begin, end); }

	void feedEof() { (void) feed(nullptr, 0); }

private:
	template<typename IterT>
	typename std::enable_if<!IsContiguousMemoryForwardIterator<IterT>::value>::type
	feedIter(IterT begin, IterT end)
	{
		for (IterT it = begin; it != end; ++it) {
			char c = *it;
			feed(&c, 1);
		}
	}
	template<typename IterT>
	typename std::enable_if<IsContiguousMemoryForwardIterator<IterT>::value>::type
	feedIter(IterT begin, IterT end)
	{
		const char *buf = &(*begin);
		const std::size_t len = end - begin;
		feed(buf, len);
	}
};

class RequestParser: public Parser
{
	Request currentRequest;
	detail::HeaderAssembler headerAssembler;
	RequestConsumer requestConsumer;

public:
	std::deque<Request> parsedRequests;

public:
	RequestParser()
		: Parser(HTTP_REQUEST, detail::ParserSettings<RequestParser>::get().s),
			headerAssembler(currentRequest.headers) {}

	RequestParser(RequestConsumer requestConsumer)
		: Parser(HTTP_REQUEST, detail::ParserSettings<RequestParser>::get().s),
			headerAssembler(currentRequest.headers), requestConsumer(requestConsumer) {}

private:
	friend struct detail::Callbacks<RequestParser>;

	int onMessageBegin()
	{
		//std::cout << __FUNCTION__ << std::endl;
		currentRequest = Request();
		headerAssembler.reset();
		return 0;
	}

	int onUrl(const char* data, std::size_t length)
	{
		//std::cout << __FUNCTION__ << " (" << std::string(data, length) << ")" << std::endl;
		currentRequest.url.append(data, length);
		return 0;
	}

	int onStatus(const char* data, std::size_t length)
	{
		//std::cout << __FUNCTION__ << " (" << std::string(data, length) << ")" << std::endl;
		assert(false); // not reached
		return 0;
	}

	int onHeaderField(const char* data, std::size_t length)
	{
		//std::cout << __FUNCTION__ << " (" << std::string(data, length) << ")" << std::endl;
		headerAssembler.onHeaderField(data, length);
		return 0;
	}

	int onHeaderValue(const char* data, std::size_t length)
	{
		// std::cout << __FUNCTION__ << " (" << std::string(data, length) << ")" << std::endl;
		headerAssembler.onHeaderValue(data, length);
		return 0;
	}

	int onHeadersComplete()
	{
		// std::cout << __FUNCTION__ << std::endl;
		headerAssembler.onHeadersComplete();
		return 0;
	}

	int onBody(const char* data, std::size_t length)
	{
		//std::cout << __FUNCTION__ << " (" << std::string(data, length) << ")" << std::endl;
		currentRequest.body.append(data, length);
		return 0;
	}

	int onMessageComplete()
	{
		//std::cout << __FUNCTION__ << std::endl;
		currentRequest.type = static_cast<Request::Type>(p.method);
		if (requestConsumer) {
			requestConsumer(std::move(currentRequest));
		} else {
			parsedRequests.push_back(std::move(currentRequest));
		}
		return 0;
	}

	int onChunkHeader()
	{
		// std::cout << __FUNCTION__ << " (" << p.content_length << ")" << std::endl;
		// TODO
		return 0;
	}

	int onChunkComplete()
	{
		// std::cout << __FUNCTION__ << std::endl;
		// TODO
		return 0;
	}
};

} /* namespace http */

template<typename StreamT>
StreamT& operator<<(StreamT& stream, http::Request::Type reqType)
{
	stream << http_method_str(reqType);
	return stream;
}

template<typename StreamT>
StreamT& operator<<(StreamT& stream, const http::Request& req)
{
	stream << "HTTP " << req.type << " request\n"
			<< "\turl: '" << req.url << "'\n"
			<< "\theaders:\n";
	for (const auto& fvPair: req.headers) {
		stream << "\t\t'" << fvPair.first << "': '" << fvPair.second << "'\n";
	}
	stream << "\tbody is " << req.body.size() << " bytes long.";
	return stream;
}
<|endoftext|>


<commit_before>#include <dropwhile.hpp>

#include <vector>
#include <iostream>

using iter::dropwhile;

int main() {
    std::vector<int> ivec{1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4};
    for (auto i : dropwhile([] (int i) {return i < 5;}, ivec)) {
        std::cout << i << '\n';
    }
    return 0;
}
<commit_msg>Adds test with temporary<commit_after>#include <dropwhile.hpp>
#include <range.hpp>

#include <vector>
#include <iostream>

using iter::dropwhile;
using iter::range;

int main() {
    std::vector<int> ivec{1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4};
    for (auto i : dropwhile([] (int i) {return i < 5;}, ivec)) {
        std::cout << i << '\n';
    }

    for (auto i : dropwhile([] (int i) {return i < 5;}, range(10))) {
        std::cout << i << '\n';
    }
    return 0;
}
<|endoftext|>


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

#include "base/file_util.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/process_util.h"
#include "base/shared_memory.h"
#include "base/string16.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_version_info.h"
#include "chrome/common/service_process_util.h"
#include "chrome/installer/util/version.h"

#if defined(OS_WIN)
#include "base/object_watcher.h"
#include "base/scoped_handle_win.h"
#endif

// TODO(hclam): Split this file for different platforms.

namespace {

// This should be more than enough to hold a version string assuming each part
// of the version string is an int64.
const uint32 kMaxVersionStringLength = 256;

// The structure that gets written to shared memory.
struct ServiceProcessSharedData {
  char service_process_version[kMaxVersionStringLength];
  base::ProcessId service_process_pid;
};

// Return a name that is scoped to this instance of the service process. We
// use the user-data-dir as a scoping prefix.
std::string GetServiceProcessScopedName(const std::string& append_str) {
  FilePath user_data_dir;
  PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
#if defined(OS_WIN)
  std::string scoped_name = WideToUTF8(user_data_dir.value());
#elif defined(OS_POSIX)
  std::string scoped_name = user_data_dir.value();
#endif  // defined(OS_WIN)
  std::replace(scoped_name.begin(), scoped_name.end(), '\\', '!');
  scoped_name.append(append_str);
  return scoped_name;
}

// Return a name that is scoped to this instance of the service process. We
// use the user-data-dir and the version as a scoping prefix.
std::string GetServiceProcessScopedVersionedName(
    const std::string& append_str) {
  std::string versioned_str;
  chrome::VersionInfo version_info;
  DCHECK(version_info.is_valid());
  versioned_str.append(version_info.Version());
  versioned_str.append(append_str);
  return GetServiceProcessScopedName(versioned_str);
}

// Gets the name of the shared memory used by the service process to write its
// version. The name is not versioned.
std::string GetServiceProcessSharedMemName() {
  return GetServiceProcessScopedName("_service_shmem");
}

// Reads the named shared memory to get the shared data. Returns false if no
// matching shared memory was found.
bool GetServiceProcessSharedData(std::string* version, base::ProcessId* pid) {
  scoped_ptr<base::SharedMemory> shared_mem_service_data;
  shared_mem_service_data.reset(new base::SharedMemory());
  ServiceProcessSharedData* service_data = NULL;
  if (shared_mem_service_data.get() &&
      shared_mem_service_data->Open(GetServiceProcessSharedMemName(), true) &&
      shared_mem_service_data->Map(sizeof(ServiceProcessSharedData))) {
    service_data = reinterpret_cast<ServiceProcessSharedData*>(
        shared_mem_service_data->memory());
    // Make sure the version in shared memory is null-terminated. If it is not,
    // treat it as invalid.
    if (version && memchr(service_data->service_process_version, '\0',
                          sizeof(service_data->service_process_version)))
      *version = service_data->service_process_version;
    if (pid)
      *pid = service_data->service_process_pid;
    return true;
  }
  return false;
}

enum ServiceProcessRunningState {
  SERVICE_NOT_RUNNING,
  SERVICE_OLDER_VERSION_RUNNING,
  SERVICE_SAME_VERSION_RUNNING,
  SERVICE_NEWER_VERSION_RUNNING,
};

ServiceProcessRunningState GetServiceProcessRunningState(
    std::string* service_version_out) {
  std::string version;
  GetServiceProcessSharedData(&version, NULL);
  if (version.empty())
    return SERVICE_NOT_RUNNING;

  // At this time we have a version string. Set the out param if it exists.
  if (service_version_out)
    *service_version_out = version;

  scoped_ptr<installer::Version> service_version;
  service_version.reset(
      installer::Version::GetVersionFromString(ASCIIToUTF16(version)));
  // If the version string is invalid, treat it like an older version.
  if (!service_version.get())
    return SERVICE_OLDER_VERSION_RUNNING;

  // Get the version of the currently *running* instance of Chrome.
  chrome::VersionInfo version_info;
  if (!version_info.is_valid()) {
    NOTREACHED() << "Failed to get current file version";
    // Our own version is invalid. This is an error case. Pretend that we
    // are out of date.
    return SERVICE_NEWER_VERSION_RUNNING;
  }
  scoped_ptr<installer::Version> running_version(
      installer::Version::GetVersionFromString(
          ASCIIToUTF16(version_info.Version())));
  if (!running_version.get()) {
    NOTREACHED() << "Failed to parse version info";
    // Our own version is invalid. This is an error case. Pretend that we
    // are out of date.
    return SERVICE_NEWER_VERSION_RUNNING;
  }

  if (running_version->IsHigherThan(service_version.get())) {
    return SERVICE_OLDER_VERSION_RUNNING;
  } else if (service_version->IsHigherThan(running_version.get())) {
    return SERVICE_NEWER_VERSION_RUNNING;
  }
  return SERVICE_SAME_VERSION_RUNNING;
}

#if defined(OS_WIN)
string16 GetServiceProcessReadyEventName() {
  return UTF8ToWide(
      GetServiceProcessScopedVersionedName("_service_ready"));
}

string16 GetServiceProcessShutdownEventName() {
  return UTF8ToWide(
      GetServiceProcessScopedVersionedName("_service_shutdown_evt"));
}

class ServiceProcessShutdownMonitor : public base::ObjectWatcher::Delegate {
 public:
  explicit ServiceProcessShutdownMonitor(Task* shutdown_task)
      : shutdown_task_(shutdown_task) {
  }
  void Start() {
    string16 event_name = GetServiceProcessShutdownEventName();
    CHECK(event_name.length() <= MAX_PATH);
    shutdown_event_.Set(CreateEvent(NULL, TRUE, FALSE, event_name.c_str()));
    watcher_.StartWatching(shutdown_event_.Get(), this);
  }

  // base::ObjectWatcher::Delegate implementation.
  virtual void OnObjectSignaled(HANDLE object) {
    shutdown_task_->Run();
    shutdown_task_.reset();
  }

 private:
  ScopedHandle shutdown_event_;
  base::ObjectWatcher watcher_;
  scoped_ptr<Task> shutdown_task_;
};
#else  // defined(OS_WIN)
// Gets the name of the lock file for service process. Used on non-Windows OSes.
FilePath GetServiceProcessLockFilePath() {
  FilePath user_data_dir;
  PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
  chrome::VersionInfo version_info;
  std::string lock_file_name = version_info.Version() + "Service Process Lock";
  return user_data_dir.Append(lock_file_name);
}
#endif  // defined(OS_WIN)

struct ServiceProcessGlobalState {
  scoped_ptr<base::SharedMemory> shared_mem_service_data;
#if defined(OS_WIN)
  // An event that is signaled when a service process is ready.
  ScopedHandle ready_event;
  scoped_ptr<ServiceProcessShutdownMonitor> shutdown_monitor;
#endif  // defined(OS_WIN)
};

// TODO(sanjeevr): Remove this ugly global pointer and move all methods and
// data members used by the service process into one singleton class which
// could be owned by the service process.
ServiceProcessGlobalState* g_service_globals = NULL;

}  // namespace

// Gets the name of the service process IPC channel.
std::string GetServiceProcessChannelName() {
  return GetServiceProcessScopedVersionedName("_service_ipc");
}

std::string GetServiceProcessAutoRunKey() {
  return GetServiceProcessScopedName("_service_run");
}

bool TakeServiceProcessSingletonLock() {
  DCHECK(g_service_globals == NULL);
  std::string running_version;
  ServiceProcessRunningState state =
      GetServiceProcessRunningState(&running_version);
  switch (state) {
    case SERVICE_SAME_VERSION_RUNNING:
    case SERVICE_NEWER_VERSION_RUNNING:
      return false;
    case SERVICE_OLDER_VERSION_RUNNING:
      // If an older version is running, kill it.
      ForceServiceProcessShutdown(running_version);
      break;
    case SERVICE_NOT_RUNNING:
      break;
  }
  g_service_globals = new ServiceProcessGlobalState;
  // TODO(sanjeevr): We can probably use the shared mem as the sole singleton
  // mechanism. For that the shared mem class needs to return whether it created
  // new instance or opened an existing one.
#if defined(OS_WIN)
  string16 event_name = GetServiceProcessReadyEventName();
  CHECK(event_name.length() <= MAX_PATH);
  ScopedHandle service_process_ready_event;
  service_process_ready_event.Set(
      CreateEvent(NULL, TRUE, FALSE, event_name.c_str()));
  DWORD error = GetLastError();
  if ((error == ERROR_ALREADY_EXISTS) || (error == ERROR_ACCESS_DENIED)) {
    delete g_service_globals;
    g_service_globals = NULL;
    return false;
  }
  DCHECK(service_process_ready_event.IsValid());
  g_service_globals->ready_event.Set(service_process_ready_event.Take());
#else
  // TODO(sanjeevr): Implement singleton mechanism for other platforms.
  NOTIMPLEMENTED();
#endif
  // Now that we have the singleton, let is also write the version we are using
  // to shared memory. This can be used by a newer service to signal us to exit.
  chrome::VersionInfo version_info;
  if (!version_info.is_valid()) {
    NOTREACHED() << "Failed to get current file version";
    return false;
  }
  if (version_info.Version().length() >= kMaxVersionStringLength) {
    NOTREACHED() << "Version string length is << " <<
        version_info.Version().length() << "which is longer than" <<
        kMaxVersionStringLength;
    return false;
  }

  scoped_ptr<base::SharedMemory> shared_mem_service_data;
  shared_mem_service_data.reset(new base::SharedMemory());
  if (!shared_mem_service_data.get())
    return false;

  uint32 alloc_size = sizeof(ServiceProcessSharedData);
  if (!shared_mem_service_data->Create(GetServiceProcessSharedMemName(), false,
                                       true, alloc_size))
    return false;

  if (!shared_mem_service_data->Map(alloc_size))
    return false;

  memset(shared_mem_service_data->memory(), 0, alloc_size);
  ServiceProcessSharedData* shared_data =
      reinterpret_cast<ServiceProcessSharedData*>(
          shared_mem_service_data->memory());
  memcpy(shared_data->service_process_version, version_info.Version().c_str(),
         version_info.Version().length());
  shared_data->service_process_pid = base::GetCurrentProcId();
  g_service_globals->shared_mem_service_data.reset(
      shared_mem_service_data.release());
  return true;
}

void SignalServiceProcessReady(Task* shutdown_task) {
#if defined(OS_WIN)
  DCHECK(g_service_globals != NULL);
  DCHECK(g_service_globals->ready_event.IsValid());
  SetEvent(g_service_globals->ready_event.Get());
  g_service_globals->shutdown_monitor.reset(
      new ServiceProcessShutdownMonitor(shutdown_task));
  g_service_globals->shutdown_monitor->Start();
#else
  // TODO(hclam): Implement better mechanism for these platform.
  // Also we need to save shutdown task. For now we just delete the shutdown
  // task because we have not way to listen for shutdown requests.
  delete shutdown_task;
  const FilePath path = GetServiceProcessLockFilePath();
  FILE* file = file_util::OpenFile(path, "wb+");
  if (!file)
    return;
  LOG(INFO) << "Created Service Process lock file: " << path.value();
  file_util::TruncateFile(file) && file_util::CloseFile(file);
#endif
}

void SignalServiceProcessStopped() {
  delete g_service_globals;
  g_service_globals = NULL;
#if !defined(OS_WIN)
  // TODO(hclam): Implement better mechanism for these platform.
  const FilePath path = GetServiceProcessLockFilePath();
  file_util::Delete(path, false);
#endif
}

bool ForceServiceProcessShutdown(const std::string& version) {
#if defined(OS_WIN)
  ScopedHandle shutdown_event;
  std::string versioned_name = version;
  versioned_name.append("_service_shutdown_evt");
  string16 event_name =
      UTF8ToWide(GetServiceProcessScopedName(versioned_name));
  shutdown_event.Set(OpenEvent(EVENT_MODIFY_STATE, FALSE, event_name.c_str()));
  if (!shutdown_event.IsValid())
    return false;
  SetEvent(shutdown_event.Get());
  return true;
#else  // defined(OS_WIN)
  NOTIMPLEMENTED();
  return false;
#endif    // defined(OS_WIN)
}

bool CheckServiceProcessReady() {
#if defined(OS_WIN)
  string16 event_name = GetServiceProcessReadyEventName();
  ScopedHandle event(
      OpenEvent(SYNCHRONIZE | READ_CONTROL, false, event_name.c_str()));
  if (!event.IsValid())
    return false;
  // Check if the event is signaled.
  return WaitForSingleObject(event, 0) == WAIT_OBJECT_0;
#else
  // TODO(hclam): Implement better mechanism for these platform.
  const FilePath path = GetServiceProcessLockFilePath();
  return file_util::PathExists(path);
#endif
}

base::ProcessId GetServiceProcessPid() {
  base::ProcessId pid = 0;
  GetServiceProcessSharedData(NULL, &pid);
  return pid;
}

<commit_msg>Fix service for CUPS CP proxy.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/file_util.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/process_util.h"
#include "base/shared_memory.h"
#include "base/string16.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_version_info.h"
#include "chrome/common/service_process_util.h"
#include "chrome/installer/util/version.h"

#if defined(OS_WIN)
#include "base/object_watcher.h"
#include "base/scoped_handle_win.h"
#endif

// TODO(hclam): Split this file for different platforms.

namespace {

// This should be more than enough to hold a version string assuming each part
// of the version string is an int64.
const uint32 kMaxVersionStringLength = 256;

// The structure that gets written to shared memory.
struct ServiceProcessSharedData {
  char service_process_version[kMaxVersionStringLength];
  base::ProcessId service_process_pid;
};

// Return a name that is scoped to this instance of the service process. We
// use the user-data-dir as a scoping prefix.
std::string GetServiceProcessScopedName(const std::string& append_str) {
  FilePath user_data_dir;
  PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
#if defined(OS_WIN)
  std::string scoped_name = WideToUTF8(user_data_dir.value());
#elif defined(OS_POSIX)
  std::string scoped_name = user_data_dir.value();
#endif  // defined(OS_WIN)
  std::replace(scoped_name.begin(), scoped_name.end(), '\\', '!');
  std::replace(scoped_name.begin(), scoped_name.end(), '/', '!');
  scoped_name.append(append_str);
  return scoped_name;
}

// Return a name that is scoped to this instance of the service process. We
// use the user-data-dir and the version as a scoping prefix.
std::string GetServiceProcessScopedVersionedName(
    const std::string& append_str) {
  std::string versioned_str;
  chrome::VersionInfo version_info;
  DCHECK(version_info.is_valid());
  versioned_str.append(version_info.Version());
  versioned_str.append(append_str);
  return GetServiceProcessScopedName(versioned_str);
}

// Gets the name of the shared memory used by the service process to write its
// version. The name is not versioned.
std::string GetServiceProcessSharedMemName() {
  return GetServiceProcessScopedName("_service_shmem");
}

// Reads the named shared memory to get the shared data. Returns false if no
// matching shared memory was found.
bool GetServiceProcessSharedData(std::string* version, base::ProcessId* pid) {
  scoped_ptr<base::SharedMemory> shared_mem_service_data;
  shared_mem_service_data.reset(new base::SharedMemory());
  ServiceProcessSharedData* service_data = NULL;
  if (shared_mem_service_data.get() &&
      shared_mem_service_data->Open(GetServiceProcessSharedMemName(), true) &&
      shared_mem_service_data->Map(sizeof(ServiceProcessSharedData))) {
    service_data = reinterpret_cast<ServiceProcessSharedData*>(
        shared_mem_service_data->memory());
    // Make sure the version in shared memory is null-terminated. If it is not,
    // treat it as invalid.
    if (version && memchr(service_data->service_process_version, '\0',
                          sizeof(service_data->service_process_version)))
      *version = service_data->service_process_version;
    if (pid)
      *pid = service_data->service_process_pid;
    return true;
  }
  return false;
}

enum ServiceProcessRunningState {
  SERVICE_NOT_RUNNING,
  SERVICE_OLDER_VERSION_RUNNING,
  SERVICE_SAME_VERSION_RUNNING,
  SERVICE_NEWER_VERSION_RUNNING,
};

ServiceProcessRunningState GetServiceProcessRunningState(
    std::string* service_version_out) {
  std::string version;
  GetServiceProcessSharedData(&version, NULL);
  if (version.empty())
    return SERVICE_NOT_RUNNING;

  // At this time we have a version string. Set the out param if it exists.
  if (service_version_out)
    *service_version_out = version;

  scoped_ptr<installer::Version> service_version;
  service_version.reset(
      installer::Version::GetVersionFromString(ASCIIToUTF16(version)));
  // If the version string is invalid, treat it like an older version.
  if (!service_version.get())
    return SERVICE_OLDER_VERSION_RUNNING;

  // Get the version of the currently *running* instance of Chrome.
  chrome::VersionInfo version_info;
  if (!version_info.is_valid()) {
    NOTREACHED() << "Failed to get current file version";
    // Our own version is invalid. This is an error case. Pretend that we
    // are out of date.
    return SERVICE_NEWER_VERSION_RUNNING;
  }
  scoped_ptr<installer::Version> running_version(
      installer::Version::GetVersionFromString(
          ASCIIToUTF16(version_info.Version())));
  if (!running_version.get()) {
    NOTREACHED() << "Failed to parse version info";
    // Our own version is invalid. This is an error case. Pretend that we
    // are out of date.
    return SERVICE_NEWER_VERSION_RUNNING;
  }

  if (running_version->IsHigherThan(service_version.get())) {
    return SERVICE_OLDER_VERSION_RUNNING;
  } else if (service_version->IsHigherThan(running_version.get())) {
    return SERVICE_NEWER_VERSION_RUNNING;
  }
  return SERVICE_SAME_VERSION_RUNNING;
}

#if defined(OS_WIN)
string16 GetServiceProcessReadyEventName() {
  return UTF8ToWide(
      GetServiceProcessScopedVersionedName("_service_ready"));
}

string16 GetServiceProcessShutdownEventName() {
  return UTF8ToWide(
      GetServiceProcessScopedVersionedName("_service_shutdown_evt"));
}

class ServiceProcessShutdownMonitor : public base::ObjectWatcher::Delegate {
 public:
  explicit ServiceProcessShutdownMonitor(Task* shutdown_task)
      : shutdown_task_(shutdown_task) {
  }
  void Start() {
    string16 event_name = GetServiceProcessShutdownEventName();
    CHECK(event_name.length() <= MAX_PATH);
    shutdown_event_.Set(CreateEvent(NULL, TRUE, FALSE, event_name.c_str()));
    watcher_.StartWatching(shutdown_event_.Get(), this);
  }

  // base::ObjectWatcher::Delegate implementation.
  virtual void OnObjectSignaled(HANDLE object) {
    shutdown_task_->Run();
    shutdown_task_.reset();
  }

 private:
  ScopedHandle shutdown_event_;
  base::ObjectWatcher watcher_;
  scoped_ptr<Task> shutdown_task_;
};
#else  // defined(OS_WIN)
// Gets the name of the lock file for service process. Used on non-Windows OSes.
FilePath GetServiceProcessLockFilePath() {
  FilePath user_data_dir;
  PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
  chrome::VersionInfo version_info;
  std::string lock_file_name = version_info.Version() + "Service Process Lock";
  return user_data_dir.Append(lock_file_name);
}
#endif  // defined(OS_WIN)

struct ServiceProcessGlobalState {
  scoped_ptr<base::SharedMemory> shared_mem_service_data;
#if defined(OS_WIN)
  // An event that is signaled when a service process is ready.
  ScopedHandle ready_event;
  scoped_ptr<ServiceProcessShutdownMonitor> shutdown_monitor;
#endif  // defined(OS_WIN)
};

// TODO(sanjeevr): Remove this ugly global pointer and move all methods and
// data members used by the service process into one singleton class which
// could be owned by the service process.
ServiceProcessGlobalState* g_service_globals = NULL;

}  // namespace

// Gets the name of the service process IPC channel.
std::string GetServiceProcessChannelName() {
  return GetServiceProcessScopedVersionedName("_service_ipc");
}

std::string GetServiceProcessAutoRunKey() {
  return GetServiceProcessScopedName("_service_run");
}

bool TakeServiceProcessSingletonLock() {
  DCHECK(g_service_globals == NULL);
  // On Linux shared menory is implemented using file. In case of incorrect
  // shutdown or process kill memshared file stay on the disk and prevents
  // next instance of service from starting. So, on Linux we have to disable
  // check for another running instance of the service.
#if defined(OS_WIN)
  std::string running_version;
  ServiceProcessRunningState state =
      GetServiceProcessRunningState(&running_version);
  switch (state) {
    case SERVICE_SAME_VERSION_RUNNING:
    case SERVICE_NEWER_VERSION_RUNNING:
      return false;
    case SERVICE_OLDER_VERSION_RUNNING:
      // If an older version is running, kill it.
      ForceServiceProcessShutdown(running_version);
      break;
    case SERVICE_NOT_RUNNING:
      break;
  }
#endif
  g_service_globals = new ServiceProcessGlobalState;
  // TODO(sanjeevr): We can probably use the shared mem as the sole singleton
  // mechanism. For that the shared mem class needs to return whether it created
  // new instance or opened an existing one.
#if defined(OS_WIN)
  string16 event_name = GetServiceProcessReadyEventName();
  CHECK(event_name.length() <= MAX_PATH);
  ScopedHandle service_process_ready_event;
  service_process_ready_event.Set(
      CreateEvent(NULL, TRUE, FALSE, event_name.c_str()));
  DWORD error = GetLastError();
  if ((error == ERROR_ALREADY_EXISTS) || (error == ERROR_ACCESS_DENIED)) {
    delete g_service_globals;
    g_service_globals = NULL;
    return false;
  }
  DCHECK(service_process_ready_event.IsValid());
  g_service_globals->ready_event.Set(service_process_ready_event.Take());
#else
  // TODO(sanjeevr): Implement singleton mechanism for other platforms.
  NOTIMPLEMENTED();
#endif
  // Now that we have the singleton, let is also write the version we are using
  // to shared memory. This can be used by a newer service to signal us to exit.
  chrome::VersionInfo version_info;
  if (!version_info.is_valid()) {
    NOTREACHED() << "Failed to get current file version";
    return false;
  }
  if (version_info.Version().length() >= kMaxVersionStringLength) {
    NOTREACHED() << "Version string length is << " <<
        version_info.Version().length() << "which is longer than" <<
        kMaxVersionStringLength;
    return false;
  }

  scoped_ptr<base::SharedMemory> shared_mem_service_data;
  shared_mem_service_data.reset(new base::SharedMemory());
  if (!shared_mem_service_data.get())
    return false;

  uint32 alloc_size = sizeof(ServiceProcessSharedData);
  if (!shared_mem_service_data->Create(GetServiceProcessSharedMemName(), false,
                                       true, alloc_size))
    return false;

  if (!shared_mem_service_data->Map(alloc_size))
    return false;

  memset(shared_mem_service_data->memory(), 0, alloc_size);
  ServiceProcessSharedData* shared_data =
      reinterpret_cast<ServiceProcessSharedData*>(
          shared_mem_service_data->memory());
  memcpy(shared_data->service_process_version, version_info.Version().c_str(),
         version_info.Version().length());
  shared_data->service_process_pid = base::GetCurrentProcId();
  g_service_globals->shared_mem_service_data.reset(
      shared_mem_service_data.release());
  return true;
}

void SignalServiceProcessReady(Task* shutdown_task) {
#if defined(OS_WIN)
  DCHECK(g_service_globals != NULL);
  DCHECK(g_service_globals->ready_event.IsValid());
  SetEvent(g_service_globals->ready_event.Get());
  g_service_globals->shutdown_monitor.reset(
      new ServiceProcessShutdownMonitor(shutdown_task));
  g_service_globals->shutdown_monitor->Start();
#else
  // TODO(hclam): Implement better mechanism for these platform.
  // Also we need to save shutdown task. For now we just delete the shutdown
  // task because we have not way to listen for shutdown requests.
  delete shutdown_task;
  const FilePath path = GetServiceProcessLockFilePath();
  FILE* file = file_util::OpenFile(path, "wb+");
  if (!file)
    return;
  LOG(INFO) << "Created Service Process lock file: " << path.value();
  file_util::TruncateFile(file) && file_util::CloseFile(file);
#endif
}

void SignalServiceProcessStopped() {
  delete g_service_globals;
  g_service_globals = NULL;
#if !defined(OS_WIN)
  // TODO(hclam): Implement better mechanism for these platform.
  const FilePath path = GetServiceProcessLockFilePath();
  file_util::Delete(path, false);
#endif
}

bool ForceServiceProcessShutdown(const std::string& version) {
#if defined(OS_WIN)
  ScopedHandle shutdown_event;
  std::string versioned_name = version;
  versioned_name.append("_service_shutdown_evt");
  string16 event_name =
      UTF8ToWide(GetServiceProcessScopedName(versioned_name));
  shutdown_event.Set(OpenEvent(EVENT_MODIFY_STATE, FALSE, event_name.c_str()));
  if (!shutdown_event.IsValid())
    return false;
  SetEvent(shutdown_event.Get());
  return true;
#else  // defined(OS_WIN)
  NOTIMPLEMENTED();
  return false;
#endif    // defined(OS_WIN)
}

bool CheckServiceProcessReady() {
#if defined(OS_WIN)
  string16 event_name = GetServiceProcessReadyEventName();
  ScopedHandle event(
      OpenEvent(SYNCHRONIZE | READ_CONTROL, false, event_name.c_str()));
  if (!event.IsValid())
    return false;
  // Check if the event is signaled.
  return WaitForSingleObject(event, 0) == WAIT_OBJECT_0;
#else
  // TODO(hclam): Implement better mechanism for these platform.
  const FilePath path = GetServiceProcessLockFilePath();
  return file_util::PathExists(path);
#endif
}

base::ProcessId GetServiceProcessPid() {
  base::ProcessId pid = 0;
  GetServiceProcessSharedData(NULL, &pid);
  return pid;
}

<|endoftext|>