<commit_before>// Jubatus: Online machine learning framework for distributed environment
// Copyright (C) 2011,2012 Preferred Infrastructure and Nippon Telegraph and Telephone Corporation.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

#include "graph_serv.hpp"
#include "graph_types.hpp"

#include "../graph/graph_factory.hpp"
#include "../common/util.hpp"
#include "../common/membership.hpp"

#include "../framework/aggregators.hpp"

#include <pficommon/lang/cast.h>
#include <sstream>

#include <pficommon/system/time_util.h>
using pfi::system::time::clock_time;
using pfi::system::time::get_clock_time;

namespace jubatus { namespace server {

inline node_id uint642nodeid(uint64_t i){
  return pfi::lang::lexical_cast<node_id, uint64_t>(i);
}
inline uint64_t nodeid2uint64(const node_id& id)
{
  return pfi::lang::lexical_cast<uint64_t, node_id>(id);
}

inline node_id i2n(uint64_t i){
  return uint642nodeid(i);
}
inline uint64_t n2i(const node_id& id){
  return nodeid2uint64(id);
}

graph_serv::graph_serv(const framework::server_argv& a)
  : jubatus_serv(a)
{
  common::cshared_ptr<jubatus::graph::graph_base>
    g(jubatus::graph::create_graph("graph_wo_index"));
  g_.set_model(g);
  register_mixable(mixable_cast(&g_));
}
graph_serv::~graph_serv()
{}

std::string graph_serv::create_node(){
  uint64_t nid = idgen_.generate();
  std::string nid_str = pfi::lang::lexical_cast<std::string>(nid);
  // send true create_global_node to other machines.

  if(not a_.is_standalone()){
    // TODO: we need global locking
    {
      common::cht ht(zk_, a_.name);
      std::vector<std::pair<std::string, int> > nodes;
      ht.find(nid_str, nodes, 2); //replication number of local_node
      if(nodes.empty()){
        throw std::runtime_error("fatal: no server found in cht: "+nid_str);
      }

      if(nodes[0].first == a_.eth && nodes[0].second == a_.port){
        create_node_here(nid_str);
      }else{
        pfi::network::mprpc::rpc_client c(nodes[0].first, nodes[0].second, 5.0);
        pfi::lang::function<int(std::string)> f = c.call<int(std::string)>("craete_node_here");
        f(nid_str);
      }
      for(size_t i = 1; i < nodes.size(); ++i){
        try{
          if(nodes[i].first == a_.eth && nodes[i].second == a_.port){
            create_node_here(nid_str);
          }else{
            pfi::network::mprpc::rpc_client c(nodes[i].first, nodes[i].second, 5.0);
            pfi::lang::function<int(std::string)> f = c.call<int(std::string)>("craete_node_here");
            f(nid_str);
          }
        }catch(const std::runtime_error& e){
          LOG(INFO) << i << "th replica: " << nodes[i].first << ":" << nodes[i].second << " " << e.what();
        }
      }

    }
    std::vector<std::pair<std::string, int> > members;
    get_members(members);
    if(not members.empty()){
      common::mprpc::rpc_mclient c(members, a_.timeout); //create global node
      c.call_async("create_global_node", a_.name, nid_str);
      c.join_all<int>(pfi::lang::function<int(int,int)>(&jubatus::framework::add<int>));
    }
  }else{
    create_node_here(nid_str);
  }
  //DLOG(INFO) << "new node created: " << nid_str;
  return nid_str;
}

int graph_serv::update_node(const std::string& id, const property& p)
{

  g_.get_model()->update_node(n2i(id), p);
  return 0;
}

int graph_serv::remove_node(const std::string& nid){
  g_.get_model()->remove_node(n2i(nid));
  g_.get_model()->remove_global_node(n2i(nid));

  if(not a_.is_standalone()){
  // TODO: we need global locking
  // send true remove_node_ to other machine,
    std::vector<std::pair<std::string, int> > members;
    get_members(members);

    if(not members.empty()){
      common::mprpc::rpc_mclient c(members, a_.timeout); //create global node
      c.call_async("remove_global_node", a_.name, nid);
      c.join_all<int>(pfi::lang::function<int(int,int)>(&jubatus::framework::add<int>));
    }
  }
  DLOG(INFO) << "node removed: " << nid;
  return 0;
}

  //@cht
int graph_serv::create_edge(const std::string& id, const edge_info& ei)
{
  edge_id_t eid = idgen_.generate();
  g_.get_model()->create_edge(eid, n2i(ei.src), n2i(ei.tgt));
  g_.get_model()->update_edge(eid, ei.p);
  // DLOG(INFO) << "edge created (" << eid << ") " << ei.src << " => " << ei.tgt;
  return eid;
}

  //@random
int graph_serv::update_edge(const std::string&, edge_id_t eid, const edge_info& ei)
{
  g_.get_model()->update_edge(eid, ei.p);
  return 0;
}

int graph_serv::remove_edge(const std::string&, const edge_id_t& id){
  g_.get_model()->remove_edge(id);
  return 0;
}

//@random
double graph_serv::centrality(const std::string& id, const centrality_type& s,
			      const preset_query& q) const
{
  if(s == 0){
    jubatus::graph::preset_query q0;
    return g_.get_model()->centrality(n2i(id),
				      jubatus::graph::EIGENSCORE,
				      q0);
  }else{
    std::stringstream msg;
    msg << "unknown centrality type: " << s;
    LOG(ERROR) << msg.str();
    throw std::runtime_error(msg.str());
  }

}
//@random
std::vector<node_id> graph_serv::shortest_path(const shortest_path_req& req) const
{
  std::vector<jubatus::graph::node_id_t> ret0;
  jubatus::graph::preset_query q;
  g_.get_model()->shortest_path(n2i(req.src), n2i(req.tgt), req.max_hop, ret0, q);
  std::vector<node_id> ret;
  for(size_t i=0;i<ret0.size();++i){
    ret.push_back(i2n(ret0[i]));
  }
  return ret;
}

//update, broadcast
bool graph_serv::add_centrality_query(const preset_query& q0)
{
  jubatus::graph::preset_query q;
  framework::convert<jubatus::preset_query, jubatus::graph::preset_query>(q0, q);
  g_.get_model()->add_centrality_query(q);
  return true;
}

//update, broadcast
bool graph_serv::add_shortest_path_query(const preset_query& q0)
{
  jubatus::graph::preset_query q;
  framework::convert<jubatus::preset_query, jubatus::graph::preset_query>(q0, q);
  g_.get_model()->add_shortest_path_query(q);
  return true;
}

//update, broadcast
bool graph_serv::remove_centrality_query(const preset_query& q0)
{
  jubatus::graph::preset_query q;
  framework::convert<jubatus::preset_query, jubatus::graph::preset_query>(q0, q);
  g_.get_model()->remove_centrality_query(q);
  return true;
}

//update, broadcast
bool graph_serv::remove_shortest_path_query(const preset_query& q0)
{
  jubatus::graph::preset_query q;
  framework::convert<jubatus::preset_query, jubatus::graph::preset_query>(q0, q);
  g_.get_model()->remove_shortest_path_query(q);
  return true;
}

node_info graph_serv::get_node(const std::string& nid)const
{
  jubatus::graph::node_info info;
  g_.get_model()->get_node(n2i(nid), info);
  jubatus::node_info ret;
  framework::convert<graph::node_info, jubatus::node_info>(info, ret);
  return ret;
}
//@random
edge_info graph_serv::get_edge(const std::string& nid, const edge_id_t& id)const
{
  jubatus::graph::edge_info info;
  g_.get_model()->get_edge((jubatus::graph::edge_id_t)id, info);
  jubatus::edge_info ret;
  ret.p = info.p;
  ret.src = i2n(info.src);
  ret.tgt = i2n(info.tgt);
  return ret;
}

//@broadcast
int graph_serv::update_index(){
  if(not a_.is_standalone()){
    throw std::runtime_error("manual mix is available only in standalone mode.");
  }
  clock_time start = get_clock_time();
  g_.get_model()->update_index();
  std::string diff;
  g_.get_model()->get_diff(diff);
  g_.get_model()->set_mixed_and_clear_diff(diff);
  clock_time end = get_clock_time();
  LOG(WARNING) << "mix done manually and locally; in " << (double)(end - start) << " secs.";
  return 0;
}
int graph_serv::clear(){
  if(g_.get_model())
    g_.get_model()->clear();
  return 0;
}

std::map<std::string, std::map<std::string,std::string> > graph_serv::get_status()const
{
  std::map<std::string,std::string> ret0;

  g_.get_model()->get_status(ret0);

  std::map<std::string, std::map<std::string,std::string> > ret =
    jubatus_serv::get_status();

  ret[get_server_identifier()].insert(ret0.begin(), ret0.end());
  return ret;
}

int graph_serv::create_node_here(const std::string& nid)
{
  graph::node_id_t id = pfi::lang::lexical_cast<graph::node_id_t>(nid);
  g_.get_model()->create_node(id);
  g_.get_model()->create_global_node(id);
  return 0;
}
int graph_serv::create_global_node(const std::string& nid)
{
  g_.get_model()->create_global_node(n2i(nid));
  return 0;
} //update internal

int graph_serv::remove_global_node(const std::string& nid)
{
  g_.get_model()->remove_global_node(n2i(nid));
  return 0;
} //update internal

void graph_serv::after_load(){}

}}
<commit_msg>better error ignor^H^H^H^H^Hhandling<commit_after>// Jubatus: Online machine learning framework for distributed environment
// Copyright (C) 2011,2012 Preferred Infrastructure and Nippon Telegraph and Telephone Corporation.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

#include "graph_serv.hpp"
#include "graph_types.hpp"

#include "../graph/graph_factory.hpp"
#include "../common/util.hpp"
#include "../common/membership.hpp"
#include "graph_client.hpp"

#include "../framework/aggregators.hpp"

#include <pficommon/lang/cast.h>
#include <sstream>

#include <pficommon/system/time_util.h>
using pfi::system::time::clock_time;
using pfi::system::time::get_clock_time;

namespace jubatus { namespace server {

enum graph_serv_error {
  NODE_ALREADY_EXISTS = 0xDEADBEEF
};

inline node_id uint642nodeid(uint64_t i){
  return pfi::lang::lexical_cast<node_id, uint64_t>(i);
}
inline uint64_t nodeid2uint64(const node_id& id)
{
  return pfi::lang::lexical_cast<uint64_t, node_id>(id);
}

inline node_id i2n(uint64_t i){
  return uint642nodeid(i);
}
inline uint64_t n2i(const node_id& id){
  return nodeid2uint64(id);
}

graph_serv::graph_serv(const framework::server_argv& a)
  : jubatus_serv(a)
{
  common::cshared_ptr<jubatus::graph::graph_base>
    g(jubatus::graph::create_graph("graph_wo_index"));
  g_.set_model(g);
  register_mixable(mixable_cast(&g_));
}
graph_serv::~graph_serv()
{}

std::string graph_serv::create_node(){
  uint64_t nid = idgen_.generate();
  std::string nid_str = pfi::lang::lexical_cast<std::string>(nid);
  // send true create_global_node to other machines.
  //DLOG(INFO) << __func__ << " " << nid_str;

  if(not a_.is_standalone()){
    // we dont need global locking, because getting unique id from zk
    // guarantees there'll be no data confliction
    {
      common::cht ht(zk_, a_.name);
      std::vector<std::pair<std::string, int> > nodes;
      ht.find(nid_str, nodes, 2); //replication number of local_node
      if(nodes.empty()){
        throw std::runtime_error("fatal: no server found in cht: "+nid_str);
      }
      // this sequences MUST success, in case of failures the whole request should be canceled
      if(nodes[0].first == a_.eth && nodes[0].second == a_.port){
        this->create_node_here(nid_str);
      }else{
        client::graph c(nodes[0].first, nodes[0].second, 5.0);
        c.create_node_here(a_.name, nid_str);
      }

      for(size_t i = 1; i < nodes.size(); ++i){
        try{
          if(nodes[i].first == a_.eth && nodes[i].second == a_.port){
            this->create_node_here(nid_str);
          }else{
            client::graph c(nodes[i].first, nodes[i].second, 5.0);
            c.create_node_here(a_.name, nid_str);
          }
        }catch(const graph::local_node_exists& e){ // pass through
        }catch(const graph::global_node_exists& e){// pass through

        }catch(const std::runtime_error& e){ // error !
          LOG(INFO) << i+1 << "th replica: " << nodes[i].first << ":" << nodes[i].second << " " << e.what();
        }
      }
    }
    std::vector<std::pair<std::string, int> > members;
    get_members(members);
    if(not members.empty()){
      common::mprpc::rpc_mclient c(members, a_.timeout); //create global node
      c.call_async("create_global_node", a_.name, nid_str);

      try{
        c.join_all<int>(pfi::lang::function<int(int,int)>(&jubatus::framework::add<int>));
      }catch(const std::runtime_error & e){ // no results?, pass through
        DLOG(INFO) << __func__ << " " << e.what();
      }
    }
  }else{
    this->create_node_here(nid_str);
  }
  DLOG(INFO) << "new node created: " << nid_str;
  return nid_str;
}

int graph_serv::update_node(const std::string& id, const property& p)
{

  g_.get_model()->update_node(n2i(id), p);
  return 0;
}

int graph_serv::remove_node(const std::string& nid){
  g_.get_model()->remove_node(n2i(nid));
  g_.get_model()->remove_global_node(n2i(nid));

  if(not a_.is_standalone()){
    // send true remove_node_ to other machine,
    // if conflicts with create_node, users should re-run to ensure removal
    std::vector<std::pair<std::string, int> > members;
    get_members(members);

    if(not members.empty()){
      common::mprpc::rpc_mclient c(members, a_.timeout); //create global node
      c.call_async("remove_global_node", a_.name, nid);
      c.join_all<int>(pfi::lang::function<int(int,int)>(&jubatus::framework::add<int>));
    }
  }
  DLOG(INFO) << "node removed: " << nid;
  return 0;
}

  //@cht
int graph_serv::create_edge(const std::string& id, const edge_info& ei)
{
  edge_id_t eid = idgen_.generate();
  g_.get_model()->create_edge(eid, n2i(ei.src), n2i(ei.tgt));
  g_.get_model()->update_edge(eid, ei.p);
  // DLOG(INFO) << "edge created (" << eid << ") " << ei.src << " => " << ei.tgt;
  return eid;
}

  //@random
int graph_serv::update_edge(const std::string&, edge_id_t eid, const edge_info& ei)
{
  g_.get_model()->update_edge(eid, ei.p);
  return 0;
}

int graph_serv::remove_edge(const std::string&, const edge_id_t& id){
  g_.get_model()->remove_edge(id);
  return 0;
}

//@random
double graph_serv::centrality(const std::string& id, const centrality_type& s,
			      const preset_query& q) const
{
  if(s == 0){
    jubatus::graph::preset_query q0;
    return g_.get_model()->centrality(n2i(id),
				      jubatus::graph::EIGENSCORE,
				      q0);
  }else{
    std::stringstream msg;
    msg << "unknown centrality type: " << s;
    LOG(ERROR) << msg.str();
    throw std::runtime_error(msg.str());
  }

}
//@random
std::vector<node_id> graph_serv::shortest_path(const shortest_path_req& req) const
{
  std::vector<jubatus::graph::node_id_t> ret0;
  jubatus::graph::preset_query q;
  g_.get_model()->shortest_path(n2i(req.src), n2i(req.tgt), req.max_hop, ret0, q);
  std::vector<node_id> ret;
  for(size_t i=0;i<ret0.size();++i){
    ret.push_back(i2n(ret0[i]));
  }
  return ret;
}

//update, broadcast
bool graph_serv::add_centrality_query(const preset_query& q0)
{
  jubatus::graph::preset_query q;
  framework::convert<jubatus::preset_query, jubatus::graph::preset_query>(q0, q);
  g_.get_model()->add_centrality_query(q);
  return true;
}

//update, broadcast
bool graph_serv::add_shortest_path_query(const preset_query& q0)
{
  jubatus::graph::preset_query q;
  framework::convert<jubatus::preset_query, jubatus::graph::preset_query>(q0, q);
  g_.get_model()->add_shortest_path_query(q);
  return true;
}

//update, broadcast
bool graph_serv::remove_centrality_query(const preset_query& q0)
{
  jubatus::graph::preset_query q;
  framework::convert<jubatus::preset_query, jubatus::graph::preset_query>(q0, q);
  g_.get_model()->remove_centrality_query(q);
  return true;
}

//update, broadcast
bool graph_serv::remove_shortest_path_query(const preset_query& q0)
{
  jubatus::graph::preset_query q;
  framework::convert<jubatus::preset_query, jubatus::graph::preset_query>(q0, q);
  g_.get_model()->remove_shortest_path_query(q);
  return true;
}

node_info graph_serv::get_node(const std::string& nid)const
{
  jubatus::graph::node_info info;
  g_.get_model()->get_node(n2i(nid), info);
  jubatus::node_info ret;
  framework::convert<graph::node_info, jubatus::node_info>(info, ret);
  return ret;
}
//@random
edge_info graph_serv::get_edge(const std::string& nid, const edge_id_t& id)const
{
  jubatus::graph::edge_info info;
  g_.get_model()->get_edge((jubatus::graph::edge_id_t)id, info);
  jubatus::edge_info ret;
  ret.p = info.p;
  ret.src = i2n(info.src);
  ret.tgt = i2n(info.tgt);
  return ret;
}

//@broadcast
int graph_serv::update_index(){
  if(not a_.is_standalone()){
    throw std::runtime_error("manual mix is available only in standalone mode.");
  }
  clock_time start = get_clock_time();
  g_.get_model()->update_index();
  std::string diff;
  g_.get_model()->get_diff(diff);
  g_.get_model()->set_mixed_and_clear_diff(diff);
  clock_time end = get_clock_time();
  LOG(WARNING) << "mix done manually and locally; in " << (double)(end - start) << " secs.";
  return 0;
}
int graph_serv::clear(){
  if(g_.get_model())
    g_.get_model()->clear();
  return 0;
}

std::map<std::string, std::map<std::string,std::string> > graph_serv::get_status()const
{
  std::map<std::string,std::string> ret0;

  g_.get_model()->get_status(ret0);

  std::map<std::string, std::map<std::string,std::string> > ret =
    jubatus_serv::get_status();

  ret[get_server_identifier()].insert(ret0.begin(), ret0.end());
  return ret;
}

int graph_serv::create_node_here(const std::string& nid)
{
  try{
    graph::node_id_t id = pfi::lang::lexical_cast<graph::node_id_t>(nid);
    g_.get_model()->create_node(id);
    g_.get_model()->create_global_node(id);

  }catch(const graph::local_node_exists& e){ //pass through
  }catch(const graph::global_node_exists& e){//pass through
  }catch(const std::runtime_error& e){
    DLOG(INFO) << e.what() << " " << nid;
    throw e;
  }

  return 0;
}
int graph_serv::create_global_node(const std::string& nid)
{
  try{
    g_.get_model()->create_global_node(n2i(nid));
  }catch(const graph::local_node_exists& e){
  }catch(const graph::global_node_exists& e){
  }catch(const std::runtime_error& e){
    DLOG(INFO) << e.what() << " " << nid;
    throw e;
  }
  return 0;
} //update internal

int graph_serv::remove_global_node(const std::string& nid)
{
  try{
    g_.get_model()->remove_global_node(n2i(nid));
  }catch(const graph::local_node_exists& e){
  }catch(const graph::global_node_exists& e){
  }catch(const std::runtime_error& e){
    DLOG(INFO) << e.what() << " " << nid;
    throw e;
  }
  return 0;
} //update internal

void graph_serv::after_load(){}

}}
<|endoftext|>


<commit_before>//===-- llc.cpp - Implement the LLVM Compiler -----------------------------===//
//
// This is the llc compiler driver.
//
//===----------------------------------------------------------------------===//

#include "llvm/Bytecode/Reader.h"
#include "llvm/Target/TargetMachineImpls.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Assembly/PrintModulePass.h"
#include "llvm/Module.h"
#include "llvm/PassManager.h"
#include "llvm/Pass.h"
#include "llvm/Support/PassNameParser.h"
#include "Support/CommandLine.h"
#include "Support/Signals.h"
#include <memory>
#include <fstream>

//------------------------------------------------------------------------------
// Option declarations for LLC.
//------------------------------------------------------------------------------

// Make all registered optimization passes available to llc.  These passes
// will all be run before the simplification and lowering steps used by the
// back-end code generator, and will be run in the order specified on the
// command line. The OptimizationList is automatically populated with
// registered Passes by the PassNameParser.
//
static cl::list<const PassInfo*, bool,
                FilteredPassNameParser<PassInfo::Optimization> >
OptimizationList(cl::desc("Optimizations available:"));

// General options for llc.  Other pass-specific options are specified
// within the corresponding llc passes, and target-specific options
// and back-end code generation options are specified with the target machine.
//
static cl::opt<std::string>
InputFilename(cl::Positional, cl::desc("<input bytecode>"), cl::init("-"));

static cl::opt<std::string>
OutputFilename("o", cl::desc("Output filename"), cl::value_desc("filename"));

static cl::opt<bool> Force("f", cl::desc("Overwrite output files"));

static cl::opt<bool>
DisableStrip("disable-strip",
          cl::desc("Do not strip the LLVM bytecode included in the executable"));

static cl::opt<bool>
DumpAsm("d", cl::desc("Print bytecode before native code generation"),
        cl::Hidden);

// GetFileNameRoot - Helper function to get the basename of a filename...
static inline std::string
GetFileNameRoot(const std::string &InputFilename)
{
  std::string IFN = InputFilename;
  std::string outputFilename;
  int Len = IFN.length();
  if (IFN[Len-3] == '.' && IFN[Len-2] == 'b' && IFN[Len-1] == 'c') {
    outputFilename = std::string(IFN.begin(), IFN.end()-3); // s/.bc/.s/
  } else {
    outputFilename = IFN;
  }
  return outputFilename;
}

//===---------------------------------------------------------------------===//
// Function main()
//
// Entry point for the llc compiler.
//===---------------------------------------------------------------------===//

int
main(int argc, char **argv)
{
  cl::ParseCommandLineOptions(argc, argv, " llvm system compiler\n");

  // Allocate a target... in the future this will be controllable on the
  // command line.
  std::auto_ptr<TargetMachine> target(allocateSparcTargetMachine());
  assert(target.get() && "Could not allocate target machine!");

  TargetMachine &Target = *target.get();
  const TargetData &TD = Target.getTargetData();

  // Load the module to be compiled...
  std::auto_ptr<Module> M(ParseBytecodeFile(InputFilename));
  if (M.get() == 0)
    {
      std::cerr << argv[0] << ": bytecode didn't read correctly.\n";
      return 1;
    }

  // Build up all of the passes that we want to do to the module...
  PassManager Passes;

  Passes.add(new TargetData("llc", TD.isLittleEndian(), TD.getPointerSize(),
                            TD.getPointerAlignment(), TD.getDoubleAlignment()));

  // Create a new optimization pass for each one specified on the command line
  // Deal specially with tracing passes, which must be run differently than opt.
  //
  for (unsigned i = 0; i < OptimizationList.size(); ++i) {
    const PassInfo *Opt = OptimizationList[i];

    // handle other passes as normal optimization passes
    if (Opt->getNormalCtor())
      Passes.add(Opt->getNormalCtor()());
    else if (Opt->getTargetCtor())
      Passes.add(Opt->getTargetCtor()(Target));
    else
      std::cerr << argv[0] << ": cannot create pass: "
                << Opt->getPassName() << "\n";
  }

  // Decompose multi-dimensional refs into a sequence of 1D refs
  // FIXME: This is sparc specific!
  Passes.add(createDecomposeMultiDimRefsPass());

  // Replace malloc and free instructions with library calls.
  // Do this after tracing until lli implements these lib calls.
  // For now, it will emulate malloc and free internally.
  // FIXME: This is sparc specific!
  Passes.add(createLowerAllocationsPass());

  // If LLVM dumping after transformations is requested, add it to the pipeline
  if (DumpAsm)
    Passes.add(new PrintFunctionPass("Code after xformations: \n", &std::cerr));

  // Strip all of the symbols from the bytecode so that it will be smaller...
  if (!DisableStrip)
    Passes.add(createSymbolStrippingPass());

  // Figure out where we are going to send the output...
  std::ostream *Out = 0;
  if (OutputFilename != "")
    {   // Specified an output filename?
      if (!Force && std::ifstream(OutputFilename.c_str())) {
        // If force is not specified, make sure not to overwrite a file!
        std::cerr << argv[0] << ": error opening '" << OutputFilename
                  << "': file exists!\n"
                  << "Use -f command line argument to force output\n";
        return 1;
      }
      Out = new std::ofstream(OutputFilename.c_str());

      // Make sure that the Out file gets unlink'd from the disk if we get a
      // SIGINT
      RemoveFileOnSignal(OutputFilename);
    }
  else
    {
      if (InputFilename == "-")
        {
          OutputFilename = "-";
          Out = &std::cout;
        }
      else
        {
          std::string OutputFilename = GetFileNameRoot(InputFilename);
          OutputFilename += ".s";

          if (!Force && std::ifstream(OutputFilename.c_str()))
            {
              // If force is not specified, make sure not to overwrite a file!
              std::cerr << argv[0] << ": error opening '" << OutputFilename
                        << "': file exists!\n"
                        << "Use -f command line argument to force output\n";
              return 1;
            }

          Out = new std::ofstream(OutputFilename.c_str());
          if (!Out->good())
            {
              std::cerr << argv[0] << ": error opening " << OutputFilename
                        << "!\n";
              delete Out;
              return 1;
            }

          // Make sure that the Out file gets unlink'd from the disk if we get a
          // SIGINT
          RemoveFileOnSignal(OutputFilename);
        }
    }

  // Ask the target to add backend passes as neccesary
  if (Target.addPassesToEmitAssembly(Passes, *Out)) {
    std::cerr << argv[0] << ": target '" << Target.getName()
              << " does not support static compilation!\n";
  } else {
    // Run our queue of passes all at once now, efficiently.
    Passes.run(*M.get());
  }

  // Delete the ostream if it's not a stdout stream
  if (Out != &std::cout) delete Out;

  return 0;
}
<commit_msg>Remove duplicate pass<commit_after>//===-- llc.cpp - Implement the LLVM Compiler -----------------------------===//
//
// This is the llc compiler driver.
//
//===----------------------------------------------------------------------===//

#include "llvm/Bytecode/Reader.h"
#include "llvm/Target/TargetMachineImpls.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Assembly/PrintModulePass.h"
#include "llvm/Module.h"
#include "llvm/PassManager.h"
#include "llvm/Pass.h"
#include "llvm/Support/PassNameParser.h"
#include "Support/CommandLine.h"
#include "Support/Signals.h"
#include <memory>
#include <fstream>

//------------------------------------------------------------------------------
// Option declarations for LLC.
//------------------------------------------------------------------------------

// Make all registered optimization passes available to llc.  These passes
// will all be run before the simplification and lowering steps used by the
// back-end code generator, and will be run in the order specified on the
// command line. The OptimizationList is automatically populated with
// registered Passes by the PassNameParser.
//
static cl::list<const PassInfo*, bool,
                FilteredPassNameParser<PassInfo::Optimization> >
OptimizationList(cl::desc("Optimizations available:"));

// General options for llc.  Other pass-specific options are specified
// within the corresponding llc passes, and target-specific options
// and back-end code generation options are specified with the target machine.
//
static cl::opt<std::string>
InputFilename(cl::Positional, cl::desc("<input bytecode>"), cl::init("-"));

static cl::opt<std::string>
OutputFilename("o", cl::desc("Output filename"), cl::value_desc("filename"));

static cl::opt<bool> Force("f", cl::desc("Overwrite output files"));

static cl::opt<bool>
DisableStrip("disable-strip",
          cl::desc("Do not strip the LLVM bytecode included in the executable"));

static cl::opt<bool>
DumpAsm("d", cl::desc("Print bytecode before native code generation"),
        cl::Hidden);

// GetFileNameRoot - Helper function to get the basename of a filename...
static inline std::string
GetFileNameRoot(const std::string &InputFilename)
{
  std::string IFN = InputFilename;
  std::string outputFilename;
  int Len = IFN.length();
  if (IFN[Len-3] == '.' && IFN[Len-2] == 'b' && IFN[Len-1] == 'c') {
    outputFilename = std::string(IFN.begin(), IFN.end()-3); // s/.bc/.s/
  } else {
    outputFilename = IFN;
  }
  return outputFilename;
}

//===---------------------------------------------------------------------===//
// Function main()
//
// Entry point for the llc compiler.
//===---------------------------------------------------------------------===//

int
main(int argc, char **argv)
{
  cl::ParseCommandLineOptions(argc, argv, " llvm system compiler\n");

  // Allocate a target... in the future this will be controllable on the
  // command line.
  std::auto_ptr<TargetMachine> target(allocateSparcTargetMachine());
  assert(target.get() && "Could not allocate target machine!");

  TargetMachine &Target = *target.get();
  const TargetData &TD = Target.getTargetData();

  // Load the module to be compiled...
  std::auto_ptr<Module> M(ParseBytecodeFile(InputFilename));
  if (M.get() == 0)
    {
      std::cerr << argv[0] << ": bytecode didn't read correctly.\n";
      return 1;
    }

  // Build up all of the passes that we want to do to the module...
  PassManager Passes;

  Passes.add(new TargetData("llc", TD.isLittleEndian(), TD.getPointerSize(),
                            TD.getPointerAlignment(), TD.getDoubleAlignment()));

  // Create a new optimization pass for each one specified on the command line
  // Deal specially with tracing passes, which must be run differently than opt.
  //
  for (unsigned i = 0; i < OptimizationList.size(); ++i) {
    const PassInfo *Opt = OptimizationList[i];

    // handle other passes as normal optimization passes
    if (Opt->getNormalCtor())
      Passes.add(Opt->getNormalCtor()());
    else if (Opt->getTargetCtor())
      Passes.add(Opt->getTargetCtor()(Target));
    else
      std::cerr << argv[0] << ": cannot create pass: "
                << Opt->getPassName() << "\n";
  }

  // Replace malloc and free instructions with library calls.
  // Do this after tracing until lli implements these lib calls.
  // For now, it will emulate malloc and free internally.
  // FIXME: This is sparc specific!
  Passes.add(createLowerAllocationsPass());

  // If LLVM dumping after transformations is requested, add it to the pipeline
  if (DumpAsm)
    Passes.add(new PrintFunctionPass("Code after xformations: \n", &std::cerr));

  // Strip all of the symbols from the bytecode so that it will be smaller...
  if (!DisableStrip)
    Passes.add(createSymbolStrippingPass());

  // Figure out where we are going to send the output...
  std::ostream *Out = 0;
  if (OutputFilename != "")
    {   // Specified an output filename?
      if (!Force && std::ifstream(OutputFilename.c_str())) {
        // If force is not specified, make sure not to overwrite a file!
        std::cerr << argv[0] << ": error opening '" << OutputFilename
                  << "': file exists!\n"
                  << "Use -f command line argument to force output\n";
        return 1;
      }
      Out = new std::ofstream(OutputFilename.c_str());

      // Make sure that the Out file gets unlink'd from the disk if we get a
      // SIGINT
      RemoveFileOnSignal(OutputFilename);
    }
  else
    {
      if (InputFilename == "-")
        {
          OutputFilename = "-";
          Out = &std::cout;
        }
      else
        {
          std::string OutputFilename = GetFileNameRoot(InputFilename);
          OutputFilename += ".s";

          if (!Force && std::ifstream(OutputFilename.c_str()))
            {
              // If force is not specified, make sure not to overwrite a file!
              std::cerr << argv[0] << ": error opening '" << OutputFilename
                        << "': file exists!\n"
                        << "Use -f command line argument to force output\n";
              return 1;
            }

          Out = new std::ofstream(OutputFilename.c_str());
          if (!Out->good())
            {
              std::cerr << argv[0] << ": error opening " << OutputFilename
                        << "!\n";
              delete Out;
              return 1;
            }

          // Make sure that the Out file gets unlink'd from the disk if we get a
          // SIGINT
          RemoveFileOnSignal(OutputFilename);
        }
    }

  // Ask the target to add backend passes as neccesary
  if (Target.addPassesToEmitAssembly(Passes, *Out)) {
    std::cerr << argv[0] << ": target '" << Target.getName()
              << " does not support static compilation!\n";
  } else {
    // Run our queue of passes all at once now, efficiently.
    Passes.run(*M.get());
  }

  // Delete the ostream if it's not a stdout stream
  if (Out != &std::cout) delete Out;

  return 0;
}
<|endoftext|>


<commit_before>//===-lto.cpp - LLVM Link Time Optimizer ----------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the Link Time Optimization library. This library is
// intended to be used by linker to optimize code at link time.
//
//===----------------------------------------------------------------------===//

#include "llvm-c/lto.h"
#include "llvm-c/Core.h"

#include "LTOModule.h"
#include "LTOCodeGenerator.h"

// holds most recent error string
// *** not thread safe ***
static std::string sLastErrorString;

//
// returns a printable string
//
extern const char* lto_get_version()
{
    return LTOCodeGenerator::getVersionString();
}

//
// returns the last error string or NULL if last operation was successful
//
const char* lto_get_error_message()
{
    return sLastErrorString.c_str();
}

//
// validates if a file is a loadable object file
//
bool lto_module_is_object_file(const char* path)
{
    return LTOModule::isBitcodeFile(path);
}

//
// validates if a file is a loadable object file compilable for requested target
//
bool lto_module_is_object_file_for_target(const char* path,
                                            const char* target_triplet_prefix)
{
    return LTOModule::isBitcodeFileForTarget(path, target_triplet_prefix);
}

//
// validates if a buffer is a loadable object file
//
bool lto_module_is_object_file_in_memory(const void* mem, size_t length)
{
    return LTOModule::isBitcodeFile(mem, length);
}

//
// validates if a buffer is a loadable object file compilable for the target
//
bool lto_module_is_object_file_in_memory_for_target(const void* mem,
                            size_t length, const char* target_triplet_prefix)
{
    return LTOModule::isBitcodeFileForTarget(mem, length, target_triplet_prefix);
}

//
// loads an object file from disk
// returns NULL on error (check lto_get_error_message() for details)
//
lto_module_t lto_module_create(const char* path)
{
     return LTOModule::makeLTOModule(path, sLastErrorString);
}

//
// loads an object file from memory
// returns NULL on error (check lto_get_error_message() for details)
//
lto_module_t lto_module_create_from_memory(const void* mem, size_t length)
{
     return LTOModule::makeLTOModule(mem, length, sLastErrorString);
}

//
// frees all memory for a module
// upon return the lto_module_t is no longer valid
//
void lto_module_dispose(lto_module_t mod)
{
    delete mod;
}

//
// returns triplet string which the object module was compiled under
//
const char* lto_module_get_target_triple(lto_module_t mod)
{
    return mod->getTargetTriple();
}

//
// returns the number of symbols in the object module
//
uint32_t lto_module_get_num_symbols(lto_module_t mod)
{
    return mod->getSymbolCount();
}

//
// returns the name of the ith symbol in the object module
//
const char* lto_module_get_symbol_name(lto_module_t mod, uint32_t index)
{
    return mod->getSymbolName(index);
}

//
// returns the attributes of the ith symbol in the object module
//
lto_symbol_attributes lto_module_get_symbol_attribute(lto_module_t mod,
                                                            uint32_t index)
{
    return mod->getSymbolAttributes(index);
}

//
// instantiates a code generator
// returns NULL if there is an error
//
lto_code_gen_t lto_codegen_create(void)
{
     return new LTOCodeGenerator();
}

//
// frees all memory for a code generator
// upon return the lto_code_gen_t is no longer valid
//
void lto_codegen_dispose(lto_code_gen_t cg)
{
    delete cg;
}

//
// add an object module to the set of modules for which code will be generated
// returns true on error (check lto_get_error_message() for details)
//
bool lto_codegen_add_module(lto_code_gen_t cg, lto_module_t mod)
{
    return cg->addModule(mod, sLastErrorString);
}

//
// sets what if any format of debug info should be generated
// returns true on error (check lto_get_error_message() for details)
//
bool lto_codegen_set_debug_model(lto_code_gen_t cg, lto_debug_model debug)
{
    return cg->setDebugInfo(debug, sLastErrorString);
}

//
// sets what code model to generated
// returns true on error (check lto_get_error_message() for details)
//
bool lto_codegen_set_pic_model(lto_code_gen_t cg, lto_codegen_model model)
{
  return cg->setCodePICModel(model, sLastErrorString);
}

//
// sets the path to gcc
//
void lto_codegen_set_gcc_path(lto_code_gen_t cg, const char* path)
{
  cg->setGccPath(path);
}

//
// sets the path to the assembler tool
//
void lto_codegen_set_assembler_path(lto_code_gen_t cg, const char* path)
{
    cg->setAssemblerPath(path);
}

//
// adds to a list of all global symbols that must exist in the final
// generated code.  If a function is not listed there, it might be
// inlined into every usage and optimized away.
//
void lto_codegen_add_must_preserve_symbol(lto_code_gen_t cg, const char* symbol)
{
  cg->addMustPreserveSymbol(symbol);
}

//
// writes a new file at the specified path that contains the
// merged contents of all modules added so far.
// returns true on error (check lto_get_error_message() for details)
//
bool lto_codegen_write_merged_modules(lto_code_gen_t cg, const char* path)
{
  return cg->writeMergedModules(path, sLastErrorString);
}

//
// Generates code for all added modules into one native object file.
// On sucess returns a pointer to a generated mach-o/ELF buffer and
// length set to the buffer size.  The buffer is owned by the
// lto_code_gen_t and will be freed when lto_codegen_dispose()
// is called, or lto_codegen_compile() is called again.
// On failure, returns NULL (check lto_get_error_message() for details).
//
extern const void*
lto_codegen_compile(lto_code_gen_t cg, size_t* length)
{
  return cg->compile(length, sLastErrorString);
}

//
// Used to pass extra options to the code generator
//
extern void
lto_codegen_debug_options(lto_code_gen_t cg, const char * opt)
{
  cg->setCodeGenDebugOptions(opt);
}<commit_msg>Add newline at end of file.<commit_after>//===-lto.cpp - LLVM Link Time Optimizer ----------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the Link Time Optimization library. This library is
// intended to be used by linker to optimize code at link time.
//
//===----------------------------------------------------------------------===//

#include "llvm-c/lto.h"
#include "llvm-c/Core.h"

#include "LTOModule.h"
#include "LTOCodeGenerator.h"

// holds most recent error string
// *** not thread safe ***
static std::string sLastErrorString;

//
// returns a printable string
//
extern const char* lto_get_version()
{
    return LTOCodeGenerator::getVersionString();
}

//
// returns the last error string or NULL if last operation was successful
//
const char* lto_get_error_message()
{
    return sLastErrorString.c_str();
}

//
// validates if a file is a loadable object file
//
bool lto_module_is_object_file(const char* path)
{
    return LTOModule::isBitcodeFile(path);
}

//
// validates if a file is a loadable object file compilable for requested target
//
bool lto_module_is_object_file_for_target(const char* path,
                                            const char* target_triplet_prefix)
{
    return LTOModule::isBitcodeFileForTarget(path, target_triplet_prefix);
}

//
// validates if a buffer is a loadable object file
//
bool lto_module_is_object_file_in_memory(const void* mem, size_t length)
{
    return LTOModule::isBitcodeFile(mem, length);
}

//
// validates if a buffer is a loadable object file compilable for the target
//
bool lto_module_is_object_file_in_memory_for_target(const void* mem,
                            size_t length, const char* target_triplet_prefix)
{
    return LTOModule::isBitcodeFileForTarget(mem, length, target_triplet_prefix);
}

//
// loads an object file from disk
// returns NULL on error (check lto_get_error_message() for details)
//
lto_module_t lto_module_create(const char* path)
{
     return LTOModule::makeLTOModule(path, sLastErrorString);
}

//
// loads an object file from memory
// returns NULL on error (check lto_get_error_message() for details)
//
lto_module_t lto_module_create_from_memory(const void* mem, size_t length)
{
     return LTOModule::makeLTOModule(mem, length, sLastErrorString);
}

//
// frees all memory for a module
// upon return the lto_module_t is no longer valid
//
void lto_module_dispose(lto_module_t mod)
{
    delete mod;
}

//
// returns triplet string which the object module was compiled under
//
const char* lto_module_get_target_triple(lto_module_t mod)
{
    return mod->getTargetTriple();
}

//
// returns the number of symbols in the object module
//
uint32_t lto_module_get_num_symbols(lto_module_t mod)
{
    return mod->getSymbolCount();
}

//
// returns the name of the ith symbol in the object module
//
const char* lto_module_get_symbol_name(lto_module_t mod, uint32_t index)
{
    return mod->getSymbolName(index);
}

//
// returns the attributes of the ith symbol in the object module
//
lto_symbol_attributes lto_module_get_symbol_attribute(lto_module_t mod,
                                                            uint32_t index)
{
    return mod->getSymbolAttributes(index);
}

//
// instantiates a code generator
// returns NULL if there is an error
//
lto_code_gen_t lto_codegen_create(void)
{
     return new LTOCodeGenerator();
}

//
// frees all memory for a code generator
// upon return the lto_code_gen_t is no longer valid
//
void lto_codegen_dispose(lto_code_gen_t cg)
{
    delete cg;
}

//
// add an object module to the set of modules for which code will be generated
// returns true on error (check lto_get_error_message() for details)
//
bool lto_codegen_add_module(lto_code_gen_t cg, lto_module_t mod)
{
    return cg->addModule(mod, sLastErrorString);
}

//
// sets what if any format of debug info should be generated
// returns true on error (check lto_get_error_message() for details)
//
bool lto_codegen_set_debug_model(lto_code_gen_t cg, lto_debug_model debug)
{
    return cg->setDebugInfo(debug, sLastErrorString);
}

//
// sets what code model to generated
// returns true on error (check lto_get_error_message() for details)
//
bool lto_codegen_set_pic_model(lto_code_gen_t cg, lto_codegen_model model)
{
  return cg->setCodePICModel(model, sLastErrorString);
}

//
// sets the path to gcc
//
void lto_codegen_set_gcc_path(lto_code_gen_t cg, const char* path)
{
  cg->setGccPath(path);
}

//
// sets the path to the assembler tool
//
void lto_codegen_set_assembler_path(lto_code_gen_t cg, const char* path)
{
    cg->setAssemblerPath(path);
}

//
// adds to a list of all global symbols that must exist in the final
// generated code.  If a function is not listed there, it might be
// inlined into every usage and optimized away.
//
void lto_codegen_add_must_preserve_symbol(lto_code_gen_t cg, const char* symbol)
{
  cg->addMustPreserveSymbol(symbol);
}

//
// writes a new file at the specified path that contains the
// merged contents of all modules added so far.
// returns true on error (check lto_get_error_message() for details)
//
bool lto_codegen_write_merged_modules(lto_code_gen_t cg, const char* path)
{
  return cg->writeMergedModules(path, sLastErrorString);
}

//
// Generates code for all added modules into one native object file.
// On sucess returns a pointer to a generated mach-o/ELF buffer and
// length set to the buffer size.  The buffer is owned by the
// lto_code_gen_t and will be freed when lto_codegen_dispose()
// is called, or lto_codegen_compile() is called again.
// On failure, returns NULL (check lto_get_error_message() for details).
//
extern const void*
lto_codegen_compile(lto_code_gen_t cg, size_t* length)
{
  return cg->compile(length, sLastErrorString);
}

//
// Used to pass extra options to the code generator
//
extern void
lto_codegen_debug_options(lto_code_gen_t cg, const char * opt)
{
  cg->setCodeGenDebugOptions(opt);
}
<|endoftext|>


<commit_before>/*
 * Copyright 2017 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkImage.h"
#include "SkOSFile.h"
#include "SkPictureRecorder.h"
#include "SkPngEncoder.h"
#include "Timer.h"
#include "ok.h"
#include <chrono>
#include <regex>

static std::unique_ptr<Src> proxy(Src* original, std::function<Status(SkCanvas*)> fn) {
    struct : Src {
        Src*                             original;
        std::function<Status(SkCanvas*)> fn;

        std::string name() override { return original->name(); }
        SkISize     size() override { return original->size(); }
        Status draw(SkCanvas* canvas) override { return fn(canvas); }
    } src;
    src.original = original;
    src.fn       = fn;
    return move_unique(src);
}

struct ViaPic : Dst {
    std::unique_ptr<Dst> target;
    bool                 rtree = false;

    static std::unique_ptr<Dst> Create(Options options, std::unique_ptr<Dst> dst) {
        ViaPic via;
        via.target = std::move(dst);
        if (options("bbh") == "rtree") { via.rtree = true; }
        return move_unique(via);
    }

    Status draw(Src* src) override {
        SkRTreeFactory factory;
        SkPictureRecorder rec;
        rec.beginRecording(SkRect::MakeSize(SkSize::Make(src->size())),
                           rtree ? &factory : nullptr);

        for (auto status = src->draw(rec.getRecordingCanvas()); status != Status::OK; ) {
            return status;
        }
        auto pic = rec.finishRecordingAsPicture();

        return target->draw(proxy(src, [=](SkCanvas* canvas) {
            pic->playback(canvas);
            return Status::OK;
        }).get());
    }

    sk_sp<SkImage> image() override {
        return target->image();
    }
};
static Register via_pic{"via_pic", "record then play back an SkPicture", ViaPic::Create};

struct Png : Dst {
    std::unique_ptr<Dst> target;
    std::string          dir;

    static std::unique_ptr<Dst> Create(Options options, std::unique_ptr<Dst> dst) {
        Png via;
        via.target = std::move(dst);
        via.dir    = options("dir", "ok");
        return move_unique(via);
    }

    Status draw(Src* src) override {
        for (auto status = target->draw(src); status != Status::OK; ) {
            return status;
        }

        SkBitmap bm;
        SkPixmap pm;
        if (!target->image()->asLegacyBitmap(&bm, SkImage::kRO_LegacyBitmapMode) ||
            !bm.peekPixels(&pm)) {
            return Status::Failed;
        }

        sk_mkdir(dir.c_str());
        SkFILEWStream dst{(dir + "/" + src->name() + ".png").c_str()};

        SkPngEncoder::Options options;
        options.fFilterFlags      = SkPngEncoder::FilterFlag::kNone;
        options.fZLibLevel        = 1;
        options.fUnpremulBehavior = pm.colorSpace() ? SkTransferFunctionBehavior::kRespect
                                                    : SkTransferFunctionBehavior::kIgnore;
        return SkPngEncoder::Encode(&dst, pm, options) ? Status::OK
                                                       : Status::Failed;
    }

    sk_sp<SkImage> image() override {
        return target->image();
    }
};
static Register png{"png", "dump PNGs to dir=ok" , Png::Create};

struct Filter : Dst {
    std::unique_ptr<Dst> target;
    std::regex match, search;

    static std::unique_ptr<Dst> Create(Options options, std::unique_ptr<Dst> dst) {
        Filter via;
        via.target = std::move(dst);
        via.match  = options("match",  ".*");
        via.search = options("search", ".*");
        return move_unique(via);
    }

    Status draw(Src* src) override {
        auto name = src->name();
        if (!std::regex_match (name, match) ||
            !std::regex_search(name, search)) {
            return Status::Skipped;
        }
        return target->draw(src);
    }

    sk_sp<SkImage> image() override {
        return target->image();
    }
};
static Register filter{"filter",
                       "run only srcs matching match=.* exactly and search=.* somewhere",
                       Filter::Create};

struct Time : Dst {
    std::unique_ptr<Dst> target;

    static std::unique_ptr<Dst> Create(Options options, std::unique_ptr<Dst> dst) {
        Time via;
        via.target = std::move(dst);
        return move_unique(via);
    }

    Status draw(Src* src) override {
        auto start = std::chrono::steady_clock::now();
            Status status = target->draw(src);
        std::chrono::duration<double, std::milli> elapsed = std::chrono::steady_clock::now()
                                                          - start;

        auto msg = HumanizeMs(elapsed.count());
        ok_log(msg.c_str());
        return status;
    }

    sk_sp<SkImage> image() override {
        return target->image();
    }
};
static Register _time{"time",
                      "print wall run time",
                      Time::Create};
<commit_msg>add memory via to ok<commit_after>/*
 * Copyright 2017 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkImage.h"
#include "SkOSFile.h"
#include "SkPictureRecorder.h"
#include "SkPngEncoder.h"
#include "ProcStats.h"
#include "Timer.h"
#include "ok.h"
#include <chrono>
#include <regex>

static std::unique_ptr<Src> proxy(Src* original, std::function<Status(SkCanvas*)> fn) {
    struct : Src {
        Src*                             original;
        std::function<Status(SkCanvas*)> fn;

        std::string name() override { return original->name(); }
        SkISize     size() override { return original->size(); }
        Status draw(SkCanvas* canvas) override { return fn(canvas); }
    } src;
    src.original = original;
    src.fn       = fn;
    return move_unique(src);
}

struct ViaPic : Dst {
    std::unique_ptr<Dst> target;
    bool                 rtree = false;

    static std::unique_ptr<Dst> Create(Options options, std::unique_ptr<Dst> dst) {
        ViaPic via;
        via.target = std::move(dst);
        if (options("bbh") == "rtree") { via.rtree = true; }
        return move_unique(via);
    }

    Status draw(Src* src) override {
        SkRTreeFactory factory;
        SkPictureRecorder rec;
        rec.beginRecording(SkRect::MakeSize(SkSize::Make(src->size())),
                           rtree ? &factory : nullptr);

        for (auto status = src->draw(rec.getRecordingCanvas()); status != Status::OK; ) {
            return status;
        }
        auto pic = rec.finishRecordingAsPicture();

        return target->draw(proxy(src, [=](SkCanvas* canvas) {
            pic->playback(canvas);
            return Status::OK;
        }).get());
    }

    sk_sp<SkImage> image() override {
        return target->image();
    }
};
static Register via_pic{"via_pic", "record then play back an SkPicture", ViaPic::Create};

struct Png : Dst {
    std::unique_ptr<Dst> target;
    std::string          dir;

    static std::unique_ptr<Dst> Create(Options options, std::unique_ptr<Dst> dst) {
        Png via;
        via.target = std::move(dst);
        via.dir    = options("dir", "ok");
        return move_unique(via);
    }

    Status draw(Src* src) override {
        for (auto status = target->draw(src); status != Status::OK; ) {
            return status;
        }

        SkBitmap bm;
        SkPixmap pm;
        if (!target->image()->asLegacyBitmap(&bm, SkImage::kRO_LegacyBitmapMode) ||
            !bm.peekPixels(&pm)) {
            return Status::Failed;
        }

        sk_mkdir(dir.c_str());
        SkFILEWStream dst{(dir + "/" + src->name() + ".png").c_str()};

        SkPngEncoder::Options options;
        options.fFilterFlags      = SkPngEncoder::FilterFlag::kNone;
        options.fZLibLevel        = 1;
        options.fUnpremulBehavior = pm.colorSpace() ? SkTransferFunctionBehavior::kRespect
                                                    : SkTransferFunctionBehavior::kIgnore;
        return SkPngEncoder::Encode(&dst, pm, options) ? Status::OK
                                                       : Status::Failed;
    }

    sk_sp<SkImage> image() override {
        return target->image();
    }
};
static Register png{"png", "dump PNGs to dir=ok" , Png::Create};

struct Filter : Dst {
    std::unique_ptr<Dst> target;
    std::regex match, search;

    static std::unique_ptr<Dst> Create(Options options, std::unique_ptr<Dst> dst) {
        Filter via;
        via.target = std::move(dst);
        via.match  = options("match",  ".*");
        via.search = options("search", ".*");
        return move_unique(via);
    }

    Status draw(Src* src) override {
        auto name = src->name();
        if (!std::regex_match (name, match) ||
            !std::regex_search(name, search)) {
            return Status::Skipped;
        }
        return target->draw(src);
    }

    sk_sp<SkImage> image() override {
        return target->image();
    }
};
static Register filter{"filter",
                       "run only srcs matching match=.* exactly and search=.* somewhere",
                       Filter::Create};

struct Time : Dst {
    std::unique_ptr<Dst> target;

    static std::unique_ptr<Dst> Create(Options options, std::unique_ptr<Dst> dst) {
        Time via;
        via.target = std::move(dst);
        return move_unique(via);
    }

    Status draw(Src* src) override {
        auto start = std::chrono::steady_clock::now();
            Status status = target->draw(src);
        std::chrono::duration<double, std::milli> elapsed = std::chrono::steady_clock::now()
                                                          - start;

        auto msg = HumanizeMs(elapsed.count());
        ok_log(msg.c_str());
        return status;
    }

    sk_sp<SkImage> image() override {
        return target->image();
    }
};
static Register _time{"time", "print wall run time", Time::Create};

struct Memory : Dst {
    std::unique_ptr<Dst> target;

    static std::unique_ptr<Dst> Create(Options options, std::unique_ptr<Dst> dst) {
        Memory via;
        via.target = std::move(dst);
        return move_unique(via);
    }

    Status draw(Src* src) override {
        Status status = target->draw(src);

        auto msg = SkStringPrintf("%dMB", sk_tools::getMaxResidentSetSizeMB());
        ok_log(msg.c_str());

        return status;
    }

    sk_sp<SkImage> image() override {
        return target->image();
    }
};
static Register memory{"memory", "print process maximum memory usage", Memory::Create};
<|endoftext|>


<commit_before>#include "Settings.h"

TypeHandle Settings::_type_handle;

Settings::Settings() {
    m_vfs = VirtualFileSystem::get_global_ptr();
    m_file = Filename("/useropt"); //First let's use this to set our dir.
    m_file = Filename(m_file.to_os_long_name()); //Now let's do the real file.
    m_file.set_binary();

    //Now to define our default settings.
    m_want_music = 1;
    m_want_sfx = 1;
    m_sfx_volume = 100.0f;
    m_music_volume = 100.0f;
    m_force_sw_midi = 0;
    m_embedded_mode = 0;
    m_log_chat = 0;
    m_current_driver = 0;
    m_resolution = 1;
    m_windowed_mode = 0;
    m_resolution_dimensions[0] = 800;
    m_resolution_dimensions[1] = 600;
}

Settings::~Settings() {

}

void Settings::read_settings() {
    Filename found(m_file);
    if (!m_vfs->exists(found)) {
        libotp_cat.debug() << "Failed to find Settings! Creating file...." << std::endl;
        m_vfs->create_file(m_file);
        write_settings();
        return;
    }
    m_vfs->read_file(found, m_data, true);
    m_data = decompress_string(m_data);
    Datagram dg(m_data);
    DatagramIterator dgi(dg);
    m_data = "";
    m_want_music = dgi.get_bool();
    m_want_sfx = dgi.get_bool();
    m_sfx_volume = dgi.get_stdfloat();
    m_music_volume = dgi.get_stdfloat();
    m_force_sw_midi = dgi.get_bool();
    m_embedded_mode = dgi.get_bool();
    m_log_chat = dgi.get_bool();
    m_current_driver = dgi.get_uint8();
    m_resolution = dgi.get_uint8();
    m_windowed_mode = dgi.get_uint8();
    m_resolution_dimensions[0] = dgi.get_uint16();
    m_resolution_dimensions[1] = dgi.get_uint16();
}

void Settings::write_settings() {
    Datagram dg;
    dg.add_bool(m_want_music);
    dg.add_bool(m_want_sfx);
    dg.add_stdfloat(m_sfx_volume);
    dg.add_stdfloat(m_music_volume);
    dg.add_bool(m_force_sw_midi);
    dg.add_bool(m_embedded_mode);
    dg.add_bool(m_log_chat);
    dg.add_uint8(m_current_driver);
    dg.add_uint8(m_resolution);
    dg.add_uint8(m_windowed_mode);
    dg.add_uint16(m_resolution_dimensions[0]);
    dg.add_uint16(m_resolution_dimensions[1]);
    DatagramIterator dgi(dg);
    m_data = dgi.get_remaining_bytes();
    m_data = compress_string(m_data, 9);
    if (m_vfs->exists(m_file)) {
        m_vfs->delete_file(m_file);
    }
    m_vfs->write_file(m_file, m_data, 0);
    m_data = "";
}

void Settings::set_music(bool mode) {
    m_want_music = mode;
}

void Settings::set_sfx(bool mode) {
    m_want_sfx = mode;
}

void Settings::set_force_sw_midi(bool mode) {
    m_force_sw_midi = mode;
}

void Settings::set_embedded_mode(bool mode) {
    m_embedded_mode = mode;
}

void Settings::set_chat_log(bool mode) {
    m_log_chat = mode;
}

void Settings::set_sfx_volume(float volume) {
    m_sfx_volume = volume;
}

void Settings::set_music_volume(float volume) {
    m_music_volume = volume;
}

void Settings::set_display_driver(unsigned int driver) {
    m_current_driver = driver;
}

void Settings::set_windowed_mode(unsigned int mode) {
    m_windowed_mode = mode;
}

void Settings::set_resolution(unsigned int resolution) {
    m_resolution = resolution;
}

void Settings::set_resolution_dimensions(unsigned int xsize, unsigned int ysize) {
    m_resolution_dimensions[0] = xsize;
    m_resolution_dimensions[1] = ysize;
}

int Settings::get_resolution() {
    return m_resolution;
}

int Settings::get_windowed_mode() {
    return m_windowed_mode;
}

bool Settings::get_music() {
    return m_want_music;
}

bool Settings::get_sfx() {
    return m_want_sfx;
}

float Settings::get_sfx_volume() {
    return m_sfx_volume;
}

float Settings::get_music_volume() {
    return m_music_volume;
}

bool Settings::get_embedded_mode() {
    return m_embedded_mode;
}

bool Settings::do_saved_settings_exist() {
    return 0;
}

<commit_msg>That's better!<commit_after>#include "Settings.h"

TypeHandle Settings::_type_handle;

Settings::Settings() {
    m_vfs = VirtualFileSystem::get_global_ptr();
    m_file = Filename("/useropt"); //First let's use this to set our dir.
    m_file = Filename(m_file.to_os_long_name()); //Now let's do the real file.
    m_file.set_binary();

    //Now to define our default settings.
    m_want_music = 1;
    m_want_sfx = 1;
    m_sfx_volume = 100.0f;
    m_music_volume = 100.0f;
    m_force_sw_midi = 0;
    m_embedded_mode = 0;
    m_log_chat = 0;
    m_current_driver = 0;
    m_resolution = 1;
    m_windowed_mode = 0;
    m_resolution_dimensions[0] = 800;
    m_resolution_dimensions[1] = 600;
}

Settings::~Settings() {
    delete[] m_vfs;
}

void Settings::read_settings() {
    Filename found(m_file);
    if (!m_vfs->exists(found)) {
        libotp_cat.debug() << "Failed to find Settings! Creating file...." << std::endl;
        m_vfs->create_file(m_file);
        write_settings();
        return;
    }
    m_vfs->read_file(found, m_data, true);
    m_data = decompress_string(m_data);
    Datagram dg(m_data);
    DatagramIterator dgi(dg);
    m_data = "";
    m_want_music = dgi.get_bool();
    m_want_sfx = dgi.get_bool();
    m_sfx_volume = dgi.get_stdfloat();
    m_music_volume = dgi.get_stdfloat();
    m_force_sw_midi = dgi.get_bool();
    m_embedded_mode = dgi.get_bool();
    m_log_chat = dgi.get_bool();
    m_current_driver = dgi.get_uint8();
    m_resolution = dgi.get_uint8();
    m_windowed_mode = dgi.get_uint8();
    m_resolution_dimensions[0] = dgi.get_uint16();
    m_resolution_dimensions[1] = dgi.get_uint16();
}

void Settings::write_settings() {
    Datagram dg;
    dg.add_bool(m_want_music);
    dg.add_bool(m_want_sfx);
    dg.add_stdfloat(m_sfx_volume);
    dg.add_stdfloat(m_music_volume);
    dg.add_bool(m_force_sw_midi);
    dg.add_bool(m_embedded_mode);
    dg.add_bool(m_log_chat);
    dg.add_uint8(m_current_driver);
    dg.add_uint8(m_resolution);
    dg.add_uint8(m_windowed_mode);
    dg.add_uint16(m_resolution_dimensions[0]);
    dg.add_uint16(m_resolution_dimensions[1]);
    DatagramIterator dgi(dg);
    m_data = dgi.get_remaining_bytes();
    m_data = compress_string(m_data, 9);
    if (m_vfs->exists(m_file)) {
        m_vfs->delete_file(m_file);
    }
    m_vfs->write_file(m_file, m_data, 0);
    m_data = "";
}

void Settings::set_music(bool mode) {
    m_want_music = mode;
}

void Settings::set_sfx(bool mode) {
    m_want_sfx = mode;
}

void Settings::set_force_sw_midi(bool mode) {
    m_force_sw_midi = mode;
}

void Settings::set_embedded_mode(bool mode) {
    m_embedded_mode = mode;
}

void Settings::set_chat_log(bool mode) {
    m_log_chat = mode;
}

void Settings::set_sfx_volume(float volume) {
    m_sfx_volume = volume;
}

void Settings::set_music_volume(float volume) {
    m_music_volume = volume;
}

void Settings::set_display_driver(unsigned int driver) {
    m_current_driver = driver;
}

void Settings::set_windowed_mode(unsigned int mode) {
    m_windowed_mode = mode;
}

void Settings::set_resolution(unsigned int resolution) {
    m_resolution = resolution;
}

void Settings::set_resolution_dimensions(unsigned int xsize, unsigned int ysize) {
    m_resolution_dimensions[0] = xsize;
    m_resolution_dimensions[1] = ysize;
}

int Settings::get_resolution() {
    return m_resolution;
}

int Settings::get_windowed_mode() {
    return m_windowed_mode;
}

bool Settings::get_music() {
    return m_want_music;
}

bool Settings::get_sfx() {
    return m_want_sfx;
}

float Settings::get_sfx_volume() {
    return m_sfx_volume;
}

float Settings::get_music_volume() {
    return m_music_volume;
}

bool Settings::get_embedded_mode() {
    return m_embedded_mode;
}

bool Settings::do_saved_settings_exist() {
    return m_vfs->exists(m_file);
}

<|endoftext|>


<commit_before>#pragma once

#include "file_monitor.hpp"
#include "filesystem.hpp"
#include "gcd_utility.hpp"
#include "spdlog_utility.hpp"
#include <deque>
#include <fstream>
#include <spdlog/spdlog.h>
#include <thread>
#include <vector>

namespace krbn {
class log_monitor final {
public:
  typedef std::function<void(const std::string& line)> new_log_line_callback;

  log_monitor(const log_monitor&) = delete;

  // FSEvents (file_monitor) notifies file changes only when the target file is just closed.
  // So, it is not usable for log_monitor since spdlog keeps opening log files and appending lines.
  //
  // We use timer to observe file changes instead.

  log_monitor(const std::vector<std::string>& targets,
              const new_log_line_callback& callback) : callback_(callback), timer_count_(timer_count(0)) {
    // setup initial_lines_

    for (const auto& target : targets) {
      add_initial_lines(target + ".1.txt");
      add_initial_lines(target + ".txt");

      files_.push_back(target + ".txt");
    }
  }

  ~log_monitor(void) {
    timer_ = nullptr;
  }

  void start(void) {
    timer_ = std::make_unique<gcd_utility::main_queue_timer>(
        dispatch_time(DISPATCH_TIME_NOW, 1.0 * NSEC_PER_SEC),
        1.0 * NSEC_PER_SEC,
        0,
        ^{
          timer_count_ = timer_count(static_cast<uint64_t>(timer_count_) + 1);
          for (const auto& file : files_) {
            if (auto size = filesystem::file_size(file)) {
              auto it = read_position_.find(file);
              if (it != read_position_.end()) {
                if (it->second != *size) {
                  add_lines(file);
                }
              }
            }
          }
          call_callback();
        });
  }

  const std::vector<std::pair<uint64_t, std::string>>& get_initial_lines(void) const {
    return initial_lines_;
  }

private:
  enum class timer_count : uint64_t {};

  void add_initial_lines(const std::string& file_path) {
    std::ifstream stream(file_path);
    std::string line;
    std::streampos read_position;

    while (std::getline(stream, line)) {
      if (add_initial_line(line)) {
        const size_t max_initial_lines = 250;
        while (initial_lines_.size() > max_initial_lines) {
          initial_lines_.erase(initial_lines_.begin());
        }
      }
      read_position = stream.tellg();
    }

    read_position_[file_path] = read_position;
  }

  bool add_initial_line(const std::string& line) {
    if (auto sort_key = spdlog_utility::get_sort_key(line)) {
      if (initial_lines_.empty()) {
        initial_lines_.push_back(std::make_pair(*sort_key, line));
        return true;
      }

      if (*sort_key < initial_lines_.front().first) {
        // line is too old
        return false;
      }

      if (*sort_key > initial_lines_.back().first) {
        initial_lines_.push_back(std::make_pair(*sort_key, line));
        return true;
      }

      for (auto it = initial_lines_.begin(); it != initial_lines_.end(); ++it) {
        if (*sort_key < it->first) {
          initial_lines_.insert(it, std::make_pair(*sort_key, line));
          return true;
        }
      }

      initial_lines_.push_back(std::make_pair(*sort_key, line));
      return true;
    }

    return false;
  }

  void add_lines(const std::string& file_path) {
    std::ifstream stream(file_path);
    if (!stream) {
      return;
    }

    // ----------------------------------------
    // seek

    auto it = read_position_.find(file_path);
    if (it != read_position_.end()) {
      if (auto size = filesystem::file_size(file_path)) {
        if (it->second < *size) {
          stream.seekg(it->second);
        }
      }
    }

    // ----------------------------------------
    // read

    std::string line;
    std::streampos read_position;
    while (std::getline(stream, line)) {
      if (auto sort_key = spdlog_utility::get_sort_key(line)) {
        added_lines_.push_back(std::make_tuple(timer_count_, *sort_key, line));
      }
      read_position = stream.tellg();
    }

    read_position_[file_path] = read_position;

    // ----------------------------------------
    // sort

    std::stable_sort(added_lines_.begin(), added_lines_.end(), [](const auto& a, const auto& b) {
      return std::get<1>(a) < std::get<1>(b);
    });
  }

  void call_callback(void) {
    while (true) {
      if (added_lines_.empty()) {
        return;
      }

      auto front = added_lines_.front();

      if (std::get<0>(front) != timer_count_) {
        // Wait if front is just added.
        return;
      }

      if (callback_) {
        callback_(std::get<2>(front));
      }

      added_lines_.pop_front();
    }
  }

  new_log_line_callback callback_;

  std::unique_ptr<gcd_utility::main_queue_timer> timer_;
  timer_count timer_count_;

  std::vector<std::pair<uint64_t, std::string>> initial_lines_;
  std::unordered_map<std::string, std::streampos> read_position_;
  std::vector<std::string> files_;
  std::deque<std::tuple<timer_count, uint64_t, std::string>> added_lines_;
};
}
<commit_msg>update #include<commit_after>#pragma once

#include "filesystem.hpp"
#include "gcd_utility.hpp"
#include "spdlog_utility.hpp"
#include <deque>
#include <fstream>
#include <spdlog/spdlog.h>
#include <thread>
#include <vector>

namespace krbn {
class log_monitor final {
public:
  typedef std::function<void(const std::string& line)> new_log_line_callback;

  log_monitor(const log_monitor&) = delete;

  // FSEvents (file_monitor) notifies file changes only when the target file is just closed.
  // So, it is not usable for log_monitor since spdlog keeps opening log files and appending lines.
  //
  // We use timer to observe file changes instead.

  log_monitor(const std::vector<std::string>& targets,
              const new_log_line_callback& callback) : callback_(callback), timer_count_(timer_count(0)) {
    // setup initial_lines_

    for (const auto& target : targets) {
      add_initial_lines(target + ".1.txt");
      add_initial_lines(target + ".txt");

      files_.push_back(target + ".txt");
    }
  }

  ~log_monitor(void) {
    timer_ = nullptr;
  }

  void start(void) {
    timer_ = std::make_unique<gcd_utility::main_queue_timer>(
        dispatch_time(DISPATCH_TIME_NOW, 1.0 * NSEC_PER_SEC),
        1.0 * NSEC_PER_SEC,
        0,
        ^{
          timer_count_ = timer_count(static_cast<uint64_t>(timer_count_) + 1);
          for (const auto& file : files_) {
            if (auto size = filesystem::file_size(file)) {
              auto it = read_position_.find(file);
              if (it != read_position_.end()) {
                if (it->second != *size) {
                  add_lines(file);
                }
              }
            }
          }
          call_callback();
        });
  }

  const std::vector<std::pair<uint64_t, std::string>>& get_initial_lines(void) const {
    return initial_lines_;
  }

private:
  enum class timer_count : uint64_t {};

  void add_initial_lines(const std::string& file_path) {
    std::ifstream stream(file_path);
    std::string line;
    std::streampos read_position;

    while (std::getline(stream, line)) {
      if (add_initial_line(line)) {
        const size_t max_initial_lines = 250;
        while (initial_lines_.size() > max_initial_lines) {
          initial_lines_.erase(initial_lines_.begin());
        }
      }
      read_position = stream.tellg();
    }

    read_position_[file_path] = read_position;
  }

  bool add_initial_line(const std::string& line) {
    if (auto sort_key = spdlog_utility::get_sort_key(line)) {
      if (initial_lines_.empty()) {
        initial_lines_.push_back(std::make_pair(*sort_key, line));
        return true;
      }

      if (*sort_key < initial_lines_.front().first) {
        // line is too old
        return false;
      }

      if (*sort_key > initial_lines_.back().first) {
        initial_lines_.push_back(std::make_pair(*sort_key, line));
        return true;
      }

      for (auto it = initial_lines_.begin(); it != initial_lines_.end(); ++it) {
        if (*sort_key < it->first) {
          initial_lines_.insert(it, std::make_pair(*sort_key, line));
          return true;
        }
      }

      initial_lines_.push_back(std::make_pair(*sort_key, line));
      return true;
    }

    return false;
  }

  void add_lines(const std::string& file_path) {
    std::ifstream stream(file_path);
    if (!stream) {
      return;
    }

    // ----------------------------------------
    // seek

    auto it = read_position_.find(file_path);
    if (it != read_position_.end()) {
      if (auto size = filesystem::file_size(file_path)) {
        if (it->second < *size) {
          stream.seekg(it->second);
        }
      }
    }

    // ----------------------------------------
    // read

    std::string line;
    std::streampos read_position;
    while (std::getline(stream, line)) {
      if (auto sort_key = spdlog_utility::get_sort_key(line)) {
        added_lines_.push_back(std::make_tuple(timer_count_, *sort_key, line));
      }
      read_position = stream.tellg();
    }

    read_position_[file_path] = read_position;

    // ----------------------------------------
    // sort

    std::stable_sort(added_lines_.begin(), added_lines_.end(), [](const auto& a, const auto& b) {
      return std::get<1>(a) < std::get<1>(b);
    });
  }

  void call_callback(void) {
    while (true) {
      if (added_lines_.empty()) {
        return;
      }

      auto front = added_lines_.front();

      if (std::get<0>(front) != timer_count_) {
        // Wait if front is just added.
        return;
      }

      if (callback_) {
        callback_(std::get<2>(front));
      }

      added_lines_.pop_front();
    }
  }

  new_log_line_callback callback_;

  std::unique_ptr<gcd_utility::main_queue_timer> timer_;
  timer_count timer_count_;

  std::vector<std::pair<uint64_t, std::string>> initial_lines_;
  std::unordered_map<std::string, std::streampos> read_position_;
  std::vector<std::string> files_;
  std::deque<std::tuple<timer_count, uint64_t, std::string>> added_lines_;
};
}
<|endoftext|>


<commit_before>/*
  This file is part of Ingen.
  Copyright 2007-2012 David Robillard <http://drobilla.net/>

  Ingen is free software: you can redistribute it and/or modify it under the
  terms of the GNU Affero General Public License as published by the Free
  Software Foundation, either version 3 of the License, or any later version.

  Ingen 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 Affero General Public License for details.

  You should have received a copy of the GNU Affero General Public License
  along with Ingen.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <utility>

#include "ingen/shared/AtomReader.hpp"
#include "lv2/lv2plug.in/ns/ext/atom/util.h"
#include "raul/Path.hpp"
#include "raul/log.hpp"

namespace Ingen {
namespace Shared {

AtomReader::AtomReader(LV2URIMap& map, URIs& uris, Forge& forge, Interface& iface)
	: _map(map)
	, _uris(uris)
	, _forge(forge)
	, _iface(iface)
{
}

void
AtomReader::get_uri(const LV2_Atom* in, Raul::Atom& out)
{
	if (in) {
		if (in->type == _uris.atom_URID) {
			const LV2_Atom_URID* urid = (const LV2_Atom_URID*)in;
			out = _forge.alloc_uri(_map.unmap_uri(urid->body));
		} else {
			out = _forge.alloc(in->size, in->type, LV2_ATOM_BODY(in));
		}
	}
}

void
AtomReader::get_props(const LV2_Atom_Object*       obj,
                      Ingen::Resource::Properties& props)
{
	LV2_ATOM_OBJECT_FOREACH(obj, p) {
		Raul::Atom val;
		get_uri(&p->value, val);
		props.insert(std::make_pair(_map.unmap_uri(p->key), val));
	}
}

void
AtomReader::write(const LV2_Atom* msg)
{
	if (msg->type != _uris.atom_Blank) {
		Raul::warn << "Unknown message type " << msg->type << std::endl;
		return;
	}

	const LV2_Atom_Object* obj     = (const LV2_Atom_Object*)msg;
	const LV2_Atom*        subject = NULL;

	lv2_atom_object_get(obj, (LV2_URID)_uris.patch_subject, &subject, NULL);
	const char* subject_uri = NULL;
	if (subject && subject->type == _uris.atom_URI) {
		subject_uri = (const char*)LV2_ATOM_BODY(subject);
	} else if (subject && subject->type == _uris.atom_URID) {
		subject_uri = _map.unmap_uri(((LV2_Atom_URID*)subject)->body);
	}

	if (obj->body.otype == _uris.patch_Get) {
		_iface.set_response_id(obj->body.id);
		_iface.get(subject_uri);
	} else if (obj->body.otype == _uris.patch_Delete) {
		if (subject_uri) {
			_iface.del(subject_uri);
			return;
		}

		const LV2_Atom_Object* body = NULL;
		lv2_atom_object_get(obj, (LV2_URID)_uris.patch_body, &body, 0);
		if (body && body->body.otype == _uris.ingen_Edge) {
			const LV2_Atom* tail = NULL;
			const LV2_Atom* head = NULL;
			lv2_atom_object_get(body,
			                    (LV2_URID)_uris.ingen_tail, &tail,
			                    (LV2_URID)_uris.ingen_head, &head,
			                    NULL);

			Raul::Atom tail_atom;
			Raul::Atom head_atom;
			get_uri(tail, tail_atom);
			get_uri(head, head_atom);
			if (tail_atom.is_valid() && head_atom.is_valid()) {
				_iface.disconnect(Raul::Path(tail_atom.get_uri()),
				                  Raul::Path(head_atom.get_uri()));
			} else {
				Raul::warn << "Delete of unknown object." << std::endl;
			}
		}
	} else if (obj->body.otype == _uris.patch_Put) {
		const LV2_Atom_Object* body = NULL;
		lv2_atom_object_get(obj, (LV2_URID)_uris.patch_body, &body, 0);
		if (!body) {
			Raul::warn << "Put message has no body" << std::endl;
			return;
		} else if (!subject_uri) {
			Raul::warn << "Put message has no subject" << std::endl;
			return;
		}

		if (body->body.otype == _uris.ingen_Edge) {
			LV2_Atom* tail = NULL;
			LV2_Atom* head = NULL;
			lv2_atom_object_get(body,
			                    (LV2_URID)_uris.ingen_tail, &tail,
			                    (LV2_URID)_uris.ingen_head, &head,
			                    NULL);
			if (!tail || !head) {
				Raul::warn << "Edge has no tail or head" << std::endl;
				return;
			}

			Raul::Atom tail_atom;
			Raul::Atom head_atom;
			get_uri(tail, tail_atom);
			get_uri(head, head_atom);
			_iface.connect(Raul::Path(tail_atom.get_uri()),
			               Raul::Path(head_atom.get_uri()));
		} else {
			Ingen::Resource::Properties props;
			get_props(body, props);
			_iface.set_response_id(obj->body.id);
			_iface.put(subject_uri, props);
		}
	} else if (obj->body.otype == _uris.patch_Patch) {
		if (!subject_uri) {
			Raul::warn << "Put message has no subject" << std::endl;
			return;
		}

		const LV2_Atom_Object* remove = NULL;
		lv2_atom_object_get(obj, (LV2_URID)_uris.patch_remove, &remove, 0);
		if (!remove) {
			Raul::warn << "Patch message has no remove" << std::endl;
			return;
		}

		const LV2_Atom_Object* add = NULL;
		lv2_atom_object_get(obj, (LV2_URID)_uris.patch_add, &add, 0);
		if (!add) {
			Raul::warn << "Patch message has no add" << std::endl;
			return;
		}

		Ingen::Resource::Properties add_props;
		get_props(remove, add_props);

		Ingen::Resource::Properties remove_props;
		get_props(remove, remove_props);

		_iface.delta(subject_uri, remove_props, add_props);
	} else {
		Raul::warn << "Unknown object type <"
		           << _map.unmap_uri(obj->body.otype)
		           << ">" << std::endl;
	}
}

} // namespace Shared
} // namespace Ingen
<commit_msg>Implement set_property via atom interface (working blinkenlights).<commit_after>/*
  This file is part of Ingen.
  Copyright 2007-2012 David Robillard <http://drobilla.net/>

  Ingen is free software: you can redistribute it and/or modify it under the
  terms of the GNU Affero General Public License as published by the Free
  Software Foundation, either version 3 of the License, or any later version.

  Ingen 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 Affero General Public License for details.

  You should have received a copy of the GNU Affero General Public License
  along with Ingen.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <utility>

#include "ingen/shared/AtomReader.hpp"
#include "lv2/lv2plug.in/ns/ext/atom/util.h"
#include "raul/Path.hpp"
#include "raul/log.hpp"

namespace Ingen {
namespace Shared {

AtomReader::AtomReader(LV2URIMap& map, URIs& uris, Forge& forge, Interface& iface)
	: _map(map)
	, _uris(uris)
	, _forge(forge)
	, _iface(iface)
{
}

void
AtomReader::get_uri(const LV2_Atom* in, Raul::Atom& out)
{
	if (in) {
		if (in->type == _uris.atom_URID) {
			const LV2_Atom_URID* urid = (const LV2_Atom_URID*)in;
			out = _forge.alloc_uri(_map.unmap_uri(urid->body));
		} else {
			out = _forge.alloc(in->size, in->type, LV2_ATOM_BODY(in));
		}
	}
}

void
AtomReader::get_props(const LV2_Atom_Object*       obj,
                      Ingen::Resource::Properties& props)
{
	LV2_ATOM_OBJECT_FOREACH(obj, p) {
		Raul::Atom val;
		get_uri(&p->value, val);
		props.insert(std::make_pair(_map.unmap_uri(p->key), val));
	}
}

void
AtomReader::write(const LV2_Atom* msg)
{
	if (msg->type != _uris.atom_Blank) {
		Raul::warn << "Unknown message type " << msg->type << std::endl;
		return;
	}

	const LV2_Atom_Object* obj     = (const LV2_Atom_Object*)msg;
	const LV2_Atom*        subject = NULL;

	lv2_atom_object_get(obj, (LV2_URID)_uris.patch_subject, &subject, NULL);
	const char* subject_uri = NULL;
	if (subject && subject->type == _uris.atom_URI) {
		subject_uri = (const char*)LV2_ATOM_BODY(subject);
	} else if (subject && subject->type == _uris.atom_URID) {
		subject_uri = _map.unmap_uri(((LV2_Atom_URID*)subject)->body);
	}

	if (obj->body.otype == _uris.patch_Get) {
		_iface.set_response_id(obj->body.id);
		_iface.get(subject_uri);
	} else if (obj->body.otype == _uris.patch_Delete) {
		if (subject_uri) {
			_iface.del(subject_uri);
			return;
		}

		const LV2_Atom_Object* body = NULL;
		lv2_atom_object_get(obj, (LV2_URID)_uris.patch_body, &body, 0);
		if (body && body->body.otype == _uris.ingen_Edge) {
			const LV2_Atom* tail = NULL;
			const LV2_Atom* head = NULL;
			lv2_atom_object_get(body,
			                    (LV2_URID)_uris.ingen_tail, &tail,
			                    (LV2_URID)_uris.ingen_head, &head,
			                    NULL);

			Raul::Atom tail_atom;
			Raul::Atom head_atom;
			get_uri(tail, tail_atom);
			get_uri(head, head_atom);
			if (tail_atom.is_valid() && head_atom.is_valid()) {
				_iface.disconnect(Raul::Path(tail_atom.get_uri()),
				                  Raul::Path(head_atom.get_uri()));
			} else {
				Raul::warn << "Delete of unknown object." << std::endl;
			}
		}
	} else if (obj->body.otype == _uris.patch_Put) {
		const LV2_Atom_Object* body = NULL;
		lv2_atom_object_get(obj, (LV2_URID)_uris.patch_body, &body, 0);
		if (!body) {
			Raul::warn << "Put message has no body" << std::endl;
			return;
		} else if (!subject_uri) {
			Raul::warn << "Put message has no subject" << std::endl;
			return;
		}

		if (body->body.otype == _uris.ingen_Edge) {
			LV2_Atom* tail = NULL;
			LV2_Atom* head = NULL;
			lv2_atom_object_get(body,
			                    (LV2_URID)_uris.ingen_tail, &tail,
			                    (LV2_URID)_uris.ingen_head, &head,
			                    NULL);
			if (!tail || !head) {
				Raul::warn << "Edge has no tail or head" << std::endl;
				return;
			}

			Raul::Atom tail_atom;
			Raul::Atom head_atom;
			get_uri(tail, tail_atom);
			get_uri(head, head_atom);
			_iface.connect(Raul::Path(tail_atom.get_uri()),
			               Raul::Path(head_atom.get_uri()));
		} else {
			Ingen::Resource::Properties props;
			get_props(body, props);
			_iface.set_response_id(obj->body.id);
			_iface.put(subject_uri, props);
		}
	} else if (obj->body.otype == _uris.patch_Set) {
		const LV2_Atom_Object* body = NULL;
		lv2_atom_object_get(obj, (LV2_URID)_uris.patch_body, &body, 0);
		if (!body) {
			Raul::warn << "Set message has no body" << std::endl;
			return;
		} else if (!subject_uri) {
			Raul::warn << "Set message has no subject" << std::endl;
			return;
		}

		LV2_ATOM_OBJECT_FOREACH(body, p) {
			Raul::Atom val;
			get_uri(&p->value, val);
			_iface.set_property(subject_uri, _map.unmap_uri(p->key), val);
		}
	} else if (obj->body.otype == _uris.patch_Patch) {
		if (!subject_uri) {
			Raul::warn << "Put message has no subject" << std::endl;
			return;
		}

		const LV2_Atom_Object* remove = NULL;
		lv2_atom_object_get(obj, (LV2_URID)_uris.patch_remove, &remove, 0);
		if (!remove) {
			Raul::warn << "Patch message has no remove" << std::endl;
			return;
		}

		const LV2_Atom_Object* add = NULL;
		lv2_atom_object_get(obj, (LV2_URID)_uris.patch_add, &add, 0);
		if (!add) {
			Raul::warn << "Patch message has no add" << std::endl;
			return;
		}

		Ingen::Resource::Properties add_props;
		get_props(remove, add_props);

		Ingen::Resource::Properties remove_props;
		get_props(remove, remove_props);

		_iface.delta(subject_uri, remove_props, add_props);
	} else {
		Raul::warn << "Unknown object type <"
		           << _map.unmap_uri(obj->body.otype)
		           << ">" << std::endl;
	}
}

} // namespace Shared
} // namespace Ingen
<|endoftext|>