<commit_before>/*
 * Copyright (c) 2012 Bernhard Firner and Rutgers University
 * All rights reserved.
 *
 * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 * or visit http://www.gnu.org/licenses/gpl-2.0.html
 */

/*******************************************************************************
 * @file binary_state_solver.cpp
 * Offer binary solutions to the world model based upon binary sensors,
 * such as door switches, on/off power switches, etc.
 *
 * @author Bernhard Firner
 ******************************************************************************/

#include <algorithm>
#include <array>
#include <fstream>
#include <iostream>
#include <map>
#include <string>
#include <time.h>
#include <utility>
#include <vector>
#include <sstream>

#include <owl/netbuffer.hpp>
#include <owl/solver_aggregator_connection.hpp>
#include <owl/solver_world_connection.hpp>
#include <owl/sample_data.hpp>
#include <owl/world_model_protocol.hpp>
#include <owl/grail_types.hpp>

#include <owl/client_world_connection.hpp>

using namespace aggregator_solver;

using std::pair;

using world_model::Attribute;
using world_model::grail_time;
using world_model::URI;

struct Debug {
  bool on;
};

template<typename T>
Debug& operator<<(Debug& dbg, T arg) {
  if (dbg.on) {
    std::cout<<arg;
  }
  return dbg;
}

std::u16string toU16(const std::string& str) {
  return std::u16string(str.begin(), str.end());
}

std::string toString(const std::u16string& str) {
  return std::string(str.begin(), str.end());
}

int main(int arg_count, char** arg_vector) {
  if (arg_count == 2 and std::string(arg_vector[1]) == "-?") {
    std::cout<< "name: Switch Solver\n";
    std::cout<< "arguments: aggregator agg_solver worldmodel wm_solver wm_client config_file\n";
    std::cout<< "description: Monitors status of simple on/off switches.\n";
    std::cout<< "requires: sensor\\.switch\n";
    std::cout<< "config_file: tuple 1 Region name.\n";
    std::cout<< "config_file: tuple* 2 An item class (eg. door) and the name for its state when the switch is on (eg. closed).\n";
    return 0;
  }

  if (7 > arg_count or (arg_count % 2) == 0) {
    std::cerr<<"This program needs 6 or more arguments:\n";
    std::cerr<<"\t"<<arg_vector[0]<<" [<aggregator ip> <aggregator port>]+ <world model ip> <solver port> <client port> <config file>\n\n";
    std::cerr<<"Any number of server ip/port pairs may be provided to connect to multiple servers.\n";
    std::cerr<<"Lines in the config file consist of the object class to track and the name of its switch status.\n";
    std::cerr<<"For instance: \"doors\" \"closed\"\n";
    return 0;
  }

  //Grab the ip and ports for the aggregators and world model
  std::vector<SolverAggregator::NetTarget> servers;
  for (int s_num = 1; s_num < arg_count - 4; s_num += 2) {
    std::string server_ip(arg_vector[s_num]);
    uint16_t server_port = std::stoi(std::string(arg_vector[s_num + 1]));
    servers.push_back(SolverAggregator::NetTarget{server_ip, server_port});
  }

  //World model IP and ports
  std::string wm_ip(arg_vector[arg_count - 4]);
  int solver_port = std::stoi(std::string((arg_vector[arg_count - 3])));
  int client_port = std::stoi(std::string((arg_vector[arg_count - 2])));

  //Set up the solver world model connection;
  std::string origin = "grail/switch_solver\nversion 1.0";

  //Read in type information from the config file
  //Types for the GRAIL world model will be read from the file
  std::vector<std::pair<std::u16string, bool>> type_pairs;

  //Remember what names correspond to what solutions and build a
  //query to find all objects of interest.
  //Use the object to solution map to map transmitters to URIs
  std::map<std::u16string, std::u16string> object_to_solution;
  std::map<pair<uint8_t, uint128_t>, URI> tx_to_uri;
  std::mutex tx_to_uri_mutex;

  std::ifstream config(arg_vector[arg_count-1]);
  if (not config.is_open()) {
    std::cerr<<"Error opening configuration file \""<<arg_vector[arg_count-1]<<"\"\n";
    return 1;
  }
  std::string line;
  //Read in each type and its corresponding name
  while (std::getline(config, line)) {
    std::istringstream is(line);
    std::string obj_class, solution;
    if (is >> obj_class >> solution) {
      //Each switch value is a single byte for on or off but the
      //solution name for each object class is different.
      //Safe this as a non-transient solution type
      //Change underlines into spaces.
      std::transform(obj_class.begin(), obj_class.end(), obj_class.begin(),
          [&](char c) { return c == '_' ? ' ' : c;});
      type_pairs.push_back(std::make_pair(toU16(solution), false));
      std::cerr<<"Class \""<<obj_class<<"\" has solution name \""<<solution<<'\n';
      object_to_solution[toU16(obj_class)] = toU16(solution);
    }
    else {
      std::cerr<<"Couldn't make sense of line: \""<<line<<"\"\n";
    }
  }
  config.close();

  if (object_to_solution.empty()) {
    std::cerr<<"There are no types in the config file - aborting.\n";
    return 1;
  }

  std::cerr<<"Trying to connect to world model as a solver.\n";
  SolverWorldModel swm(wm_ip, solver_port, type_pairs, toU16(origin));
  if (not swm.connected()) {
    std::cerr<<"Could not connect to the world model as a solver - aborting.\n";
    return 0;
  }

  std::cerr<<"Trying to connect to world model as a client.\n";
  ClientWorldConnection cwc(wm_ip, client_port);

  //Search for any IDs with names <anything>.obj_class.<anything>
  URI desired_ids = u".*\\.";
  if (object_to_solution.size() == 1) {
    desired_ids = u".*\\." + object_to_solution.begin()->first + u"\\..*";
  }
  else {
    desired_ids += u"(";
    for (auto I = object_to_solution.begin(); I != object_to_solution.end(); ++I) {
      //Insert a | (OR in regex) into the regex if this isn't the first object
      if (I != object_to_solution.begin()) {
        desired_ids += u"|";
      }
      desired_ids += I->first;
    }
    desired_ids += u")";
  }
  desired_ids += u"\\..*";

  //Search for any matching IDs with switch sensors
  std::vector<URI> attributes{u"sensor.switch.*"};
  //Update at most once a second
  world_model::grail_time interval = 1000;
  StepResponse sr = cwc.streamRequest(desired_ids, attributes, interval);

  //Subscription rules for the GRAIL aggregator
  //The transmitters to request will be discovered from the world model
  //We need to remember what transmitters we've already requested over here.
  std::map<uint8_t, Rule> phy_to_rule;
  std::map<URI, bool> switch_state;

  //Connect to the aggregator and update it with new rules as the world model
  //provided transmitters of interest
  auto packet_callback = [&](SampleData& s) {
    if (s.valid and 1 == s.sense_data.size()) {
      int switch_value = readPrimitive<uint8_t>(s.sense_data, 0);
      if (0 == switch_value or 255 == switch_value) {
        URI uri;
        {
          std::unique_lock<std::mutex> lck(tx_to_uri_mutex);
          uri = tx_to_uri[std::make_pair(s.physical_layer, s.tx_id)];
        }
        bool switch_on = 255 == switch_value;
        if (switch_state.end() == switch_state.find(uri) or switch_state[uri] != switch_on) {
          switch_state[uri] = switch_on;
          //Use the object to solution map to get the solution name.
          for (auto obj_soln = object_to_solution.begin(); obj_soln != object_to_solution.end(); ++obj_soln) {
            if (uri.find(u"." + obj_soln->first + u".") != std::u16string::npos) {
              SolverWorldModel::AttrUpdate soln{obj_soln->second, world_model::getGRAILTime(), uri, std::vector<uint8_t>()};
              pushBackVal<uint8_t>(switch_on ? 1 : 0, soln.data);
              std::vector<SolverWorldModel::AttrUpdate> solns{soln};
              //Send the data to the world model
              bool retry = true;
              while (retry) {
                try {
                  retry = false;
                  swm.sendData(solns, false);
                }
                catch (std::runtime_error& err) {
                  //Retry if this is just
                  if (err.what() == std::string("Error sending data over socket: Resource temporarily unavailable")) {
                    std::cerr<<"Experiencing socket slow down with world model connection. Retrying...\n";
                    retry = true;
                  }
                  //Otherwise keep throwing
                  else {
                    throw err;
                  }
                }
              }
              if (switch_on) {
                std::cout<<toString(uri)<<" is "<<toString(obj_soln->second)<<'\n';
              } else {
                std::cout<<toString(uri)<<" is not "<<toString(obj_soln->second)<<'\n';
              }
            }
          }
        }
      }
    }
  };
  SolverAggregator aggregator(servers, packet_callback);

  //Less than operator for two world model attributes
  auto attr_comp = [](const Attribute& a, const Attribute& b) {
    return (a.expiration_date != 0 or a.creation_date < b.creation_date); };
  std::cerr<<"Starting processing loop...\n";
  while (sr.hasNext()) {
    //Remember if we need to ask the aggregator for more information.
    bool new_transmitters = false;
    //Get world model updates
    world_model::WorldState ws = sr.next();
    //Check each object for switch sensor ID information
    for (const std::pair<URI, std::vector<Attribute>>& I : ws) {
      if (I.second.empty()) {
        std::cerr<<toString(I.first)<<" is an empty object.\n";
      }
      else {
        Attribute newest = *(std::max_element(I.second.begin(), I.second.end(), attr_comp));
        if (newest.expiration_date != 0) {
          //TODO FIXME This attribute has been expired so stop updating the
          //status of this ID in the world model
        }
        //Otherwise, make sure that we have signed up for this sensor's data
        //from the aggregators

        //Transmitters are stored as one byte of physical layer and 16 bytes of ID
        grail_types::transmitter tx_switch = grail_types::readTransmitter(newest.data);
        if (phy_to_rule.find(tx_switch.phy) == phy_to_rule.end()) {
          phy_to_rule[tx_switch.phy].physical_layer  = tx_switch.phy;
          phy_to_rule[tx_switch.phy].update_interval = 1000;
        }
        //See if this is a new transmitter
        auto tx_present = [&](const Transmitter& tx) {return tx.base_id == tx_switch.id;};

        std::vector<Transmitter>& phy_txers = phy_to_rule[tx_switch.phy].txers;
        if (phy_txers.end() == std::find_if(phy_txers.begin(), phy_txers.end(), tx_present)) {
          std::cerr<<"Requesting aggregator data for new transmitter "<<tx_switch.id<<" on device "<<toString(I.first)<<'\n';
          //Mark that we are making a change to the aggregator rules.
          new_transmitters = true;
          //Only accept data from sensors that we care about
          Transmitter sensor_id;
          sensor_id.base_id = tx_switch.id;
          sensor_id.mask.upper = 0xFFFFFFFFFFFFFFFF;
          sensor_id.mask.lower = 0xFFFFFFFFFFFFFFFF;
          phy_txers.push_back(sensor_id);
          //Also map this transmitter's ID to the object it corresponds to in the world model
          {
            std::unique_lock<std::mutex> lck(tx_to_uri_mutex);
            tx_to_uri[std::make_pair(tx_switch.phy, tx_switch.id)] = I.first;
          }
        }
      }
    }
    //Make new subscriptions to the aggregator if there are new transmitters
    if (new_transmitters) {
      Subscription sub;
      for (auto phy_rule : phy_to_rule) {
        sub.push_back(phy_rule.second);
      }
      std::cerr<<"Sending new rules to the aggregator.\n";
      aggregator.addRules(sub);
    }
  }
}

<commit_msg>Changing origin name (removing new lines).<commit_after>/*
 * Copyright (c) 2012 Bernhard Firner and Rutgers University
 * All rights reserved.
 *
 * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 * or visit http://www.gnu.org/licenses/gpl-2.0.html
 */

/*******************************************************************************
 * @file binary_state_solver.cpp
 * Offer binary solutions to the world model based upon binary sensors,
 * such as door switches, on/off power switches, etc.
 *
 * @author Bernhard Firner
 ******************************************************************************/

#include <algorithm>
#include <array>
#include <fstream>
#include <iostream>
#include <map>
#include <string>
#include <time.h>
#include <utility>
#include <vector>
#include <sstream>

#include <owl/netbuffer.hpp>
#include <owl/solver_aggregator_connection.hpp>
#include <owl/solver_world_connection.hpp>
#include <owl/sample_data.hpp>
#include <owl/world_model_protocol.hpp>
#include <owl/grail_types.hpp>

#include <owl/client_world_connection.hpp>

using namespace aggregator_solver;

using std::pair;

using world_model::Attribute;
using world_model::grail_time;
using world_model::URI;

struct Debug {
  bool on;
};

template<typename T>
Debug& operator<<(Debug& dbg, T arg) {
  if (dbg.on) {
    std::cout<<arg;
  }
  return dbg;
}

std::u16string toU16(const std::string& str) {
  return std::u16string(str.begin(), str.end());
}

std::string toString(const std::u16string& str) {
  return std::string(str.begin(), str.end());
}

int main(int arg_count, char** arg_vector) {
  if (arg_count == 2 and std::string(arg_vector[1]) == "-?") {
    std::cout<< "name: Switch Solver\n";
    std::cout<< "arguments: aggregator agg_solver worldmodel wm_solver wm_client config_file\n";
    std::cout<< "description: Monitors status of simple on/off switches.\n";
    std::cout<< "requires: sensor\\.switch\n";
    std::cout<< "config_file: tuple 1 Region name.\n";
    std::cout<< "config_file: tuple* 2 An item class (eg. door) and the name for its state when the switch is on (eg. closed).\n";
    return 0;
  }

  if (7 > arg_count or (arg_count % 2) == 0) {
    std::cerr<<"This program needs 6 or more arguments:\n";
    std::cerr<<"\t"<<arg_vector[0]<<" [<aggregator ip> <aggregator port>]+ <world model ip> <solver port> <client port> <config file>\n\n";
    std::cerr<<"Any number of server ip/port pairs may be provided to connect to multiple servers.\n";
    std::cerr<<"Lines in the config file consist of the object class to track and the name of its switch status.\n";
    std::cerr<<"For instance: \"doors\" \"closed\"\n";
    return 0;
  }

  //Grab the ip and ports for the aggregators and world model
  std::vector<SolverAggregator::NetTarget> servers;
  for (int s_num = 1; s_num < arg_count - 4; s_num += 2) {
    std::string server_ip(arg_vector[s_num]);
    uint16_t server_port = std::stoi(std::string(arg_vector[s_num + 1]));
    servers.push_back(SolverAggregator::NetTarget{server_ip, server_port});
  }

  //World model IP and ports
  std::string wm_ip(arg_vector[arg_count - 4]);
  int solver_port = std::stoi(std::string((arg_vector[arg_count - 3])));
  int client_port = std::stoi(std::string((arg_vector[arg_count - 2])));

  //Set up the solver world model connection;
  std::string origin = "binary_state_solver";

  //Read in type information from the config file
  //Types for the GRAIL world model will be read from the file
  std::vector<std::pair<std::u16string, bool>> type_pairs;

  //Remember what names correspond to what solutions and build a
  //query to find all objects of interest.
  //Use the object to solution map to map transmitters to URIs
  std::map<std::u16string, std::u16string> object_to_solution;
  std::map<pair<uint8_t, uint128_t>, URI> tx_to_uri;
  std::mutex tx_to_uri_mutex;

  std::ifstream config(arg_vector[arg_count-1]);
  if (not config.is_open()) {
    std::cerr<<"Error opening configuration file \""<<arg_vector[arg_count-1]<<"\"\n";
    return 1;
  }
  std::string line;
  //Read in each type and its corresponding name
  while (std::getline(config, line)) {
    std::istringstream is(line);
    std::string obj_class, solution;
    if (is >> obj_class >> solution) {
      //Each switch value is a single byte for on or off but the
      //solution name for each object class is different.
      //Safe this as a non-transient solution type
      //Change underlines into spaces.
      std::transform(obj_class.begin(), obj_class.end(), obj_class.begin(),
          [&](char c) { return c == '_' ? ' ' : c;});
      type_pairs.push_back(std::make_pair(toU16(solution), false));
      std::cerr<<"Class \""<<obj_class<<"\" has solution name \""<<solution<<'\n';
      object_to_solution[toU16(obj_class)] = toU16(solution);
    }
    else {
      std::cerr<<"Couldn't make sense of line: \""<<line<<"\"\n";
    }
  }
  config.close();

  if (object_to_solution.empty()) {
    std::cerr<<"There are no types in the config file - aborting.\n";
    return 1;
  }

  std::cerr<<"Trying to connect to world model as a solver.\n";
  SolverWorldModel swm(wm_ip, solver_port, type_pairs, toU16(origin));
  if (not swm.connected()) {
    std::cerr<<"Could not connect to the world model as a solver - aborting.\n";
    return 0;
  }

  std::cerr<<"Trying to connect to world model as a client.\n";
  ClientWorldConnection cwc(wm_ip, client_port);

  //Search for any IDs with names <anything>.obj_class.<anything>
  URI desired_ids = u".*\\.";
  if (object_to_solution.size() == 1) {
    desired_ids = u".*\\." + object_to_solution.begin()->first + u"\\..*";
  }
  else {
    desired_ids += u"(";
    for (auto I = object_to_solution.begin(); I != object_to_solution.end(); ++I) {
      //Insert a | (OR in regex) into the regex if this isn't the first object
      if (I != object_to_solution.begin()) {
        desired_ids += u"|";
      }
      desired_ids += I->first;
    }
    desired_ids += u")";
  }
  desired_ids += u"\\..*";

  //Search for any matching IDs with switch sensors
  std::vector<URI> attributes{u"sensor.switch.*"};
  //Update at most once a second
  world_model::grail_time interval = 1000;
  StepResponse sr = cwc.streamRequest(desired_ids, attributes, interval);

  //Subscription rules for the GRAIL aggregator
  //The transmitters to request will be discovered from the world model
  //We need to remember what transmitters we've already requested over here.
  std::map<uint8_t, Rule> phy_to_rule;
  std::map<URI, bool> switch_state;

  //Connect to the aggregator and update it with new rules as the world model
  //provided transmitters of interest
  auto packet_callback = [&](SampleData& s) {
    if (s.valid and 1 == s.sense_data.size()) {
      int switch_value = readPrimitive<uint8_t>(s.sense_data, 0);
      if (0 == switch_value or 255 == switch_value) {
        URI uri;
        {
          std::unique_lock<std::mutex> lck(tx_to_uri_mutex);
          uri = tx_to_uri[std::make_pair(s.physical_layer, s.tx_id)];
        }
        bool switch_on = 255 == switch_value;
        if (switch_state.end() == switch_state.find(uri) or switch_state[uri] != switch_on) {
          switch_state[uri] = switch_on;
          //Use the object to solution map to get the solution name.
          for (auto obj_soln = object_to_solution.begin(); obj_soln != object_to_solution.end(); ++obj_soln) {
            if (uri.find(u"." + obj_soln->first + u".") != std::u16string::npos) {
              SolverWorldModel::AttrUpdate soln{obj_soln->second, world_model::getGRAILTime(), uri, std::vector<uint8_t>()};
              pushBackVal<uint8_t>(switch_on ? 1 : 0, soln.data);
              std::vector<SolverWorldModel::AttrUpdate> solns{soln};
              //Send the data to the world model
              bool retry = true;
              while (retry) {
                try {
                  retry = false;
                  swm.sendData(solns, false);
                }
                catch (std::runtime_error& err) {
                  //Retry if this is just
                  if (err.what() == std::string("Error sending data over socket: Resource temporarily unavailable")) {
                    std::cerr<<"Experiencing socket slow down with world model connection. Retrying...\n";
                    retry = true;
                  }
                  //Otherwise keep throwing
                  else {
                    throw err;
                  }
                }
              }
              if (switch_on) {
                std::cout<<toString(uri)<<" is "<<toString(obj_soln->second)<<'\n';
              } else {
                std::cout<<toString(uri)<<" is not "<<toString(obj_soln->second)<<'\n';
              }
            }
          }
        }
      }
    }
  };
  SolverAggregator aggregator(servers, packet_callback);

  //Less than operator for two world model attributes
  auto attr_comp = [](const Attribute& a, const Attribute& b) {
    return (a.expiration_date != 0 or a.creation_date < b.creation_date); };
  std::cerr<<"Starting processing loop...\n";
  while (sr.hasNext()) {
    //Remember if we need to ask the aggregator for more information.
    bool new_transmitters = false;
    //Get world model updates
    world_model::WorldState ws = sr.next();
    //Check each object for switch sensor ID information
    for (const std::pair<URI, std::vector<Attribute>>& I : ws) {
      if (I.second.empty()) {
        std::cerr<<toString(I.first)<<" is an empty object.\n";
      }
      else {
        Attribute newest = *(std::max_element(I.second.begin(), I.second.end(), attr_comp));
        if (newest.expiration_date != 0) {
          //TODO FIXME This attribute has been expired so stop updating the
          //status of this ID in the world model
        }
        //Otherwise, make sure that we have signed up for this sensor's data
        //from the aggregators

        //Transmitters are stored as one byte of physical layer and 16 bytes of ID
        grail_types::transmitter tx_switch = grail_types::readTransmitter(newest.data);
        if (phy_to_rule.find(tx_switch.phy) == phy_to_rule.end()) {
          phy_to_rule[tx_switch.phy].physical_layer  = tx_switch.phy;
          phy_to_rule[tx_switch.phy].update_interval = 1000;
        }
        //See if this is a new transmitter
        auto tx_present = [&](const Transmitter& tx) {return tx.base_id == tx_switch.id;};

        std::vector<Transmitter>& phy_txers = phy_to_rule[tx_switch.phy].txers;
        if (phy_txers.end() == std::find_if(phy_txers.begin(), phy_txers.end(), tx_present)) {
          std::cerr<<"Requesting aggregator data for new transmitter "<<tx_switch.id<<" on device "<<toString(I.first)<<'\n';
          //Mark that we are making a change to the aggregator rules.
          new_transmitters = true;
          //Only accept data from sensors that we care about
          Transmitter sensor_id;
          sensor_id.base_id = tx_switch.id;
          sensor_id.mask.upper = 0xFFFFFFFFFFFFFFFF;
          sensor_id.mask.lower = 0xFFFFFFFFFFFFFFFF;
          phy_txers.push_back(sensor_id);
          //Also map this transmitter's ID to the object it corresponds to in the world model
          {
            std::unique_lock<std::mutex> lck(tx_to_uri_mutex);
            tx_to_uri[std::make_pair(tx_switch.phy, tx_switch.id)] = I.first;
          }
        }
      }
    }
    //Make new subscriptions to the aggregator if there are new transmitters
    if (new_transmitters) {
      Subscription sub;
      for (auto phy_rule : phy_to_rule) {
        sub.push_back(phy_rule.second);
      }
      std::cerr<<"Sending new rules to the aggregator.\n";
      aggregator.addRules(sub);
    }
  }
}

<|endoftext|>


<commit_before>#include <map>

#include <llvm/IR/Value.h>
#include <llvm/IR/Instruction.h>
#include <llvm/IR/Instructions.h>
#include <llvm/IR/Constants.h>
#include <llvm/IR/GlobalVariable.h>
#include <llvm/IR/Module.h>
#include <llvm/Support/raw_ostream.h>

#include "LLVMNode.h"
#include "LLVMDependenceGraph.h"
#include "DefUse.h"
#include "AnalysisGeneric.h"

#include "analysis/DFS.h"

using namespace llvm;

namespace dg {
namespace analysis {

LLVMDefUseAnalysis::LLVMDefUseAnalysis(LLVMDependenceGraph *dg)
    : DataFlowAnalysis<LLVMNode>(dg->getEntryBB(), DATAFLOW_INTERPROCEDURAL),
      dg(dg)
{
    Module *m = dg->getModule();
    // set data layout
    DL = m->getDataLayout();
}

Pointer LLVMDefUseAnalysis::getConstantExprPointer(const ConstantExpr *CE)
{
    return dg::analysis::getConstantExprPointer(CE, dg, DL);
}

DefMap::DefMap(const DefMap& o)
{
    merge(&o);
}

bool DefMap::merge(const DefMap *oth, PointsToSetT *without)
{
    bool changed = false;

    if (this == oth)
        return false;

    for (auto it : oth->defs) {
        const Pointer& ptr = it.first;

        // should we skip this pointer
        if (without && without->count(ptr) != 0)
            continue;

        // our values that we have for
        // this pointer
        ValuesSetT& our_vals = defs[ptr];

        // copy values that have map oth for the
        // pointer to our values
        for (LLVMNode *defnode : it.second) {
            changed |= our_vals.insert(defnode).second;
        }
    }

    return changed;
}

bool DefMap::add(const Pointer& p, LLVMNode *n)
{
    return defs[p].insert(n).second;
}

bool DefMap::update(const Pointer& p, LLVMNode *n)
{
    bool ret;
    ValuesSetT& dfs = defs[p];

    ret = dfs.count(n) == 0 || dfs.size() > 1;
    dfs.clear();
    dfs.insert(n);

    return ret;
}

static DefMap *getDefMap(LLVMNode *n)
{
    DefMap *r = n->getData<DefMap>();
    if (!r) {
        r = new DefMap();
        n->setData(r);
    }

    // must always have
    assert(r);

    return r;
}

/// --------------------------------------------------
//   Reaching definitions analysis
/// --------------------------------------------------

static bool handleStoreInst(const StoreInst *Inst, LLVMNode *node,
                            PointsToSetT *&strong_update)
{
    bool changed = false;
    LLVMNode *ptrNode = node->getOperand(0);
    assert(ptrNode && "No pointer operand");

    (void) Inst;

    // update definitions
    DefMap *df = getDefMap(node);
    PointsToSetT& S = ptrNode->getPointsTo();

    if (S.size() == 1) {// strong update
        changed |= df->update(*S.begin(), node);
        strong_update = &S;
    } else { // weak update
        for (const Pointer& ptr : ptrNode->getPointsTo())
            changed |= df->add(ptr, node);
    }

    return changed;
}

bool LLVMDefUseAnalysis::runOnNode(LLVMNode *node)
{
    bool changed = false;
    const Value *val = node->getKey();
    // pointers that should not be updated
    // because they were updated strongly
    PointsToSetT *strong_update = nullptr;

    if (const StoreInst *Inst = dyn_cast<StoreInst>(val)) {
        changed |= handleStoreInst(Inst, node, strong_update);
    }

    // update states according to predcessors
    DefMap *df = getDefMap(node);
    LLVMNode *pred = node->getPredcessor();
    if (pred) {
        changed |= df->merge(getDefMap(pred), strong_update);
    } else { // BB predcessors
        LLVMBBlock *BB = node->getBasicBlock();
        assert(BB && "Node has no BB");

        for (auto predBB : BB->predcessors()) {
            pred = predBB->getLastNode();
            assert(pred && "BB has no last node");

            df->merge(getDefMap(pred), strong_update);
        }
    }

    return changed;
}

} // namespace analysis
} // namespace dg

/// --------------------------------------------------
//   Add def-use edges
/// --------------------------------------------------
namespace dg {
namespace analysis {

static void addIndirectDefUsePtr(const Pointer& ptr, LLVMNode *to, DefMap *df)
{
    ValuesSetT& defs = df->get(ptr);
    // do we have any reaching definition at all?
    if (defs.empty()) {
        // we do not add initial def to global variables because not all
        // global variables could be used in the code and we'd redundantly
        // iterate through the defintions. Do it lazily here.
        LLVMNode *ptrnode = ptr.obj->node;
        if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(ptrnode->getKey())) {
            if (GV->hasInitializer()) {
                // ok, so the GV was defined in initialization phase,
                // so the reaching definition for the ptr is there
                defs.insert(ptrnode);
            }
        } else {
            errs() << "WARN: no reaching definition for " << *ptr.obj->node->getKey()
                   << " + " << *ptr.offset << "\n";
            return;
        }
    }

    // we read ptrNode memory that is defined on these locations
    assert(!defs.empty());
    for (LLVMNode *n : defs)
        n->addDataDependence(to);
}

static void addIndirectDefUse(LLVMNode *ptrNode, LLVMNode *to, DefMap *df)
{
    // iterate over all memory locations that this
    // store can define and check where they are defined
    for (const Pointer& ptr : ptrNode->getPointsTo())
        addIndirectDefUsePtr(ptr, to, df);
}

void LLVMDefUseAnalysis::handleLoadInst(const LoadInst *Inst, LLVMNode *node)
{
    DefMap *df = getDefMap(node);
    LLVMNode *ptrNode = node->getOperand(0);
    const Value *valOp = Inst->getPointerOperand();

    // handle ConstantExpr
    if (!ptrNode) {
        if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(valOp)) {
            const Pointer ptr = getConstantExprPointer(CE);
            addIndirectDefUsePtr(ptr, node, df);
        } else {
            errs() << "ERR: Unhandled LoadInst operand " << *Inst << "\n";
            abort();
        }
    } else {
        // we use the top-level value that is defined
        // on ptrNode
        ptrNode->addDataDependence(node);

        addIndirectDefUse(ptrNode, node, df);
    }
}

static void handleCallInst(LLVMNode *node)
{
    DefMap *df = getDefMap(node);
    LLVMNode **operands = node->getOperands();
    LLVMDGParameters *params = node->getParameters();

    if (!params) // function has no arguments
        return;

    for (int i = 0, e = node->getOperandsNum(); i < e; ++i) {
        LLVMNode *op = operands[i];
        if (!op)
            continue;

        LLVMDGParameter *p = params->find(op->getKey());
        if (!p) {
            errs() << "ERR: no actual parameter for " << *op->getKey() << "\n";
            continue;
        }

        if (op->isPointerTy()) {
            // add data dependencies to in parameters
            addIndirectDefUse(op, p->in, df);

            // FIXME
            // look for reaching definitions inside the procedure
            // because since this is a pointer, we can change things
        } else
            op->addDataDependence(p->in);
    }

    // if the called function returns a value,
    // make this node data dependent on that
    if (!node->isVoidTy()) {
        for (auto sub : node->getSubgraphs())
            sub->getExit()->addDataDependence(node);
    }
}

static void handleInstruction(const Instruction *Inst, LLVMNode *node)
{
    LLVMDependenceGraph *dg = node->getDG();

    for (auto I = Inst->op_begin(), E = Inst->op_end(); I != E; ++I) {
        LLVMNode *op = dg->getNode(*I);
        if (op)
            op->addDataDependence(node);
        else if (!isa<Constant>(*I) && !isa<BranchInst>(Inst))
            errs() << "WARN: no node for operand " << **I
                   << "in " << *Inst << "\n";
    }
}

void LLVMDefUseAnalysis::handleNode(LLVMNode *node)
{
    const Value *val = node->getKey();

    if (const LoadInst *Inst = dyn_cast<LoadInst>(val)) {
        handleLoadInst(Inst, node);
    } else if (isa<CallInst>(val)) {
        handleCallInst(node);
    } else if (const Instruction *Inst = dyn_cast<Instruction>(val)) {
        handleInstruction(Inst, node); // handle rest of Insts
    }
}

void handleBlock(LLVMBBlock *BB, LLVMDefUseAnalysis *analysis)
{
    LLVMNode *n = BB->getFirstNode();
    while (n) {
        analysis->handleNode(n);
        n = n->getSuccessor();
    }
}

void LLVMDefUseAnalysis::addDefUseEdges()
{
    // it doesn't matter how we'll go through the nodes
    BBlockDFS<LLVMNode> runner(DFS_INTERPROCEDURAL);
    runner.run(dg->getEntryBB(), handleBlock, this);
}

} // namespace analysis
} // namespace dg
<commit_msg>Revert "def-use: remove special handler for StoreInst"<commit_after>#include <map>

#include <llvm/IR/Value.h>
#include <llvm/IR/Instruction.h>
#include <llvm/IR/Instructions.h>
#include <llvm/IR/Constants.h>
#include <llvm/IR/GlobalVariable.h>
#include <llvm/IR/Module.h>
#include <llvm/Support/raw_ostream.h>

#include "LLVMNode.h"
#include "LLVMDependenceGraph.h"
#include "DefUse.h"
#include "AnalysisGeneric.h"

#include "analysis/DFS.h"

using namespace llvm;

namespace dg {
namespace analysis {

LLVMDefUseAnalysis::LLVMDefUseAnalysis(LLVMDependenceGraph *dg)
    : DataFlowAnalysis<LLVMNode>(dg->getEntryBB(), DATAFLOW_INTERPROCEDURAL),
      dg(dg)
{
    Module *m = dg->getModule();
    // set data layout
    DL = m->getDataLayout();
}

Pointer LLVMDefUseAnalysis::getConstantExprPointer(const ConstantExpr *CE)
{
    return dg::analysis::getConstantExprPointer(CE, dg, DL);
}

DefMap::DefMap(const DefMap& o)
{
    merge(&o);
}

bool DefMap::merge(const DefMap *oth, PointsToSetT *without)
{
    bool changed = false;

    if (this == oth)
        return false;

    for (auto it : oth->defs) {
        const Pointer& ptr = it.first;

        // should we skip this pointer
        if (without && without->count(ptr) != 0)
            continue;

        // our values that we have for
        // this pointer
        ValuesSetT& our_vals = defs[ptr];

        // copy values that have map oth for the
        // pointer to our values
        for (LLVMNode *defnode : it.second) {
            changed |= our_vals.insert(defnode).second;
        }
    }

    return changed;
}

bool DefMap::add(const Pointer& p, LLVMNode *n)
{
    return defs[p].insert(n).second;
}

bool DefMap::update(const Pointer& p, LLVMNode *n)
{
    bool ret;
    ValuesSetT& dfs = defs[p];

    ret = dfs.count(n) == 0 || dfs.size() > 1;
    dfs.clear();
    dfs.insert(n);

    return ret;
}

static DefMap *getDefMap(LLVMNode *n)
{
    DefMap *r = n->getData<DefMap>();
    if (!r) {
        r = new DefMap();
        n->setData(r);
    }

    // must always have
    assert(r);

    return r;
}

/// --------------------------------------------------
//   Reaching definitions analysis
/// --------------------------------------------------

static bool handleStoreInst(const StoreInst *Inst, LLVMNode *node,
                            PointsToSetT *&strong_update)
{
    bool changed = false;
    LLVMNode *ptrNode = node->getOperand(0);
    assert(ptrNode && "No pointer operand");

    (void) Inst;

    // update definitions
    DefMap *df = getDefMap(node);
    PointsToSetT& S = ptrNode->getPointsTo();

    if (S.size() == 1) {// strong update
        changed |= df->update(*S.begin(), node);
        strong_update = &S;
    } else { // weak update
        for (const Pointer& ptr : ptrNode->getPointsTo())
            changed |= df->add(ptr, node);
    }

    return changed;
}

bool LLVMDefUseAnalysis::runOnNode(LLVMNode *node)
{
    bool changed = false;
    const Value *val = node->getKey();
    // pointers that should not be updated
    // because they were updated strongly
    PointsToSetT *strong_update = nullptr;

    if (const StoreInst *Inst = dyn_cast<StoreInst>(val)) {
        changed |= handleStoreInst(Inst, node, strong_update);
    }

    // update states according to predcessors
    DefMap *df = getDefMap(node);
    LLVMNode *pred = node->getPredcessor();
    if (pred) {
        changed |= df->merge(getDefMap(pred), strong_update);
    } else { // BB predcessors
        LLVMBBlock *BB = node->getBasicBlock();
        assert(BB && "Node has no BB");

        for (auto predBB : BB->predcessors()) {
            pred = predBB->getLastNode();
            assert(pred && "BB has no last node");

            df->merge(getDefMap(pred), strong_update);
        }
    }

    return changed;
}

} // namespace analysis
} // namespace dg

/// --------------------------------------------------
//   Add def-use edges
/// --------------------------------------------------
namespace dg {
namespace analysis {

static void handleStoreInst(LLVMNode *node)
{
    // we have only top-level dependencies here

    LLVMNode *valNode = node->getOperand(1);
    // this node uses what is defined on valNode
    if (valNode)
        valNode->addDataDependence(node);

    // and also uses what is defined on ptrNode
    LLVMNode *ptrNode = node->getOperand(0);
    ptrNode->addDataDependence(node);
}

static void addIndirectDefUsePtr(const Pointer& ptr, LLVMNode *to, DefMap *df)
{
    ValuesSetT& defs = df->get(ptr);
    // do we have any reaching definition at all?
    if (defs.empty()) {
        // we do not add initial def to global variables because not all
        // global variables could be used in the code and we'd redundantly
        // iterate through the defintions. Do it lazily here.
        LLVMNode *ptrnode = ptr.obj->node;
        if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(ptrnode->getKey())) {
            if (GV->hasInitializer()) {
                // ok, so the GV was defined in initialization phase,
                // so the reaching definition for the ptr is there
                defs.insert(ptrnode);
            }
        } else {
            errs() << "WARN: no reaching definition for " << *ptr.obj->node->getKey()
                   << " + " << *ptr.offset << "\n";
            return;
        }
    }

    // we read ptrNode memory that is defined on these locations
    assert(!defs.empty());
    for (LLVMNode *n : defs)
        n->addDataDependence(to);
}

static void addIndirectDefUse(LLVMNode *ptrNode, LLVMNode *to, DefMap *df)
{
    // iterate over all memory locations that this
    // store can define and check where they are defined
    for (const Pointer& ptr : ptrNode->getPointsTo())
        addIndirectDefUsePtr(ptr, to, df);
}

void LLVMDefUseAnalysis::handleLoadInst(const LoadInst *Inst, LLVMNode *node)
{
    DefMap *df = getDefMap(node);
    LLVMNode *ptrNode = node->getOperand(0);
    const Value *valOp = Inst->getPointerOperand();

    // handle ConstantExpr
    if (!ptrNode) {
        if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(valOp)) {
            const Pointer ptr = getConstantExprPointer(CE);
            addIndirectDefUsePtr(ptr, node, df);
        } else {
            errs() << "ERR: Unhandled LoadInst operand " << *Inst << "\n";
            abort();
        }
    } else {
        // we use the top-level value that is defined
        // on ptrNode
        ptrNode->addDataDependence(node);

        addIndirectDefUse(ptrNode, node, df);
    }
}

static void handleCallInst(LLVMNode *node)
{
    DefMap *df = getDefMap(node);
    LLVMNode **operands = node->getOperands();
    LLVMDGParameters *params = node->getParameters();

    if (!params) // function has no arguments
        return;

    for (int i = 0, e = node->getOperandsNum(); i < e; ++i) {
        LLVMNode *op = operands[i];
        if (!op)
            continue;

        LLVMDGParameter *p = params->find(op->getKey());
        if (!p) {
            errs() << "ERR: no actual parameter for " << *op->getKey() << "\n";
            continue;
        }

        if (op->isPointerTy()) {
            // add data dependencies to in parameters
            addIndirectDefUse(op, p->in, df);

            // FIXME
            // look for reaching definitions inside the procedure
            // because since this is a pointer, we can change things
        } else
            op->addDataDependence(p->in);
    }

    // if the called function returns a value,
    // make this node data dependent on that
    if (!node->isVoidTy()) {
        for (auto sub : node->getSubgraphs())
            sub->getExit()->addDataDependence(node);
    }
}

static void handleInstruction(const Instruction *Inst, LLVMNode *node)
{
    LLVMDependenceGraph *dg = node->getDG();

    for (auto I = Inst->op_begin(), E = Inst->op_end(); I != E; ++I) {
        LLVMNode *op = dg->getNode(*I);
        if (op)
            op->addDataDependence(node);
        else if (!isa<ConstantInt>(*I) && !isa<BranchInst>(Inst))
            errs() << "WARN: no node for operand " << **I
                   << "in " << *Inst << "\n";
    }
}

void LLVMDefUseAnalysis::handleNode(LLVMNode *node)
{
    const Value *val = node->getKey();

    if (isa<StoreInst>(val)) {
        handleStoreInst(node);
    } else if (const LoadInst *Inst = dyn_cast<LoadInst>(val)) {
        handleLoadInst(Inst, node);
    } else if (isa<CallInst>(val)) {
        handleCallInst(node);
    } else if (const Instruction *Inst = dyn_cast<Instruction>(val)) {
        handleInstruction(Inst, node); // handle rest of Insts
    }
}

void handleBlock(LLVMBBlock *BB, LLVMDefUseAnalysis *analysis)
{
    LLVMNode *n = BB->getFirstNode();
    while (n) {
        analysis->handleNode(n);
        n = n->getSuccessor();
    }
}

void LLVMDefUseAnalysis::addDefUseEdges()
{
    // it doesn't matter how we'll go through the nodes
    BBlockDFS<LLVMNode> runner(DFS_INTERPROCEDURAL);
    runner.run(dg->getEntryBB(), handleBlock, this);
}

} // namespace analysis
} // namespace dg
<|endoftext|>


<commit_before>// Known bugs:
//  * Volume on a logarithmic scale
//  * _buffer must be made thread-safe

#include "MPDMessageHandler.h"
#include "common.h"
#include "StringUtil.h"
#include "PlaybackCommandHandler.h"
#include "PlaylistCommandHandler.h"
#include "GeneralCommandHandler.h"
#include "DataRequestHandler.h"
#include "Timer.h"
#include <algorithm>
#include <functional>
#include <fstream>
#include <string>
#include <unordered_map>

namespace foo_mpdsrv
{
	MPDMessageHandler::MPDMessageHandler(MPDMessageHandler&& right) : _sender(std::move(right._sender)),
		_actions(std::move(right._actions)),
		_activeHandleCommandRoutine(&MPDMessageHandler::HandleCommandOnly)
	{
		TRACK_CALL_TEXT("MPDMessageHandler::MPDMessageHandler(&&)");
	}

	MPDMessageHandler::MPDMessageHandler(SOCKET connection) : _sender(connection)
	{
		TRACK_CALL_TEXT("MPDMessageHandler::MPDMessageHandler(socket)");
		_actions.insert(std::make_pair("ping", &HandlePing));
		_actions.insert(std::make_pair("pause", &HandlePause));
		_actions.insert(std::make_pair("play", &HandlePlay));
		_actions.insert(std::make_pair("playid", &HandlePlayId));
		_actions.insert(std::make_pair("stop", &HandleStop));
		_actions.insert(std::make_pair("next", &HandleNext));
		_actions.insert(std::make_pair("previous", &HandlePrevious));
		_actions.insert(std::make_pair("playlistinfo", &HandlePlaylistinfo));
		_actions.insert(std::make_pair("listplaylistinfo", &HandleListplaylistinfo));
		_actions.insert(std::make_pair("lsinfo", &HandleLsinfo));
		_actions.insert(std::make_pair("currentsong", &HandleCurrentsong));
		_actions.insert(std::make_pair("plchanges", &HandlePlchanges));
		_actions.insert(std::make_pair("status", &HandleStatus));
		_actions.insert(std::make_pair("stats", &HandleStats));
		_actions.insert(std::make_pair("outputs", &HandleOutputs));
		_actions.insert(std::make_pair("close", &HandleClose));
		_actions.insert(std::make_pair("volume", &HandleVolume));
		_actions.insert(std::make_pair("setvol", &HandleVolume));
	}

	MPDMessageHandler::~MPDMessageHandler()
	{
		TRACK_CALL_TEXT("MPDMessageHandler::~MPDMessageHandler()");
#ifdef FOO_MPDSRV_THREADED
		ExitThread();
		WaitTillThreadDone();
#endif
	}

	void MPDMessageHandler::PushBuffer(const char* buf, size_t numBytes)
	{
		TRACK_CALL_TEXT("MPDMessageHandler::PushBuffer()");
		_buffer.insert(_buffer.end(), buf, buf + numBytes);
#ifdef FOO_MPDSRV_THREADED
		Wake();
#else
		HandleBuffer();
#endif
	}

	void MPDMessageHandler::HandleBuffer()
	{
		TRACK_CALL_TEXT("MPDMessageHandler::HandleBuffer()");
		char newLineChars[] = { '\n', '\r' };
		BufferType::iterator begin = _buffer.begin();
		BufferType::iterator end = _buffer.end();
		BufferType::iterator newLine;
		while((newLine = std::find_first_of(begin, end, newLineChars, newLineChars + sizeof(newLineChars)))
				!= end)
		{
			std::string nextCommand(begin, newLine);
			Trim(nextCommand);
			begin = newLine + 1;
			if(!nextCommand.empty())
			{
				Logger(Logger::DBG) << "I: " << nextCommand;
				(this->*_activeHandleCommandRoutine)(nextCommand);
			}
		}
		_buffer.erase(_buffer.begin(), begin);
	}

	template<typename T>
	void MPDMessageHandler::ExecuteCommandQueue(T commandLoop)
	{
		TRACK_CALL_TEXT("MPDMessageHandler::ExecuteCommandQueue()");
		size_t i = 0;
		try
		{
			for(i = 0; i < _commandQueue.size(); ++i)
				commandLoop(_commandQueue[i]);
		}
		catch(const CommandException& e)
		{
			_sender.SendError(i, _commandQueue[i], e);
		}
		_commandQueue.clear();
	}

	void MPDMessageHandler::HandleCommandListActive(const std::string& cmd)
	{
		if(!StrStartsWithLC(cmd, "command_list_end"))
			_commandQueue.push_back(cmd);
		else
		{
			ExecuteCommandQueue([this](const std::string& cmd) {
				ExecuteCommand(cmd);
			});
			_sender.SendOk();
			_activeHandleCommandRoutine = &MPDMessageHandler::HandleCommandOnly;
		}
	}
	void MPDMessageHandler::HandleCommandListOkActive(const std::string& cmd)
	{
		if(!StrStartsWithLC(cmd, "command_list_end"))
			_commandQueue.push_back(cmd);
		else
		{
			ExecuteCommandQueue([this](const std::string& cmd) {
				ExecuteCommand(cmd);
				_sender.SendListOk();
			});
			_activeHandleCommandRoutine = &MPDMessageHandler::HandleCommandOnly;
		}
	}
	void MPDMessageHandler::HandleCommandOnly(const std::string& cmd)
	{
		if(StrStartsWithLC(cmd, "command_list_begin"))
		{
			_activeHandleCommandRoutine = &MPDMessageHandler::HandleCommandListActive;
		}
		else if(StrStartsWithLC(cmd, "command_list_ok_begin"))
		{
			_activeHandleCommandRoutine = &MPDMessageHandler::HandleCommandListOkActive;
		}
		else
		{
			try
			{
				ExecuteCommand(cmd);
				_sender.SendOk();
			}
			catch(const CommandException& e)
			{
				_sender.SendError(0, cmd, e);
			}
		}
	}

	bool MPDMessageHandler::WakeProc(abort_callback &abort)
	{
		TRACK_CALL_TEXT("MPDMessageHandler::WakeProc()");
		Logger(Logger::FINEST) << "==>MPDMessageHandler got pushed buffer";
		try
		{
			HandleBuffer();
		}
		catch(const std::exception& e)
		{
			Logger(Logger::SEVERE) << "Caught exception: " << e;
		}
		return true;
	}

	void MPDMessageHandler::ExecuteCommand(std::string message)
	{
		TRACK_CALL_TEXT("MPDMessageHandler::ExecuteCommand()");
		Timer time;
		std::vector<std::string> cmd = SplitCommand(message);
		std::transform(cmd[0].begin(), cmd[0].end(), cmd[0].begin(), tolower);

		auto action = _actions.find(cmd[0]);
		if(action != _actions.end())
			action->second(_sender, cmd);
		else
		{
			Logger(Logger::DBG) << "Command not found: " << message;
		}
		time.LogDifference("Command " + cmd[0]);
	}

	std::vector<std::string> MPDMessageHandler::SplitCommand(const std::string& cmd)
	{
		assert(!cmd.empty());
		TRACK_CALL_TEXT("MPDMessageHandler::SplitCommand()");
		std::vector<std::string> ret;
		std::string::const_iterator start = cmd.begin();
		std::string::const_iterator end = cmd.end();
		while(start != end)
		{
			std::string::const_iterator argEnd;
			if(*start == '"')
				argEnd = std::find(start + 1, end, '"');
			else
				argEnd = std::find_if(start + 1, end, &CharIsSpace);
			ret.push_back(std::string(start, argEnd));
			if(argEnd != cmd.end())
				argEnd += 1;

			start = std::find_if_not(argEnd, end, &CharIsSpace);
		}
		return ret;
	}

	/*void MPDMessageHandler::SendAllFileinfo(std::vector<std::string>& args)
	{
		if(args.size() < 2)
			args.push_back("/");
		pfc::string8 path = args[1].c_str();
		NormalizePath(path);

		static_api_ptr_t<library_manager> lib;
		pfc::list_t<metadb_handle_ptr> out;
		lib->get_all_items(out);
		SortByFolder tmp;
		out.sort(tmp);
		FilterListByPath(out, path);

		t_size length = out.get_count();

		for(t_size i = 0; i < length; ++i)
			_sender.SendSongMetadata(out[i]);
	}*/
}<commit_msg>Fixed SplitCommand not handling " correctly<commit_after>// Known bugs:
//  * Volume on a logarithmic scale
//  * _buffer must be made thread-safe

#include "MPDMessageHandler.h"
#include "common.h"
#include "StringUtil.h"
#include "PlaybackCommandHandler.h"
#include "PlaylistCommandHandler.h"
#include "GeneralCommandHandler.h"
#include "DataRequestHandler.h"
#include "Timer.h"
#include <algorithm>
#include <functional>
#include <fstream>
#include <string>
#include <unordered_map>

namespace foo_mpdsrv
{
	MPDMessageHandler::MPDMessageHandler(MPDMessageHandler&& right) : _sender(std::move(right._sender)),
		_actions(std::move(right._actions)),
		_activeHandleCommandRoutine(&MPDMessageHandler::HandleCommandOnly)
	{
		TRACK_CALL_TEXT("MPDMessageHandler::MPDMessageHandler(&&)");
	}

	MPDMessageHandler::MPDMessageHandler(SOCKET connection) : _sender(connection)
	{
		TRACK_CALL_TEXT("MPDMessageHandler::MPDMessageHandler(socket)");
		_actions.insert(std::make_pair("ping", &HandlePing));
		_actions.insert(std::make_pair("pause", &HandlePause));
		_actions.insert(std::make_pair("play", &HandlePlay));
		_actions.insert(std::make_pair("playid", &HandlePlayId));
		_actions.insert(std::make_pair("stop", &HandleStop));
		_actions.insert(std::make_pair("next", &HandleNext));
		_actions.insert(std::make_pair("previous", &HandlePrevious));
		_actions.insert(std::make_pair("playlistinfo", &HandlePlaylistinfo));
		_actions.insert(std::make_pair("listplaylistinfo", &HandleListplaylistinfo));
		_actions.insert(std::make_pair("lsinfo", &HandleLsinfo));
		_actions.insert(std::make_pair("currentsong", &HandleCurrentsong));
		_actions.insert(std::make_pair("plchanges", &HandlePlchanges));
		_actions.insert(std::make_pair("status", &HandleStatus));
		_actions.insert(std::make_pair("stats", &HandleStats));
		_actions.insert(std::make_pair("outputs", &HandleOutputs));
		_actions.insert(std::make_pair("close", &HandleClose));
		_actions.insert(std::make_pair("volume", &HandleVolume));
		_actions.insert(std::make_pair("setvol", &HandleVolume));
	}

	MPDMessageHandler::~MPDMessageHandler()
	{
		TRACK_CALL_TEXT("MPDMessageHandler::~MPDMessageHandler()");
#ifdef FOO_MPDSRV_THREADED
		ExitThread();
		WaitTillThreadDone();
#endif
	}

	void MPDMessageHandler::PushBuffer(const char* buf, size_t numBytes)
	{
		TRACK_CALL_TEXT("MPDMessageHandler::PushBuffer()");
		_buffer.insert(_buffer.end(), buf, buf + numBytes);
#ifdef FOO_MPDSRV_THREADED
		Wake();
#else
		HandleBuffer();
#endif
	}

	void MPDMessageHandler::HandleBuffer()
	{
		TRACK_CALL_TEXT("MPDMessageHandler::HandleBuffer()");
		char newLineChars[] = { '\n', '\r' };
		BufferType::iterator begin = _buffer.begin();
		BufferType::iterator end = _buffer.end();
		BufferType::iterator newLine;
		while((newLine = std::find_first_of(begin, end, newLineChars, newLineChars + sizeof(newLineChars)))
				!= end)
		{
			std::string nextCommand(begin, newLine);
			Trim(nextCommand);
			begin = newLine + 1;
			if(!nextCommand.empty())
			{
				Logger(Logger::DBG) << "I: " << nextCommand;
				(this->*_activeHandleCommandRoutine)(nextCommand);
			}
		}
		_buffer.erase(_buffer.begin(), begin);
	}

	template<typename T>
	void MPDMessageHandler::ExecuteCommandQueue(T commandLoop)
	{
		TRACK_CALL_TEXT("MPDMessageHandler::ExecuteCommandQueue()");
		size_t i = 0;
		try
		{
			for(i = 0; i < _commandQueue.size(); ++i)
				commandLoop(_commandQueue[i]);
		}
		catch(const CommandException& e)
		{
			_sender.SendError(i, _commandQueue[i], e);
		}
		_commandQueue.clear();
	}

	void MPDMessageHandler::HandleCommandListActive(const std::string& cmd)
	{
		if(!StrStartsWithLC(cmd, "command_list_end"))
			_commandQueue.push_back(cmd);
		else
		{
			ExecuteCommandQueue([this](const std::string& cmd) {
				ExecuteCommand(cmd);
			});
			_sender.SendOk();
			_activeHandleCommandRoutine = &MPDMessageHandler::HandleCommandOnly;
		}
	}
	void MPDMessageHandler::HandleCommandListOkActive(const std::string& cmd)
	{
		if(!StrStartsWithLC(cmd, "command_list_end"))
			_commandQueue.push_back(cmd);
		else
		{
			ExecuteCommandQueue([this](const std::string& cmd) {
				ExecuteCommand(cmd);
				_sender.SendListOk();
			});
			_activeHandleCommandRoutine = &MPDMessageHandler::HandleCommandOnly;
		}
	}
	void MPDMessageHandler::HandleCommandOnly(const std::string& cmd)
	{
		if(StrStartsWithLC(cmd, "command_list_begin"))
		{
			_activeHandleCommandRoutine = &MPDMessageHandler::HandleCommandListActive;
		}
		else if(StrStartsWithLC(cmd, "command_list_ok_begin"))
		{
			_activeHandleCommandRoutine = &MPDMessageHandler::HandleCommandListOkActive;
		}
		else
		{
			try
			{
				ExecuteCommand(cmd);
				_sender.SendOk();
			}
			catch(const CommandException& e)
			{
				_sender.SendError(0, cmd, e);
			}
		}
	}

	bool MPDMessageHandler::WakeProc(abort_callback &abort)
	{
		TRACK_CALL_TEXT("MPDMessageHandler::WakeProc()");
		Logger(Logger::FINEST) << "==>MPDMessageHandler got pushed buffer";
		try
		{
			HandleBuffer();
		}
		catch(const std::exception& e)
		{
			Logger(Logger::SEVERE) << "Caught exception: " << e;
		}
		return true;
	}

	void MPDMessageHandler::ExecuteCommand(std::string message)
	{
		TRACK_CALL_TEXT("MPDMessageHandler::ExecuteCommand()");
		Timer time;
		std::vector<std::string> cmd = SplitCommand(message);
		std::transform(cmd[0].begin(), cmd[0].end(), cmd[0].begin(), tolower);

		auto action = _actions.find(cmd[0]);
		if(action != _actions.end())
			action->second(_sender, cmd);
		else
		{
			Logger(Logger::DBG) << "Command not found: " << message;
		}
		time.LogDifference("Command " + cmd[0]);
	}

	std::vector<std::string> MPDMessageHandler::SplitCommand(const std::string& cmd)
	{
		assert(!cmd.empty());
		TRACK_CALL_TEXT("MPDMessageHandler::SplitCommand()");
		std::vector<std::string> ret;
		std::string::const_iterator start = cmd.begin();
		std::string::const_iterator end = cmd.end();
		while(start != end)
		{
			std::string::const_iterator argEnd;
			if(*start == '"')
			{
				start += 1;
				argEnd = std::find(start, end, '"');
			}
			else
			{
				argEnd = std::find_if(start + 1, end, &CharIsSpace);
			}
			ret.push_back(std::string(start, argEnd));
			if(argEnd != cmd.end())
				argEnd += 1;

			start = std::find_if_not(argEnd, end, &CharIsSpace);
		}
		return ret;
	}

	/*void MPDMessageHandler::SendAllFileinfo(std::vector<std::string>& args)
	{
		if(args.size() < 2)
			args.push_back("/");
		pfc::string8 path = args[1].c_str();
		NormalizePath(path);

		static_api_ptr_t<library_manager> lib;
		pfc::list_t<metadb_handle_ptr> out;
		lib->get_all_items(out);
		SortByFolder tmp;
		out.sort(tmp);
		FilterListByPath(out, path);

		t_size length = out.get_count();

		for(t_size i = 0; i < length; ++i)
			_sender.SendSongMetadata(out[i]);
	}*/
}<|endoftext|>


<commit_before>#include <red_black_tree.hpp>
#include <catch.hpp>

SCENARIO("default constructor")
{
	RedBlackTree<int> rbt;
	REQUIRE(rbt._root() == rbt._NIL());
}

SCENARIO("insert")
{
  RedBlackTree<int> rbt;
  rbt.insert(5);
  REQUIRE(rbt.findElement(5) != 0);
}

SCENARIO("insert2", "[init]")
{
  RedBlackTree<int> rbt;
  rbt.insert(2);
  rbt.insert(3);
  rbt.insert(4);
  REQUIRE(rbt._root() == rbt.findElement(3));
  REQUIRE(rbt._color(3) == 1);
  REQUIRE(rbt._color(2) == 0);
  REQUIRE(rbt._color(4) == 0);
  REQUIRE(rbt.findElement(2) != 0);
  REQUIRE(rbt.findElement(3) != 0);
  REQUIRE(rbt.findElement(4) != 0);
}

SCENARIO("insert3")
{
  RedBlackTree<int> rbt;
  rbt.insert(1);
  rbt.insert(2);
  rbt.insert(3);
  rbt.insert(4);
  rbt.insert(5);
  REQUIRE(rbt._root() == rbt.findElement(2));
  REQUIRE(rbt._color(2) == 1);
  REQUIRE(rbt._color(1) == 1);
  REQUIRE(rbt._color(4) == 1);
  REQUIRE(rbt._color(3) == 0);
  REQUIRE(rbt._color(5) == 0);
  REQUIRE(rbt.findElement(1) != 0);
  REQUIRE(rbt.findElement(2) != 0);
  REQUIRE(rbt.findElement(3) != 0);
  REQUIRE(rbt.findElement(4) != 0);
  REQUIRE(rbt.findElement(5) != 0);
}

SCENARIO ("insert4")
{
  RedBlackTree<int> rbt;
  rbt.insert(3);
  rbt.insert(1);
  rbt.insert(2);
  REQUIRE(rbt._root() == rbt.findElement(2));
  REQUIRE(rbt._color(2) == 1);
  REQUIRE(rbt._color(1) == 0);
  REQUIRE(rbt._color(3) == 0);
  REQUIRE(rbt.findElement(1) != 0);
  REQUIRE(rbt.findElement(2) != 0);
  REQUIRE(rbt.findElement(3) != 0);
}

SCENARIO("insert5")
{
  RedBlackTree<int> rbt;
  rbt.insert(3);
  rbt.insert(2);
  rbt.insert(1);
  REQUIRE(rbt._root() == rbt.findElement(2));
  REQUIRE(rbt._color(2) == 1);
  REQUIRE(rbt._color(1) == 0);
  REQUIRE(rbt._color(3) == 0);
  REQUIRE(rbt.findElement(1) != 0);
  REQUIRE(rbt.findElement(2) != 0);
  REQUIRE(rbt.findElement(3) != 0);
}
<commit_msg>Create init.cpp<commit_after>#include <red_black_tree.hpp>
#include <catch.hpp>

SCENARIO("default constructor")
{
	RedBlackTree<int> rbt;
	REQUIRE(rbt._root() == rbt._NIL());
}

SCENARIO("insert")
{
  RedBlackTree<int> rbt;
  rbt.insert(5);
  REQUIRE(rbt.findElement(5) != 0);
}

SCENARIO("insert2", "[init]")
{
  RedBlackTree<int> rbt;
  rbt.insert(2);
  rbt.insert(3);
  rbt.insert(4);
  REQUIRE(rbt._root() == rbt.findElement(3));
  REQUIRE(rbt._color(3) == 1);
  REQUIRE(rbt._color(2) == 0);
  REQUIRE(rbt._color(4) == 0);
  REQUIRE(rbt.findElement(2) != 0);
  REQUIRE(rbt.findElement(3) != 0);
  REQUIRE(rbt.findElement(4) != 0);
}

SCENARIO("insert3")
{
  RedBlackTree<int> rbt;
  rbt.insert(1);
  rbt.insert(2);
  rbt.insert(3);
  rbt.insert(4);
  rbt.insert(5);
  REQUIRE(rbt._root() == rbt.findElement(2));
  REQUIRE(rbt._color(2) == 1);
  REQUIRE(rbt._color(1) == 1);
  REQUIRE(rbt._color(4) == 1);
  REQUIRE(rbt._color(3) == 0);
  REQUIRE(rbt._color(5) == 0);
  REQUIRE(rbt.findElement(1) != 0);
  REQUIRE(rbt.findElement(2) != 0);
  REQUIRE(rbt.findElement(3) != 0);
  REQUIRE(rbt.findElement(4) != 0);
  REQUIRE(rbt.findElement(5) != 0);
}

SCENARIO ("insert4")
{
  RedBlackTree<int> rbt;
  rbt.insert(3);
  rbt.insert(1);
  rbt.insert(2);
  REQUIRE(rbt._root() == rbt.findElement(2));
  REQUIRE(rbt._color(2) == 1);
  REQUIRE(rbt._color(1) == 0);
  REQUIRE(rbt._color(3) == 0);
  REQUIRE(rbt.findElement(1) != 0);
  REQUIRE(rbt.findElement(2) != 0);
  REQUIRE(rbt.findElement(3) != 0);
}

SCENARIO("insert5")
{
  RedBlackTree<int> rbt;
  rbt.insert(3);
  rbt.insert(2);
  rbt.insert(1);
  REQUIRE(rbt._root() == rbt.findElement(2));
  REQUIRE(rbt._color(2) == 1);
  REQUIRE(rbt._color(1) == 0);
  REQUIRE(rbt._color(3) == 0);
  REQUIRE(rbt.findElement(1) != 0);
  REQUIRE(rbt.findElement(2) != 0);
  REQUIRE(rbt.findElement(3) != 0);
}

SCENARIO("insert6", "[init]")
{
  RedBlackTree<int> rbt;
  rbt.insert(5);
  rbt.insert(7);
  rbt.insert(6);
  REQUIRE(rbt._root() == rbt.findElement(6));
  REQUIRE(rbt._color(6) == 1);
  REQUIRE(rbt._color(5) == 0);
  REQUIRE(rbt._color(7) == 0);
  REQUIRE(rbt.findElement(5) != 0);
  REQUIRE(rbt.findElement(6) != 0);
  REQUIRE(rbt.findElement(7) != 0);
}
<|endoftext|>


<commit_before>#include <matrix.hpp>
#include <catch.hpp>

SCENARIO("matrix init without parametrs", "[init wp]") {
	Matrix matrix;
	REQUIRE(matrix.rows() == 4);
	REQUIRE(matrix.columns() == 4);

	for (int i=0;i<matrix.rows(); i++) {
		for (int j = 0; j<matrix.columns();j++) {
			REQUIRE(matrix.Element(i,j) == 0);
		}
	}
}

SCENARIO("matrix init with parametrs", "[init withp]") {
	Matrix matrix(6,6);
	REQUIRE(matrix.rows() == 6);
	REQUIRE(matrix.columns() == 6);

	for (int i=0;i<matrix.rows(); i++) {
		for (int j = 0; j<matrix.columns();j++) {
			REQUIRE(matrix.Element(i,j) == 0);
		}
	}
}

SCENARIO("matrix init copy", "[init copy]") {
	Matrix matrix(6,6);
	Matrix matrix1(matrix);
	REQUIRE(matrix1.rows() == matrix.rows());
	REQUIRE(matrix1.columns() == matrix.columns());

	for (int i=0;i<matrix.rows(); i++) {
		for (int j = 0; j<matrix.columns();j++) {
			REQUIRE(matrix.Element(i,j) == matrix1.Element(i,j));
		}
	}
}

SCENARIO("matrix fill", "[fill]") {
	Matrix matrix(2,2);
	ofstream test1("test1.txt");
	test1 << "1 2 3 4";
	test1.close();
	matrix.fill("test1.txt");
	REQUIRE(matrix.Element(0,0) == 1);
	REQUIRE(matrix.Element(0,1) == 2);
	REQUIRE(matrix.Element(1,0) == 3);
	REQUIRE(matrix.Element(1,1) == 4);
}

SCENARIO("matrix sum", "[sum]") {
	Matrix matrix(2,2);
	Matrix matrix1(2,2);
	Matrix sum(2,2);

	ofstream test1("test1.txt");
	test1 << "1 2 3 4";
	test1.close();

	matrix.fill("test1.txt");
	matrix1.fill("test1.txt");
	ofstream sumfile("sumfile.txt");
	sumfile << "2 4 6 8";
	sum.fill("sumfile.txt");
	sumfile.close();
	for (int i=0;i<matrix.rows(); i++) {
		for (int j = 0; j<matrix.columns();j++) {
			REQUIRE(sum.Element(i,j) == matrix.Element(i,j) + matrix1.Element(i,j));
		}
	}
}

<commit_msg>Update init.cpp<commit_after>#include <matrix.hpp>
#include <catch.hpp>

SCENARIO("matrix init without parametrs", "[init wp]") {
	Matrix matrix;
	REQUIRE(matrix.rows() == 4);
	REQUIRE(matrix.columns() == 4);

	for (int i=0;i<matrix.rows(); i++) {
		for (int j = 0; j<matrix.columns();j++) {
			REQUIRE(matrix.Element(i,j) == 0);
		}
	}
}

SCENARIO("matrix init with parametrs", "[init withp]") {
	Matrix matrix(6,6);
	REQUIRE(matrix.rows() == 6);
	REQUIRE(matrix.columns() == 6);

	for (int i=0;i<matrix.rows(); i++) {
		for (int j = 0; j<matrix.columns();j++) {
			REQUIRE(matrix.Element(i,j) == 0);
		}
	}
}

SCENARIO("matrix init copy", "[init copy]") {
	Matrix matrix(6,6);
	Matrix matrix1(matrix);
	REQUIRE(matrix1.rows() == matrix.rows());
	REQUIRE(matrix1.columns() == matrix.columns());

	for (int i=0;i<matrix.rows(); i++) {
		for (int j = 0; j<matrix.columns();j++) {
			REQUIRE(matrix.Element(i,j) == matrix1.Element(i,j));
		}
	}
}

SCENARIO("matrix fill", "[fill]") {
	Matrix matrix(2,2);
	ofstream test1("test1.txt");
	test1 << "1 2 3 4";
	test1.close();
	matrix.fill("test1.txt");
	REQUIRE(matrix.Element(0,0) == 1);
	REQUIRE(matrix.Element(0,1) == 2);
	REQUIRE(matrix.Element(1,0) == 3);
	REQUIRE(matrix.Element(1,1) == 4);
}

SCENARIO("matrix sum", "[sum]") {
	Matrix matrix(2,2);
	Matrix matrix1(2,2);
	Matrix sum(2,2);

	ofstream test1("test1.txt");
	test1 << "1 2 3 4";
	test1.close();

	matrix.fill("test1.txt");
	matrix1.fill("test1.txt");
	//ofstream sumfile("sumfile.txt");
	//sumfile << "2 4 6 8";
	//sum.fill("sumfile.txt");
	//sumfile.close();
	REQUIRE(matrix.Element(0,0) + matrix1.Element(0,0) == 2);
	REQUIRE(matrix.Element(0,1) + matrix1.Element(0,1) == 4);
	REQUIRE(matrix.Element(1,0) + matrix1.Element(1,0) == 6);
	REQUIRE(matrix.Element(1,1) + matrix1.Element(1,1) == 8);

}

<|endoftext|>


<commit_before>
#include "obb.h"
#include "isect2d.h"

#include <iostream>
#include <cmath>
#include <vector>
#include <memory>
#include <random>

#include <GLFW/glfw3.h>

//#define AXIS_DRAW
#define N_BOX 100

GLFWwindow* window;
float width = 800;
float height = 600;
float dpiRatio = 1;

bool pause = false;

std::vector<OBB> obbs;

float rand_0_1(float scale) {
    return ((float)rand() / (float)(RAND_MAX)) * scale;
}

void update() {
    double time = glfwGetTime();
    if(!pause) {
        int i = 0;
        for (auto& obb : obbs) {
            float r1 = rand_0_1(10);
            float r2 = rand_0_1(20);
            float r3 = rand_0_1(M_PI);
            auto center = obb.getCenter();

            if (++i % 2 == 0) {
                obb.move(center.x, center.y + .02 * cos(time * 0.25) * r2);
                obb.rotate(cos(r3) * 0.1 + obb.getAngle());
            } else {
                obb.move(center.x + 0.1 * cos(time) * r1, center.y);
                obb.rotate(cos(r2) * 0.1 + obb.getAngle());
            }
        }
    }
}

void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) {
    if(key == 'P' && action == GLFW_PRESS) {
        pause = !pause;
    }
}

void initBBoxes() {

    int n = N_BOX;
    float o = (2 * M_PI) / n;
    float size = 250;
    float boxSize = n / (0.5 * n);

    for (int i = 0; i < n; ++i) {
        float r = rand_0_1(20);

        obbs.push_back(OBB(cos(o * i) * size + width / 2,
                    sin(o * i) * size + height / 2, r,
                    r + boxSize * 8, r * boxSize / 3 + boxSize));
    }

}

void init() {
    glfwInit();

    glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
    glfwWindowHint(GLFW_SAMPLES, 4);
    window = glfwCreateWindow(width, height, "isect2d", NULL, NULL);

    if (!window) {
        glfwTerminate();
    }

    int fbWidth, fbHeight;
    glfwGetFramebufferSize(window, &fbWidth, &fbHeight);
    glfwSetKeyCallback(window, keyCallback);

    dpiRatio = fbWidth / width;

    glfwMakeContextCurrent(window);

    initBBoxes();
}

void line(float sx, float sy, float ex, float ey) {
    glBegin(GL_LINES);
    glVertex2f(sx, sy);
    glVertex2f(ex, ey);
    glEnd();
}

void cross(float x, float y, float size = 3) {
    line(x - size, y, x + size, y);
    line(x, y - size, x, y + size);
}

void drawAABB(const isect2d::AABB& _aabb) {
    line(_aabb.getMin().x, _aabb.getMin().y, _aabb.getMax().x, _aabb.getMax().y);
}

void drawOBB(const OBB& obb, bool isect) {
    const isect2d::Vec2* quad = obb.getQuad();
    const isect2d::Vec2* axes = obb.getAxes();

    drawAABB(isect2d::AABB(obb.getExtent()));

    for(int i = 0; i < 4; ++i) {
        if(isect) {
            glColor4f(0.5, 1.0, 0.5, 1.0);
        } else {
            glColor4f(1.0, 0.5, 0.5, 1.0);
        }

        isect2d::Vec2 start = quad[i];
        isect2d::Vec2 end = quad[(i + 1) % 4];
        line(start.x, start.y, end.x, end.y);
        glColor4f(1.0, 1.0, 1.0, 0.1);
        cross(obb.getCenter().x, obb.getCenter().y, 2);

#ifdef AXIS_DRAW
        // draw separating axes and the projections
        for(int j = 0; j < 2; ++j) {
            isect2d::Vec2 proj = project(quad[i], axes[j]);

            glColor4f(1.0, 1.0, 1.0, 0.1);
            cross(proj.x, proj.y);
        }
#endif
    }

#ifdef AXIS_DRAW
    for(int i = 0; i < 2; ++i) {
        isect2d::Vec2 end = axes[i] * 1000.0;
        isect2d::Vec2 start = end * -1;

        glColor4f(0.4, 0.4, 0.4, 0.1);
        line(start.x, start.y, end.x, end.y);
    }
#endif
}

void render() {
    while (!glfwWindowShouldClose(window)) {
        update();
        glEnable(GL_MULTISAMPLE);

        glViewport(0, 0, width * dpiRatio, height * dpiRatio);
        glClearColor(0.18f, 0.18f, 0.22f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glOrtho(0, width, 0, height, -1, 1);

        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();

        for (auto& obb : obbs) {
            drawOBB(obb, false);
        }

        const clock_t beginBroadPhaseTime = clock();

        std::vector<isect2d::AABB> aabbs;

        for (auto& obb : obbs) {
            auto aabb = obb.getExtent();
            aabb.m_userData = (void*)&obb;
            aabbs.push_back(aabb);
        }

        const clock_t startBruteForce = clock();
        std::set<std::pair<int, int>> p;
        for (int i = 0; i < obbs.size(); ++i) {
            for (int j = i + 1; j < obbs.size(); ++j) {
                if (intersect(obbs[i], obbs[j])) {
                    p.insert({ i, j });
                }
            }
        }
        std::cout << "bruteforce " << float(clock() - startBruteForce) / CLOCKS_PER_SEC * 1000 << "ms" << " ";

        // broad phase
        auto pairs = intersect(&aabbs[0], aabbs.size(), &aabbs[0], aabbs.size());

        const clock_t endBroadPhaseTime = clock();

        std::cout << float(endBroadPhaseTime - beginBroadPhaseTime) / CLOCKS_PER_SEC * 1000 << "ms";

        clock_t narrowTime = 0;

        for (auto pair : pairs) {
            clock_t beginNarrowTime;
            clock_t endNarrowTime;

            auto obb1 = obbs[pair.first];
            auto obb2 = obbs[pair.second];

            // narrow phase
            beginNarrowTime = clock();
            bool isect = intersect(obb1, obb2);
            endNarrowTime = clock();

            narrowTime += (endBroadPhaseTime - beginBroadPhaseTime);

            if (isect) {

                drawOBB(obb1, true);
                drawOBB(obb2, true);

                line(obb1.getCenter().x, obb1.getCenter().y, obb2.getCenter().x, obb2.getCenter().y);
            }

        }

        std::cout << " " << float(narrowTime) / CLOCKS_PER_SEC * 1000 << "ms" << std::endl;

        glfwSwapBuffers(window);

        glfwPollEvents();
    }
}

int main() {

    init();
    render();

    return 0;
}

<commit_msg>tests<commit_after>
#include "obb.h"
#include "isect2d.h"

#include <iostream>
#include <cmath>
#include <vector>
#include <memory>
#include <random>

#include <GLFW/glfw3.h>

//#define AXIS_DRAW
#define N_BOX 100

GLFWwindow* window;
float width = 800;
float height = 600;
float dpiRatio = 1;

bool pause = false;

std::vector<OBB> obbs;

float rand_0_1(float scale) {
    return ((float)rand() / (float)(RAND_MAX)) * scale;
}

void update() {
    double time = glfwGetTime();
    if(!pause) {
        int i = 0;
        for (auto& obb : obbs) {
            float r1 = rand_0_1(10);
            float r2 = rand_0_1(20);
            float r3 = rand_0_1(M_PI);
            auto center = obb.getCenter();

            if (++i % 2 == 0) {
                obb.move(center.x, center.y + .02 * cos(time * 0.25) * r2);
                obb.rotate(cos(r3) * 0.1 + obb.getAngle());
            } else {
                obb.move(center.x + 0.1 * cos(time) * r1, center.y);
                obb.rotate(cos(r2) * 0.1 + obb.getAngle());
            }
        }
    }
}

void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) {
    if(key == 'P' && action == GLFW_PRESS) {
        pause = !pause;
    }
}

void initBBoxes() {

    int n = N_BOX;
    float o = (2 * M_PI) / n;
    float size = 250;
    float boxSize = n / (0.5 * n);

    for (int i = 0; i < n; ++i) {
        float r = rand_0_1(20);

        obbs.push_back(OBB(cos(o * i) * size + width / 2,
                    sin(o * i) * size + height / 2, r,
                    r + boxSize * 8, r * boxSize / 3 + boxSize));
    }

}

void init() {
    glfwInit();

    glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
    glfwWindowHint(GLFW_SAMPLES, 4);
    window = glfwCreateWindow(width, height, "isect2d", NULL, NULL);

    if (!window) {
        glfwTerminate();
    }

    int fbWidth, fbHeight;
    glfwGetFramebufferSize(window, &fbWidth, &fbHeight);
    glfwSetKeyCallback(window, keyCallback);

    dpiRatio = fbWidth / width;

    glfwMakeContextCurrent(window);

    initBBoxes();
}

void line(float sx, float sy, float ex, float ey) {
    glBegin(GL_LINES);
    glVertex2f(sx, sy);
    glVertex2f(ex, ey);
    glEnd();
}

void cross(float x, float y, float size = 3) {
    line(x - size, y, x + size, y);
    line(x, y - size, x, y + size);
}

void drawAABB(const isect2d::AABB& _aabb) {
    line(_aabb.getMin().x, _aabb.getMin().y, _aabb.getMax().x, _aabb.getMax().y);
}

void drawOBB(const OBB& obb, bool isect) {
    const isect2d::Vec2* quad = obb.getQuad();
    const isect2d::Vec2* axes = obb.getAxes();

    drawAABB(isect2d::AABB(obb.getExtent()));

    for(int i = 0; i < 4; ++i) {
        if(isect) {
            glColor4f(0.5, 1.0, 0.5, 1.0);
        } else {
            glColor4f(1.0, 0.5, 0.5, 1.0);
        }

        isect2d::Vec2 start = quad[i];
        isect2d::Vec2 end = quad[(i + 1) % 4];
        line(start.x, start.y, end.x, end.y);
        glColor4f(1.0, 1.0, 1.0, 0.1);
        cross(obb.getCenter().x, obb.getCenter().y, 2);

#ifdef AXIS_DRAW
        // draw separating axes and the projections
        for(int j = 0; j < 2; ++j) {
            isect2d::Vec2 proj = project(quad[i], axes[j]);

            glColor4f(1.0, 1.0, 1.0, 0.1);
            cross(proj.x, proj.y);
        }
#endif
    }

#ifdef AXIS_DRAW
    for(int i = 0; i < 2; ++i) {
        isect2d::Vec2 end = axes[i] * 1000.0;
        isect2d::Vec2 start = end * -1;

        glColor4f(0.4, 0.4, 0.4, 0.1);
        line(start.x, start.y, end.x, end.y);
    }
#endif
}

void render() {
    while (!glfwWindowShouldClose(window)) {
        update();
        glEnable(GL_MULTISAMPLE);

        glViewport(0, 0, width * dpiRatio, height * dpiRatio);
        glClearColor(0.18f, 0.18f, 0.22f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glOrtho(0, width, 0, height, -1, 1);

        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();

        for (auto& obb : obbs) {
            drawOBB(obb, false);
        }

        const clock_t startBruteForce = clock();
        std::set<std::pair<int, int>> p;
        for (int i = 0; i < obbs.size(); ++i) {
            for (int j = i + 1; j < obbs.size(); ++j) {
                if (intersect(obbs[i], obbs[j])) {
                    p.insert({ i, j });
                }
            }
        }
        std::cout << "bruteforce: " << float(clock() - startBruteForce) / CLOCKS_PER_SEC * 1000 << "ms ";

        // broad phase
        const clock_t beginBroadPhaseTime = clock();

        std::vector<isect2d::AABB> aabbs;
        for (auto& obb : obbs) {
            auto aabb = obb.getExtent();
            aabb.m_userData = (void*)&obb;
            aabbs.push_back(aabb);
        }

        auto pairs = intersect(&aabbs[0], aabbs.size(), &aabbs[0], aabbs.size());

        std::cout << "broadphase: " << (float(clock() - beginBroadPhaseTime) / CLOCKS_PER_SEC) * 1000 << "ms ";

        clock_t narrowTime = 0;

        for (auto pair : pairs) {
            clock_t beginNarrowTime;
            clock_t endNarrowTime;

            auto obb1 = obbs[pair.first];
            auto obb2 = obbs[pair.second];

            // narrow phase
            beginNarrowTime = clock();
            bool isect = intersect(obb1, obb2);
            narrowTime += (clock() - beginNarrowTime);

            if (isect) {

                drawOBB(obb1, true);
                drawOBB(obb2, true);

                line(obb1.getCenter().x, obb1.getCenter().y, obb2.getCenter().x, obb2.getCenter().y);
            }

        }

        std::cout << "narrowphase: " << (float(narrowTime) / CLOCKS_PER_SEC) * 1000 << "ms" << std::endl;

        glfwSwapBuffers(window);

        glfwPollEvents();
    }
}

int main() {

    init();
    render();

    return 0;
}

<|endoftext|>


<commit_before>// (C) Copyright Kirill Lykov 2013.
//
// Distributed under the FreeBSD Software License (See accompanying file license.txt)

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <map>

#include <boost/program_options.hpp>
namespace po = boost::program_options;

#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;

// OpenNI
#include <XnCppWrapper.h>

// OpenCV
#include <opencv2/opencv.hpp>

class CodecName2FourCC
{
  typedef std::map<std::string, std::string> Map;
  typedef typename std::map<std::string, std::string>::iterator Iterator;
  Map m_codecName2FourCC;
public:
  CodecName2FourCC() {
    m_codecName2FourCC["MPEG-1"] = "PIM1";
    m_codecName2FourCC["MPEG-4.2"] = "MP42";
    m_codecName2FourCC["MPEG-4.3"] = "DIV3";
    m_codecName2FourCC["MPEG-4"] = "DIVX";
    m_codecName2FourCC["FLV1"] = "FLV1";
  }

  int operator() (const std::string& codeName) {
    Iterator it = m_codecName2FourCC.find(codeName);
    if (it == m_codecName2FourCC.end())
      throw "unknown codec name";
    std::string fourcc = it->second;
    return CV_FOURCC(fourcc[0], fourcc[1], fourcc[2], fourcc[3]);
  }
};

class Oni2AviConverter
{
  CodecName2FourCC m_codecName2Code;
public:
  Oni2AviConverter() {

  }

  void run(const std::string& codecName,
           const std::string& inputFile, const std::string& outputFile, bool depthAsPng = false) {

    // TODO For the latest version of OpenCV, you may use HighGUI instead of using OpenNI
    // assumed that nframes, picture size for depth and images is the same
    xn::Context context;
    context.Init();

    xn::Player player;
    context.OpenFileRecording(inputFile.c_str(), player);
    player.SetRepeat(false);

    xn::ImageGenerator imageGen;
    imageGen.Create( context );
    imageGen.SetPixelFormat(XN_PIXEL_FORMAT_RGB24);
    xn::ImageMetaData xImageMap2;
    imageGen.GetMetaData(xImageMap2);
    XnUInt32 fps = xImageMap2.FPS();
    XnUInt32 frame_height = xImageMap2.YRes();
    XnUInt32 frame_width = xImageMap2.XRes();

    xn::DepthGenerator depthGen;
    depthGen.Create(context);
    XnUInt32 nframes;
    player.GetNumFrames(depthGen.GetName(), nframes);

    printResume(nframes, codecName, inputFile, outputFile);

    std::string outputFileImg, outputFileDepth;
    getOutputFileNames(outputFile, outputFileImg, outputFileDepth);

    cv::VideoWriter imgWriter(outputFileImg, m_codecName2Code(codecName), fps, cvSize(frame_width, frame_height), 1);
    cv::VideoWriter depthWriter(outputFileDepth, m_codecName2Code(codecName), fps, cvSize(frame_width, frame_height), 1);

    std::string depthFolderName = getDepthFolderName(outputFileImg);
    fs::path folderForDepthImages(depthFolderName);
    if (depthAsPng)
    {
      if (fs::exists(folderForDepthImages) && !fs::is_directory(folderForDepthImages)) {
        throw "Cannot create a directory because file with the same name exists. Remove it and try again";
      }
      if (!fs::exists(folderForDepthImages))
      {
        fs::create_directory(folderForDepthImages);
      }
    }

    context.StartGeneratingAll();

    size_t outStep = nframes / 10;

    for(size_t iframe = 0; iframe < nframes; ++iframe)
    {
      if ( iframe % outStep == 0 )
          std::cout << iframe << "/" << nframes << std::endl;

      // save image
      imageGen.WaitAndUpdateData();
      xn::ImageMetaData xImageMap;
      imageGen.GetMetaData(xImageMap);
      XnRGB24Pixel* imgData = const_cast<XnRGB24Pixel*>(xImageMap.RGB24Data());
      cv::Mat image(frame_height, frame_width, CV_8UC3, reinterpret_cast<void*>(imgData));

      cv::cvtColor(image, image, CV_BGR2RGB); // opencv image format is bgr
      imgWriter << image.clone();

      // save depth
      depthGen.WaitAndUpdateData();
      xn::DepthMetaData xDepthMap;
      depthGen.GetMetaData(xDepthMap);
      XnDepthPixel* depthData = const_cast<XnDepthPixel*>(xDepthMap.Data());
      cv::Mat depth(frame_height, frame_width, CV_16U, reinterpret_cast<void*>(depthData));

      if (!depthAsPng)
      {
#if (CV_MAJOR_VERSION == 2 && CV_MINOR_VERSION >= 4) || CV_MAJOR_VERSION > 2
        cv::Mat depthMat8UC1;
        depth.convertTo(depthMat8UC1, CV_8UC1);
        // can be used for having different colors than grey
        cv::Mat falseColorsMap;
        cv::applyColorMap(depthMat8UC1, falseColorsMap, cv::COLORMAP_AUTUMN);
        depthWriter << falseColorsMap;
#else
      throw "saving depth in avi file is not supported for opencv 2.3 or earlier. please use option --depth-png=yes";
#endif
      }
      else
      {
       // to_string is not supported by gcc4.7 so I don't use it here
       //std::string imgNumAsStr = std::to_string(imgNum);
       std::stringstream ss;
       ss << depthFolderName << "/depth-" << iframe << ".png";
       cv::imwrite(ss.str(), depth);
      }
    }

    context.StopGeneratingAll();
    context.Release();
  }

private:

  static void printResume(size_t nframes, const std::string& codecName,
      const std::string& inputFile, const std::string& outputFile) {
    std::cout << "Total: " << nframes << " frames. Used codec: " << codecName  <<
        ".\n Input file name: " << inputFile << ". Output file name: " << outputFile << "-img/depth" << std::endl;
  }

  static std::string getFileNameNoExt(const std::string& outputFileName)
  {
    size_t index = outputFileName.find_last_of('.');
    std::string nameWithoutExtension;
    if (index == std::string::npos)
      nameWithoutExtension = outputFileName;
    nameWithoutExtension = outputFileName.substr(0, index);
    std::string extention = outputFileName.substr(index + 1);
    if (extention != "avi")
      throw "output file extention must be avi";
    return nameWithoutExtension;
  }

  static void getOutputFileNames(const std::string& outputFileName, std::string& outputFileImg,
                                 std::string& outputFileDepth)
  {
    std::string nameWithoutExtension = getFileNameNoExt(outputFileName);

    outputFileImg = nameWithoutExtension + "-img.avi";
    outputFileDepth = nameWithoutExtension + "-depth.avi";
  }

  static std::string getDepthFolderName(const std::string& outputFileName)
  {
    std::string nameWithoutExtension = getFileNameNoExt(outputFileName);
    return nameWithoutExtension + "-depth";
  }

  Oni2AviConverter(const Oni2AviConverter&);
  Oni2AviConverter& operator= (const Oni2AviConverter&);
};

int main( int argc, char* argv[] )
{
  try {
    po::options_description desc("oni2avi converts an input oni file into 2 avi files - one for image and another for the depth map."
        "\n Allowed options:");
    desc.add_options()
        ("help", "produce help message")
        ("codec", po::value<std::string>()->default_value("MPEG-4.2"),
            "codec used for output video. Available codecs are MPEG-1, MPEG-4, MPEG-4.2, MPEG-4.3 , FLV1")
        ("input-file", po::value< std::string >(), "input oni file")
        ("output-file", po::value< std::string >(), "output avi file")
        ("depth-png", po::value< std::string >(), "save depth as png images instead of avi file. Available values yes or no")
    ;

    po::positional_options_description p;
    p.add("input-file", 1);
    p.add("output-file", 2);

    po::variables_map vm;
    po::store(po::command_line_parser(argc, argv).
              options(desc).positional(p).run(), vm);

    if (vm.count("help")) {
      std::cout << desc << "\n";
      return 1;
    }

    if (!vm.count("codec"))
      throw "codec was not set\n";

    if (!vm.count("input-file"))
      throw "input file was not set\n";

    if (!vm.count("output-file"))
      throw "output file was not set\n";

    bool depthAsPng = false;
    if (vm.count("depth-png"))
      if (vm["depth-png"].as<std::string>() == "yes") {
        depthAsPng = true;
      }

    Oni2AviConverter converter;
    converter.run(vm["codec"].as<std::string>(),
                  vm["input-file"].as<std::string>(),
                  vm["output-file"].as<std::string>(), depthAsPng);
  }
  catch (const char* error) {
    // oni2avi errors
    std::cout << "Error: " << error << ". Use --help for the list of available options." << std::endl;
    return 1;
  }
  //catch () {
    // OpenNI errors
  //  return 1;
  //}
  catch (const std::exception& error) {
    // OpenCV exceptions are derived from std::exception
    std::cout << error.what() << std::endl;
    return 1;
  }
  catch (...) {
    std::cout << "Unknown error" << std::endl;
    return 1;
  }

  return 0;
}
<commit_msg>Added openni return errors check and fixed positions of brackets<commit_after>// (C) Copyright Kirill Lykov 2013.
//
// Distributed under the FreeBSD Software License (See accompanying file license.txt)

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <map>

#include <boost/program_options.hpp>
namespace po = boost::program_options;

#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;

// OpenNI
#include <XnCppWrapper.h>
#define THROW_IF_FAILED(retVal,message) {if (retVal != XN_STATUS_OK) throw message;}

// OpenCV
#include <opencv2/opencv.hpp>

class CodecName2FourCC
{
  typedef std::map<std::string, std::string> Map;
  typedef typename std::map<std::string, std::string>::iterator Iterator;
  Map m_codecName2FourCC;
public:
  CodecName2FourCC()
  {
    m_codecName2FourCC["MPEG-1"] = "PIM1";
    m_codecName2FourCC["MPEG-4.2"] = "MP42";
    m_codecName2FourCC["MPEG-4.3"] = "DIV3";
    m_codecName2FourCC["MPEG-4"] = "DIVX";
    m_codecName2FourCC["FLV1"] = "FLV1";
  }

  int operator() (const std::string& codeName)
  {
    Iterator it = m_codecName2FourCC.find(codeName);
    if (it == m_codecName2FourCC.end())
      throw "unknown codec name";
    std::string fourcc = it->second;
    return CV_FOURCC(fourcc[0], fourcc[1], fourcc[2], fourcc[3]);
  }
};

class Oni2AviConverter
{
  CodecName2FourCC m_codecName2Code;
public:
  Oni2AviConverter()
  {

  }

  void run(const std::string& codecName,
           const std::string& inputFile, const std::string& outputFile, bool depthAsPng = false)
  {

    // TODO For the latest version of OpenCV, you may use HighGUI instead of using OpenNI
    // assumed that nframes, picture size for depth and images is the same
    xn::Context context;
    context.Init();

    xn::Player player;
    context.OpenFileRecording(inputFile.c_str(), player);
    player.SetRepeat(false);

    xn::ImageGenerator imageGen;
    imageGen.Create( context );
    imageGen.SetPixelFormat(XN_PIXEL_FORMAT_RGB24);
    xn::ImageMetaData xImageMap2;
    imageGen.GetMetaData(xImageMap2);
    XnUInt32 fps = xImageMap2.FPS();
    XnUInt32 frame_height = xImageMap2.YRes();
    XnUInt32 frame_width = xImageMap2.XRes();

    xn::DepthGenerator depthGen;
    depthGen.Create(context);
    XnUInt32 nframes;
    player.GetNumFrames(depthGen.GetName(), nframes);

    printResume(nframes, codecName, inputFile, outputFile);

    std::string outputFileImg, outputFileDepth;
    getOutputFileNames(outputFile, outputFileImg, outputFileDepth);

    cv::VideoWriter imgWriter(outputFileImg, m_codecName2Code(codecName), fps, cvSize(frame_width, frame_height), 1);
    cv::VideoWriter depthWriter(outputFileDepth, m_codecName2Code(codecName), fps, cvSize(frame_width, frame_height), 1);

    std::string depthFolderName = getDepthFolderName(outputFileImg);
    fs::path folderForDepthImages(depthFolderName);
    if (depthAsPng)
    {
      if (fs::exists(folderForDepthImages) && !fs::is_directory(folderForDepthImages))
      {
        throw "Cannot create a directory because file with the same name exists. Remove it and try again";
      }
      if (!fs::exists(folderForDepthImages))
      {
        fs::create_directory(folderForDepthImages);
      }
    }

    THROW_IF_FAILED(context.StartGeneratingAll(), "Could not start generating oni frames");

    size_t outStep = nframes / 10;

    try
    {
      for(size_t iframe = 0; iframe < nframes; ++iframe)
      {
        if ( iframe % outStep == 0 )
            std::cout << iframe << "/" << nframes << std::endl;

        // save image
        THROW_IF_FAILED(imageGen.WaitAndUpdateData(), "WaitAndUpdateData failed");
        xn::ImageMetaData xImageMap;
        imageGen.GetMetaData(xImageMap);
        XnRGB24Pixel* imgData = const_cast<XnRGB24Pixel*>(xImageMap.RGB24Data());
        cv::Mat image(frame_height, frame_width, CV_8UC3, reinterpret_cast<void*>(imgData));

        cv::cvtColor(image, image, CV_BGR2RGB); // opencv image format is bgr
        imgWriter << image.clone();

        // save depth
        THROW_IF_FAILED(depthGen.WaitAndUpdateData(), "WaitAndUpdateData failed");
        xn::DepthMetaData xDepthMap;
        depthGen.GetMetaData(xDepthMap);
        XnDepthPixel* depthData = const_cast<XnDepthPixel*>(xDepthMap.Data());
        cv::Mat depth(frame_height, frame_width, CV_16U, reinterpret_cast<void*>(depthData));

        if (!depthAsPng)
        {
  #if (CV_MAJOR_VERSION == 2 && CV_MINOR_VERSION >= 4) || CV_MAJOR_VERSION > 2
          cv::Mat depthMat8UC1;
          depth.convertTo(depthMat8UC1, CV_8UC1);
          // can be used for having different colors than grey
          cv::Mat falseColorsMap;
          cv::applyColorMap(depthMat8UC1, falseColorsMap, cv::COLORMAP_AUTUMN);
          depthWriter << falseColorsMap;
  #else
        throw "saving depth in avi file is not supported for opencv 2.3 or earlier. please use option --depth-png=yes";
  #endif
        }
        else
        {
          // to_string is not supported by gcc4.7 so I don't use it here
          //std::string imgNumAsStr = std::to_string(imgNum);
          std::stringstream ss;
          ss << depthFolderName << "/depth-" << iframe << ".png";
          cv::imwrite(ss.str(), depth);
        }
      }
    }
    catch(...)
    {
      context.StopGeneratingAll();
      context.Release();
      throw;
    }

    context.StopGeneratingAll();
    context.Release();
  }

private:

  static void printResume(size_t nframes, const std::string& codecName,
      const std::string& inputFile, const std::string& outputFile)
  {
    std::cout << "Total: " << nframes << " frames. Used codec: " << codecName  <<
        ".\n Input file name: " << inputFile << ". Output file name: " << outputFile << "-img/depth" << std::endl;
  }

  static std::string getFileNameNoExt(const std::string& outputFileName)
  {
    size_t index = outputFileName.find_last_of('.');
    std::string nameWithoutExtension;
    if (index == std::string::npos)
      nameWithoutExtension = outputFileName;
    nameWithoutExtension = outputFileName.substr(0, index);
    std::string extention = outputFileName.substr(index + 1);
    if (extention != "avi")
      throw "output file extention must be avi";
    return nameWithoutExtension;
  }

  static void getOutputFileNames(const std::string& outputFileName, std::string& outputFileImg,
                                 std::string& outputFileDepth)
  {
    std::string nameWithoutExtension = getFileNameNoExt(outputFileName);

    outputFileImg = nameWithoutExtension + "-img.avi";
    outputFileDepth = nameWithoutExtension + "-depth.avi";
  }

  static std::string getDepthFolderName(const std::string& outputFileName)
  {
    std::string nameWithoutExtension = getFileNameNoExt(outputFileName);
    return nameWithoutExtension + "-depth";
  }

  Oni2AviConverter(const Oni2AviConverter&);
  Oni2AviConverter& operator= (const Oni2AviConverter&);
};

int main(int argc, char* argv[])
{
  try
  {
    po::options_description desc("oni2avi converts an input oni file into 2 avi files - one for image and another for the depth map."
        "\n Allowed options:");
    desc.add_options()
        ("help", "produce help message")
        ("codec", po::value<std::string>()->default_value("MPEG-4.2"),
            "codec used for output video. Available codecs are MPEG-1, MPEG-4, MPEG-4.2, MPEG-4.3 , FLV1")
        ("input-file", po::value< std::string >(), "input oni file")
        ("output-file", po::value< std::string >(), "output avi file")
        ("depth-png", po::value< std::string >(), "save depth as png images instead of avi file. Available values yes or no")
    ;

    po::positional_options_description p;
    p.add("input-file", 1);
    p.add("output-file", 2);

    po::variables_map vm;
    po::store(po::command_line_parser(argc, argv).
              options(desc).positional(p).run(), vm);

    if (vm.count("help"))
    {
      std::cout << desc << "\n";
      return 1;
    }

    if (!vm.count("codec"))
      throw "codec was not set\n";

    if (!vm.count("input-file"))
      throw "input file was not set\n";

    if (!vm.count("output-file"))
      throw "output file was not set\n";

    bool depthAsPng = false;
    if (vm.count("depth-png"))
      if (vm["depth-png"].as<std::string>() == "yes")
      {
        depthAsPng = true;
      }

    Oni2AviConverter converter;
    converter.run(vm["codec"].as<std::string>(),
                  vm["input-file"].as<std::string>(),
                  vm["output-file"].as<std::string>(), depthAsPng);
  }
  catch (const char* error)
  {
    // oni2avi errors
    std::cout << "Error: " << error << ". Use --help for the list of available options." << std::endl;
    return 1;
  }
  catch (const std::exception& error)
  {
    // OpenCV exceptions are derived from std::exception
    std::cout << error.what() << std::endl;
    return 1;
  }
  catch (...)
  {
    std::cout << "Unknown error" << std::endl;
    return 1;
  }

  return 0;
}
<|endoftext|>