<commit_before>#include "HuboMotor.h"
#include <string>
#include <iostream>

HuboMotor::HuboMotor(){
    this->ticks_position = 0;
    this->desired_position = 0;
    this->omega = MAX_ANGULAR_VELOCITY;

    //NEW_DATA
    currGoal = 0;
	interStep = 0;
	interVel = 0;

	currVel = 0;
	currPos = 0;
	currCurrent = 0;
	currTemp = 0;

	enabled = false;
	homed = false;
	zeroed = false;
}

HuboMotor::HuboMotor(long mpos1, long mpos2, long kp, long kd, long ki,
                     long dz, long off, long hlim, long hld, long hv1,
                     long hv2, long hma, long sm, long ers, long as, long md,
                     long v_max, long a_max, long jam_lim, long jamd,
                     long pwm_lim, long i_err, long b_err){
    this->mpos1 = mpos1;
    this->mpos2 = mpos2;
    this->Kp = kp;
    this->Kd = kd;
    this->Ki = ki;
    this->dz = dz;
    this->off = off;
    this->hlim = hlim;
    this->hld = hld;
    this->hv1 = hv1;
    this->hv2 = hv2;
    this->hma = hma;
    this->sm = sm;
    this->ers = ers;
    this->as = as;
    this->md = md;
    this->v_max = v_max;
    this->a_max = a_max;
    this->jam_lim = jam_lim;
    this->jamd = jamd;
    this->pwm_lim = pwm_lim;
    this->i_err = i_err;
    this->b_err = b_err;
    this->ticks_position = 0;
    this->desired_position = 0;
    this->omega = MAX_ANGULAR_VELOCITY;
}

HuboMotor::HuboMotor(const HuboMotor& rhs){
    this->mpos1 = rhs.mpos1;
    this->mpos2 = rhs.mpos2;
    this->Kp = rhs.Kp;
    this->Kd = rhs.Kd;
    this->Ki = rhs.Ki;
    this->dz = rhs.dz;
    this->off = rhs.off;
    this->hlim = rhs.hlim;
    this->hld = rhs.hld;
    this->hv1 = rhs.hv1;
    this->hv2 = rhs.hv2;
    this->hma = rhs.hma;
    this->sm = rhs.sm;
    this->ers = rhs.ers;
    this->as = rhs.as;
    this->md = rhs.md;
    this->v_max = rhs.v_max;
    this->a_max = rhs.a_max;
    this->jam_lim = rhs.jam_lim;
    this->jamd = rhs.jamd;
    this->pwm_lim = rhs.pwm_lim;
    this->i_err = rhs.i_err;
    this->b_err = rhs.b_err;
    this->ticks_position = rhs.ticks_position;
    this->desired_position = rhs.desired_position;
    this->omega = rhs.omega;

    //NEW_DATA
    this->name = rhs.name;
    this->currGoal = rhs.currGoal;
    this->interStep = rhs.interStep;
    this->interVel = rhs.interVel;

    this->currVel = rhs.currVel;
    this->currPos = rhs.currPos;
    this->currCurrent = rhs.currCurrent;
    this->currTemp = rhs.currTemp;

    this->enabled = rhs.enabled;
    this->homed = rhs.homed;
    this->zeroed = rhs.zeroed;
}

void HuboMotor::setUpperLimit(long limit){
    this->mpos2 = limit;
}

void HuboMotor::setLowerLimit(long limit){
    this->mpos1 = limit;
}

void HuboMotor::setPositionGain(long kp, long kd, long ki){
    this->Kp = kp;
    this->Kd = kd;
    this->Ki = ki;
}

void HuboMotor::setCurrentGain(long kpt, long kdt, long kf){
    this->Kpt = kpt;
    this->Kdt = kdt;
    this->Kf = kf;
}

void HuboMotor::setDeadZone(int dz){
    this->dz = dz;
}

void HuboMotor::setHomeset1(long off, long hlim, long hld){
    this->off = off;
    this->hlim = hlim;
    this->hld = hld;
}

void HuboMotor::setHomeset2(long hv1, long hv2, long hma, long sm){
    this->hv1 = hv1;
    this->hv2 = hv2;
    this->hma = hma;
    this->sm = sm;
}

void HuboMotor::setEncoderResolution(long ers, long as, long md){
    this->ers = ers;
    this->as = as;
    this->md = md;
}

void HuboMotor::setSpeedLimit(long vel, long acc){
    this->v_max = vel;
    this->a_max = acc;
}

void HuboMotor::setJamPowerLimit(long jam_lim, long jamd, long pwm_lim){
    this->jam_lim = jam_lim;
    this->jamd = jamd;
    this->pwm_lim = pwm_lim;
}

void HuboMotor::setErrorLimit(long i_err, long b_err){
    this->i_err = i_err;
    this->b_err = b_err;
}

void HuboMotor::setGearRatios(long drive, long driven, long harm, long enc){
	this->drive = drive;
	this->driven = driven;
	this->harm = harm;
	this->enc = enc;
}

void HuboMotor::setTicksPosition(long ticks){
    this->ticks_position = ticks;
}

void HuboMotor::setDesiredPosition(long ticks){
	this->desired_position = ticks;
}

void HuboMotor::setAngularVelocity(double omega){
	this->omega = omega;
}

long HuboMotor::getUpperLimit(){
    return this->mpos2;
}

long HuboMotor::getLowerLimit(){
    return this->mpos1;
}

long HuboMotor::getKp(){
    return this->Kp;
}

long HuboMotor::getKi(){
    return this->Ki;
}

long HuboMotor::getKd(){
    return this->Kd;
}

long HuboMotor::getKpt(){
    return this->Kpt;
}

long HuboMotor::getKdt(){
    return this->Kdt;
}

long HuboMotor::getKf(){
    return this->Kf;
}

long HuboMotor::getDz(){
    return this->dz;
}

long HuboMotor::getOff(){
    return this->off;
}

long HuboMotor::getHlim(){
    return this->hlim;
}

long HuboMotor::getHld(){
    return this->hld;
}

long HuboMotor::getHv1(){
    return this->hv1;
}

long HuboMotor::getHv2(){
    return this->hv2;
}

long HuboMotor::getHma(){
    return this->hma;
}

long HuboMotor::getSm(){
    return this->sm;
}

long HuboMotor::getErs(){
    return this->ers;
}

long HuboMotor::getAs(){
    return this->as;
}

long HuboMotor::getMd(){
    return this->md;
}

long HuboMotor::getVmax(){
    return this->v_max;
}

long HuboMotor::getAmax(){
    return this->a_max;
}

long HuboMotor::getJamLim(){
    return this->jam_lim;
}

long HuboMotor::getJamd(){
    return this->jamd;
}

long HuboMotor::getPwmLim(){
    return this->pwm_lim;
}

long HuboMotor::getIerr(){
    return i_err;
}

long HuboMotor::getBerr(){
    return b_err;
}

long HuboMotor::getTicksPosition(){
    return this->ticks_position;
}

long HuboMotor::getDesiredPosition(){
	return this->desired_position;
}

bool HuboMotor::requiresMotion(){
	return desired_position - ticks_position != 0;
}

double HuboMotor::ticksToRadians(long ticks){
	return (ticks * (double)(this->drive * 2 * M_PI))/(this->driven * this->harm * this->enc);
}

long HuboMotor::radiansToTicks(double rad){
	return (long)(rad * ((double)(this->driven * this->harm * this->enc))/(this->drive * 2 * M_PI));
}

long HuboMotor::interpolate(int MAX_STEP, int MIN_STEP){
	const float LEAP_PERCENTAGE = .5;
	const int FREQUENCY = 100; //Hertz
	if (MAX_STEP == 0)
		MAX_STEP = radiansToTicks(omega) / 100;

	int error = desired_position - ticks_position;
	int output = desired_position;

	if((abs(error) > MIN_STEP)){
		output = (int)(LEAP_PERCENTAGE * error);

		if(abs(output) > MAX_STEP)
			output = output < 0 ? -MAX_STEP : MAX_STEP;

	} else
		output = error;

	output += ticks_position;
	ticks_position = output;
	return output;
}

double HuboMotor::interpolate(){
	const float LEAP_PERCENTAGE = .5;
	const float MIN_STEP = .01;
	const float MAX_STEP = interVel/100; //Radians per second, divided by our operating frequency.

	double error = currGoal - interStep;
	double output = currGoal;

	if((abs(error) > MIN_STEP)){
		output = (int)(LEAP_PERCENTAGE * error);

		if(abs(output) > MAX_STEP)
			output = output < 0 ? -MAX_STEP : MAX_STEP;

	} else
		output = error;

	output += interStep;
	interStep = output;
	return interStep;
}

void HuboMotor::setName(string name){
	this->name = name;
}

void HuboMotor::setGoalPosition(double rads){
	currGoal = rads;
}

void HuboMotor::setInterVelocity(double omega){
	interVel = omega;
}

void HuboMotor::update(double position, double velocity, double temperature, double current){
	currPos = position;
	currVel = velocity;
	currTemp = temperature;
	currCurrent = current;
}

void HuboMotor::setEnabled(bool enabled){
	this->enabled = enabled;
	interStep = currPos; //If we have recently changed from non-interpolation to interpolation, the step MUST be updated.
}

void HuboMotor::setHomed(bool homed){
	this->homed = homed;
}

void HuboMotor::setZeroed(bool zeroed){
	this->zeroed = zeroed;
}

string HuboMotor::getName(){
	return name;
}

double HuboMotor::getGoalPosition(){
	return currGoal;
}

double HuboMotor::getPosition(){
	return currPos;
}

double HuboMotor::getVelocity(){
	return currVel;
}

double HuboMotor::getTemperature(){
	return currTemp;
}

double HuboMotor::getCurrent(){
	return currCurrent;
}

bool HuboMotor::isEnabled(){
	return enabled;
}

bool HuboMotor::isHomed(){
	return homed;
}

bool HuboMotor::isZeroed(){
	return zeroed;
}

<commit_msg>Attempting strange fix...<commit_after>#include "HuboMotor.h"
#include <string>
#include <iostream>

HuboMotor::HuboMotor(){
    this->ticks_position = 0;
    this->desired_position = 0;
    this->omega = MAX_ANGULAR_VELOCITY;

    //NEW_DATA
    currGoal = 0;
	interStep = 0;
	interVel = 0;

	currVel = 0;
	currPos = 0;
	currCurrent = 0;
	currTemp = 0;

	enabled = false;
	homed = false;
	zeroed = false;
}

HuboMotor::HuboMotor(long mpos1, long mpos2, long kp, long kd, long ki,
                     long dz, long off, long hlim, long hld, long hv1,
                     long hv2, long hma, long sm, long ers, long as, long md,
                     long v_max, long a_max, long jam_lim, long jamd,
                     long pwm_lim, long i_err, long b_err){
    this->mpos1 = mpos1;
    this->mpos2 = mpos2;
    this->Kp = kp;
    this->Kd = kd;
    this->Ki = ki;
    this->dz = dz;
    this->off = off;
    this->hlim = hlim;
    this->hld = hld;
    this->hv1 = hv1;
    this->hv2 = hv2;
    this->hma = hma;
    this->sm = sm;
    this->ers = ers;
    this->as = as;
    this->md = md;
    this->v_max = v_max;
    this->a_max = a_max;
    this->jam_lim = jam_lim;
    this->jamd = jamd;
    this->pwm_lim = pwm_lim;
    this->i_err = i_err;
    this->b_err = b_err;
    this->ticks_position = 0;
    this->desired_position = 0;
    this->omega = MAX_ANGULAR_VELOCITY;
}

HuboMotor::HuboMotor(const HuboMotor& rhs){
    this->mpos1 = rhs.mpos1;
    this->mpos2 = rhs.mpos2;
    this->Kp = rhs.Kp;
    this->Kd = rhs.Kd;
    this->Ki = rhs.Ki;
    this->dz = rhs.dz;
    this->off = rhs.off;
    this->hlim = rhs.hlim;
    this->hld = rhs.hld;
    this->hv1 = rhs.hv1;
    this->hv2 = rhs.hv2;
    this->hma = rhs.hma;
    this->sm = rhs.sm;
    this->ers = rhs.ers;
    this->as = rhs.as;
    this->md = rhs.md;
    this->v_max = rhs.v_max;
    this->a_max = rhs.a_max;
    this->jam_lim = rhs.jam_lim;
    this->jamd = rhs.jamd;
    this->pwm_lim = rhs.pwm_lim;
    this->i_err = rhs.i_err;
    this->b_err = rhs.b_err;
    this->ticks_position = rhs.ticks_position;
    this->desired_position = rhs.desired_position;
    this->omega = rhs.omega;

    //NEW_DATA
    this->name = rhs.name;
    this->currGoal = rhs.currGoal;
    this->interStep = rhs.interStep;
    this->interVel = rhs.interVel;

    this->currVel = rhs.currVel;
    this->currPos = rhs.currPos;
    this->currCurrent = rhs.currCurrent;
    this->currTemp = rhs.currTemp;

    this->enabled = rhs.enabled;
    this->homed = rhs.homed;
    this->zeroed = rhs.zeroed;
}

void HuboMotor::setUpperLimit(long limit){
    this->mpos2 = limit;
}

void HuboMotor::setLowerLimit(long limit){
    this->mpos1 = limit;
}

void HuboMotor::setPositionGain(long kp, long kd, long ki){
    this->Kp = kp;
    this->Kd = kd;
    this->Ki = ki;
}

void HuboMotor::setCurrentGain(long kpt, long kdt, long kf){
    this->Kpt = kpt;
    this->Kdt = kdt;
    this->Kf = kf;
}

void HuboMotor::setDeadZone(int dz){
    this->dz = dz;
}

void HuboMotor::setHomeset1(long off, long hlim, long hld){
    this->off = off;
    this->hlim = hlim;
    this->hld = hld;
}

void HuboMotor::setHomeset2(long hv1, long hv2, long hma, long sm){
    this->hv1 = hv1;
    this->hv2 = hv2;
    this->hma = hma;
    this->sm = sm;
}

void HuboMotor::setEncoderResolution(long ers, long as, long md){
    this->ers = ers;
    this->as = as;
    this->md = md;
}

void HuboMotor::setSpeedLimit(long vel, long acc){
    this->v_max = vel;
    this->a_max = acc;
}

void HuboMotor::setJamPowerLimit(long jam_lim, long jamd, long pwm_lim){
    this->jam_lim = jam_lim;
    this->jamd = jamd;
    this->pwm_lim = pwm_lim;
}

void HuboMotor::setErrorLimit(long i_err, long b_err){
    this->i_err = i_err;
    this->b_err = b_err;
}

void HuboMotor::setGearRatios(long drive, long driven, long harm, long enc){
	this->drive = drive;
	this->driven = driven;
	this->harm = harm;
	this->enc = enc;
}

void HuboMotor::setTicksPosition(long ticks){
    this->ticks_position = ticks;
}

void HuboMotor::setDesiredPosition(long ticks){
	this->desired_position = ticks;
}

void HuboMotor::setAngularVelocity(double omega){
	this->omega = omega;
}

long HuboMotor::getUpperLimit(){
    return this->mpos2;
}

long HuboMotor::getLowerLimit(){
    return this->mpos1;
}

long HuboMotor::getKp(){
    return this->Kp;
}

long HuboMotor::getKi(){
    return this->Ki;
}

long HuboMotor::getKd(){
    return this->Kd;
}

long HuboMotor::getKpt(){
    return this->Kpt;
}

long HuboMotor::getKdt(){
    return this->Kdt;
}

long HuboMotor::getKf(){
    return this->Kf;
}

long HuboMotor::getDz(){
    return this->dz;
}

long HuboMotor::getOff(){
    return this->off;
}

long HuboMotor::getHlim(){
    return this->hlim;
}

long HuboMotor::getHld(){
    return this->hld;
}

long HuboMotor::getHv1(){
    return this->hv1;
}

long HuboMotor::getHv2(){
    return this->hv2;
}

long HuboMotor::getHma(){
    return this->hma;
}

long HuboMotor::getSm(){
    return this->sm;
}

long HuboMotor::getErs(){
    return this->ers;
}

long HuboMotor::getAs(){
    return this->as;
}

long HuboMotor::getMd(){
    return this->md;
}

long HuboMotor::getVmax(){
    return this->v_max;
}

long HuboMotor::getAmax(){
    return this->a_max;
}

long HuboMotor::getJamLim(){
    return this->jam_lim;
}

long HuboMotor::getJamd(){
    return this->jamd;
}

long HuboMotor::getPwmLim(){
    return this->pwm_lim;
}

long HuboMotor::getIerr(){
    return i_err;
}

long HuboMotor::getBerr(){
    return b_err;
}

long HuboMotor::getTicksPosition(){
    return this->ticks_position;
}

long HuboMotor::getDesiredPosition(){
	return this->desired_position;
}

bool HuboMotor::requiresMotion(){
	return desired_position - ticks_position != 0;
}

double HuboMotor::ticksToRadians(long ticks){
	return (ticks * (double)(this->drive * 2 * M_PI))/(this->driven * this->harm * this->enc);
}

long HuboMotor::radiansToTicks(double rad){
	return (long)(rad * ((double)(this->driven * this->harm * this->enc))/(this->drive * 2 * M_PI));
}

long HuboMotor::interpolate(int MAX_STEP, int MIN_STEP){
	const float LEAP_PERCENTAGE = .5;
	const int FREQUENCY = 100; //Hertz
	if (MAX_STEP == 0)
		MAX_STEP = radiansToTicks(omega) / 100;

	int error = desired_position - ticks_position;
	int output = desired_position;

	if((abs(error) > MIN_STEP)){
		output = (int)(LEAP_PERCENTAGE * error);

		if(abs(output) > MAX_STEP)
			output = output < 0 ? -MAX_STEP : MAX_STEP;

	} else
		output = error;

	output += ticks_position;
	ticks_position = output;
	return output;
}

double HuboMotor::interpolate(){
	const float LEAP_PERCENTAGE = .5;
	const double MIN_STEP = .0001;
	const double MAX_STEP = interVel/100; //Radians per second, divided by our operating frequency.

	double error = currGoal - interStep;
	double output = currGoal;

	if((abs(error) > MIN_STEP)){
		output = (int)(LEAP_PERCENTAGE * error);

		if(abs(output) > MAX_STEP)
			output = output < 0 ? -MAX_STEP : MAX_STEP;

	} else
		output = error;

	output += interStep;
	interStep = output;
	return interStep;
}

void HuboMotor::setName(string name){
	this->name = name;
}

void HuboMotor::setGoalPosition(double rads){
	currGoal = rads;
}

void HuboMotor::setInterVelocity(double omega){
	interVel = omega;
}

void HuboMotor::update(double position, double velocity, double temperature, double current){
	currPos = position;
	currVel = velocity;
	currTemp = temperature;
	currCurrent = current;
}

void HuboMotor::setEnabled(bool enabled){
	this->enabled = enabled;
	interStep = currPos; //If we have recently changed from non-interpolation to interpolation, the step MUST be updated.
}

void HuboMotor::setHomed(bool homed){
	this->homed = homed;
}

void HuboMotor::setZeroed(bool zeroed){
	this->zeroed = zeroed;
}

string HuboMotor::getName(){
	return name;
}

double HuboMotor::getGoalPosition(){
	return currGoal;
}

double HuboMotor::getPosition(){
	return currPos;
}

double HuboMotor::getVelocity(){
	return currVel;
}

double HuboMotor::getTemperature(){
	return currTemp;
}

double HuboMotor::getCurrent(){
	return currCurrent;
}

bool HuboMotor::isEnabled(){
	return enabled;
}

bool HuboMotor::isHomed(){
	return homed;
}

bool HuboMotor::isZeroed(){
	return zeroed;
}

<|endoftext|>


<commit_before>//
//  Scene.cpp
//  RoboChase
//
//  Created by nsp on 29/3/17.
//  Copyright © 2017 nspool. All rights reserved.
//

#include "Scene.hpp"

Scene::Scene(SDL_Renderer* renderer)
{
  _renderer = renderer;
}

void Scene::AddPlayer(Player* player) {
  _player = player;
}

void Scene::Add(Sprite *sprite)
{
  _sprites.push_back(sprite);
}

SDL_Point Scene::doEvent(SDL_Point nextPos)
{
  std::vector<SDL_Rect> obsticles;

  SDL_Point newPos;

  // FIXME: Quick & Dirty collision detection
  for(auto& r : _sprites) {

    if(r->isObsticle()) {
      obsticles.push_back(r->getBounds());
    }

    for(auto& s : _sprites) {
      if(r == s) { continue; }
      SDL_Rect result = SDL_Rect();
      SDL_Rect r_rect = r->getBounds();
      SDL_Rect s_rect = s->getBounds();
      if(SDL_IntersectRect(&r_rect, &s_rect, &result)== SDL_TRUE) {
        r->doCollision(&s_rect);
      }
    }
  }

  // FIXME: Update player position, *then* check for collision

  bool playerCollision = false;

  SDL_Rect s_rect;
  s_rect.x = nextPos.x - 7;
  s_rect.y = nextPos.y - 7;
  s_rect.w = 14;
  s_rect.h = 14;

  for(auto& r : _sprites) {
    SDL_Rect result = SDL_Rect();
    SDL_Rect r_rect = r->getBounds();
    if(SDL_IntersectRect(&r_rect, &s_rect, &result)== SDL_TRUE) {
      r->doCollision(&s_rect);
      playerCollision = true;
      break;
    }
  }

  if(!playerCollision) {
    SDL_Rect playerPos = _player->getBounds();
    _prevPlayerPosition.x = playerPos.x;
    _prevPlayerPosition.y = playerPos.y;
    _player->action(&nextPos, &obsticles);
    newPos = nextPos;
  } else {
    newPos.x = _prevPlayerPosition.x;
    newPos.y = _prevPlayerPosition.y;
  }

  // Update the sprite goals & render the next frame
  for(auto& r : _sprites) {
    r->action(_playerPosition, &obsticles);
    r->render();
  }

  _player->render();

  return newPos;
}
<commit_msg>Extremely basic player collision detection<commit_after>//
//  Scene.cpp
//  RoboChase
//
//  Created by nsp on 29/3/17.
//  Copyright © 2017 nspool. All rights reserved.
//

#include "Scene.hpp"

Scene::Scene(SDL_Renderer* renderer)
{
  _renderer = renderer;
}

void Scene::AddPlayer(Player* player) {
  _player = player;
}

void Scene::Add(Sprite *sprite)
{
  _sprites.push_back(sprite);
}

SDL_Point Scene::doEvent(SDL_Point nextPos)
{
  std::vector<SDL_Rect> obsticles;

  SDL_Point newPos;

  // FIXME: Quick & Dirty collision detection
  for(auto& r : _sprites) {

    if(r->isObsticle()) {
      obsticles.push_back(r->getBounds());
    }

    for(auto& s : _sprites) {
      if(r == s) { continue; }
      SDL_Rect result = SDL_Rect();
      SDL_Rect r_rect = r->getBounds();
      SDL_Rect s_rect = s->getBounds();
      if(SDL_IntersectRect(&r_rect, &s_rect, &result)== SDL_TRUE) {
        r->doCollision(&s_rect);
      }
    }
  }

  // FIXME: Update player position, *then* check for collision

  bool playerCollision = false;

  SDL_Rect s_rect;
  s_rect.x = nextPos.x;
  s_rect.y = nextPos.y;
  s_rect.w = 21;
  s_rect.h = 31;

  for(auto& r : _sprites) {
    SDL_Rect result = SDL_Rect();
    SDL_Rect r_rect = r->getBounds();
    if(SDL_IntersectRect(&r_rect, &s_rect, &result)== SDL_TRUE) {
      r->doCollision(&s_rect);
      playerCollision = true;
      break;
    }
  }

  if(!playerCollision) {
    SDL_Rect playerPos = _player->getBounds();
    _prevPlayerPosition.x = playerPos.x;
    _prevPlayerPosition.y = playerPos.y;
    _player->action(&nextPos, &obsticles);
    newPos = nextPos;
  } else {
    newPos.x = _prevPlayerPosition.x;
    newPos.y = _prevPlayerPosition.y;
  }

  // Update the sprite goals & render the next frame
  for(auto& r : _sprites) {
    r->action(_playerPosition, &obsticles);
    r->render();
  }

  _player->render();

  return newPos;
}
<|endoftext|>


<commit_before>#include <algorithm>
#include "log.h"
#include "row.h"
#include "table.h"
#include "table_iter.h"
#include "zmq_util.h"
#include "msg_pack.h"
#include "server.h"
#include "stop_watch.h"

namespace multiverso
{
    // Initializes the basic info and starts a server thread.
    Server::Server(int server_id, int num_worker_process, std::string endpoint) :
        clocks_(num_worker_process, 0),
        clock_msg_(num_worker_process, nullptr),
        lock_pool_(41)
    {
        server_id_ = server_id;
        worker_proc_count_ = num_worker_process;
        endpoint_ = endpoint;
        max_delay_ = -1;

        is_working_ = false;
        inited_ = false;
        server_thread_ = std::thread(&Server::StartThread, this);
        // keep waiting until the server thread goes into the working routine
        while (!is_working_)
        {
            std::this_thread::sleep_for(std::chrono::microseconds(10));
        }
    }

    // Closes and destroy the server
    Server::~Server()
    {
        is_working_ = false;
        WaitToComplete();
        Log::Info("Server %d closed.\n", server_id_);
    }

    // Waits for the server thread completed
    void Server::WaitToComplete()
    {
        if (server_thread_.joinable())
        {
            server_thread_.join();
        }
    }

    // Initialization at the beginning of the server thread.
    void Server::Init()
    {
        // communication stuffs
        router_ = new zmq::socket_t(ZMQUtil::GetZMQContext(), ZMQ_ROUTER);
        router_->bind(endpoint_.c_str());
        poll_count_ = 1;
        poll_items_ = new zmq::pollitem_t[poll_count_];
        // for vs2013
        poll_items_[0] = { static_cast<void*>(*router_), 0, ZMQ_POLLIN, 0 };
        // for vs2012
        //poll_items_[0].socket = *router_;
        //poll_items_[0].fd = 0;
        //poll_items_[0].events = ZMQ_POLLIN;
        //poll_items_[0].revents = 0;
        update_thread_ = std::thread(&Server::StartUpdateThread, this);
        Log::Info("Server %d starts: num_workers=%d endpoint=%s\n",
            server_id_, worker_proc_count_, endpoint_.c_str());
    }

    // Clean up at the end of the server thread
    void Server::Clear()
    {
        update_queue_.Exit();
        if (update_thread_.joinable())
        {
            update_thread_.join();
        }
        delete router_;
        delete []poll_items_;
        // Dump model before Clear
        DumpModel();
        for (auto &table : tables_)
        {
            delete table;
        }
    }

    // Server background thread function
    void Server::StartThread()
    {
        MsgType msg_type;
        MsgArrow arrow;
        int src, dst;

        Init();
        std::vector<zmq::socket_t*> sockets;
        sockets.push_back(router_);
        std::queue<std::shared_ptr<MsgPack>> msg_queue;
        is_working_ = true;
        while (is_working_)
        {
            ZMQUtil::ZMQPoll(poll_items_, poll_count_, sockets, msg_queue);
            while (!msg_queue.empty())
            {
                std::shared_ptr<MsgPack> msg_pack = msg_queue.front();
                msg_queue.pop();
                msg_pack->GetHeaderInfo(&msg_type, &arrow, &src, &dst);
                switch (msg_type)
                {
                case MsgType::Register: Process_Register(msg_pack); break;
                case MsgType::Close: Process_Close(msg_pack); break;
                case MsgType::Barrier: inited_ = Process_Barrier(msg_pack); break;
                case MsgType::CreateTable: Process_CreateTable(msg_pack); break;
                case MsgType::SetRow: Process_SetRow(msg_pack); break;
                case MsgType::Clock: Process_Clock(msg_pack); break;
                case MsgType::EndTrain: Process_EndTrain(msg_pack); break;
                case MsgType::Get: Process_Get(msg_pack); break;
                case MsgType::Add: inited_ ? update_queue_.Push(msg_pack)
                    : Process_Add(msg_pack); break;
                // case MsgType::Add: Process_Add(msg_pack); break;
                // other message process...
                }
            }
        }
        Clear();
    }

    void Server::StartUpdateThread()
    {
        std::shared_ptr<MsgPack> msg_pack;
        while (update_queue_.Pop(msg_pack))
        {
            Process_Add(msg_pack);
        }
    }

    // REMARK (feiyan): consider a Register pattern
    //-- Server process routine ---------------------------------------------//
    // processes register message
    void Server::Process_Register(std::shared_ptr<MsgPack> msg_pack)
    {
        waiting_msg_.push_back(msg_pack);
        // If all expected workers come, process the information, assign them
        // IDs and reply all back
        if (waiting_msg_.size() == worker_proc_count_)
        {
            // basic statistics
            int total_trainers = 0;
            int server_count = 0;
            for (auto &msg : waiting_msg_)
            {
                int *buffer = static_cast<int*>(msg->GetMsg(1)->data());
                total_trainers += buffer[0];    // sum up number of trainers
                if (server_count == 0)          // verify the number of servers
                {
                    server_count = buffer[1];
                }
                else if (server_count != buffer[1])
                {
                    server_count = -1;
                }
                max_delay_ = std::max<int>(max_delay_, buffer[2]);
            }
            // reply each worker process
            for (int rank = 0; rank < waiting_msg_.size(); ++rank)
            {
                MsgPack *reply = waiting_msg_[rank]->CreateReplyMsgPack();
                zmq::message_t *msg = new zmq::message_t(4 * sizeof(int));
                int *buffer = static_cast<int*>(msg->data());
                buffer[0] = rank;               // assigned process rank
                buffer[1] = worker_proc_count_; // number of worker processes
                buffer[2] = server_count;       // number of servers
                buffer[3] = total_trainers;     // total number of trainers
                reply->Push(msg);
                reply->Send(router_);
                delete reply;
            }
            waiting_msg_.clear();

            Log::Info(
                "Server %d: Worker registratrion completed: workers=%d trainers=%d servers=%d\n",
                server_id_, worker_proc_count_, total_trainers, server_count);
        } // end if
    }

    // processes close message
    void Server::Process_Close(std::shared_ptr<MsgPack> msg_pack)
    {
        MsgType msg_type;
        MsgArrow arrow;
        int src, dst;
        msg_pack->GetHeaderInfo(&msg_type, &arrow, &src, &dst);
        Log::Info("Server %d: Received close message from worker %d.\n", server_id_, src);
        // if the last worker comes, stop the server thread
        if (Process_Barrier(msg_pack))
        {
            is_working_ = false;
        }
    }

    // process barrier message, returns true if the last one comes,
    // or false otherwise
    bool Server::Process_Barrier(std::shared_ptr<MsgPack> msg_pack)
    {
        waiting_msg_.push_back(msg_pack);
        // if the last expected worker comes, reply all pending workers
        if (waiting_msg_.size() == worker_proc_count_)
        {
            for (auto &msg : waiting_msg_)
            {
                MsgPack *reply = msg->CreateReplyMsgPack();
                reply->Send(router_);
                delete reply;
            }
            waiting_msg_.clear();
            return true;
        }
        return false;
    }

    // process create table message
    void Server::Process_CreateTable(std::shared_ptr<MsgPack> msg_pack)
    {
        integer_t table_id, rows, cols;
        Type type;
        Format format;
        integer_t *buf = static_cast<integer_t*>(msg_pack->GetMsg(1)->data());
        table_id = buf[0];                          // table_id
        rows = buf[1];                              // rows
        cols = buf[2];                              // cols
        int *buf_i = static_cast<int*>(buf + 3);
        type = static_cast<Type>(buf_i[0]);         // type
        format = static_cast<Format>(buf_i[1]);     // default format

        // the calling should be in order starting from 0, process the first
        // come and ignore the others
        if (table_id == tables_.size())
        {
            tables_.push_back(new Table(table_id, rows, cols, type, format));
        }
    }

    // process set row message
    void Server::Process_SetRow(std::shared_ptr<MsgPack> msg_pack)
    {
        integer_t table_id, row_id, capacity;
        Format format;
        for (int idx = 1; idx < msg_pack->Size(); ++idx)
        {
            integer_t *buf = static_cast<integer_t*>(msg_pack->GetMsg(idx)->data());
            table_id = buf[0];                      // table_id
            row_id = buf[1];                        // row_id
            capacity = buf[2];                      // capacity
            memcpy(&format, buf + 3, sizeof(int));  // format
            tables_[table_id]->SetRow(row_id, format, capacity);
        }
    }

    void Server::Process_Clock(std::shared_ptr<MsgPack> msg_pack)
    {
        MsgType msg_type;
        MsgArrow arrow;
        int src, dst;
        msg_pack->GetHeaderInfo(&msg_type, &arrow, &src, &dst);

        if (max_delay_ < 0) // ASP model, reply immediately
        {
            MsgPack *reply = msg_pack->CreateReplyMsgPack();
            reply->Send(router_);
            delete reply;
        }
        else
        {
            clock_msg_[src] = msg_pack;
            clocks_[src]++;
            int upper_bound =
                *std::min_element(clocks_.begin(), clocks_.end()) + max_delay_;
            for (int worker = 0; worker < worker_proc_count_; ++worker)
            {
                if (clocks_[worker] <= upper_bound && clock_msg_[worker] != nullptr)
                {
                    MsgPack *reply = clock_msg_[worker]->CreateReplyMsgPack();
                    reply->Send(router_);
                    delete reply;
                    clock_msg_[worker] = nullptr;
                }
            }
        }
    }

    void Server::Process_EndTrain(std::shared_ptr<MsgPack> msg_pack)
    {
        MsgType msg_type;
        MsgArrow arrow;
        int src, dst;
        msg_pack->GetHeaderInfo(&msg_type, &arrow, &src, &dst);
        clocks_[src] = 1 << 31;
        int upper_bound =
            *std::min_element(clocks_.begin(), clocks_.end()) + max_delay_;
        for (int worker = 0; worker < worker_proc_count_; ++worker)
        {
            if (clocks_[worker] <= upper_bound && clock_msg_[worker] != nullptr)
            {
                MsgPack *reply = clock_msg_[worker]->CreateReplyMsgPack();
                reply->Send(router_);
                delete reply;
                clock_msg_[worker] = nullptr;
            }
        }
    }

    // processes get message
    void Server::Process_Get(std::shared_ptr<MsgPack> msg_pack)
    {
        MsgPack* reply = msg_pack->CreateReplyMsgPack();
        int send_ret_size = 0;
        for (int i = 1; i < msg_pack->Size(); ++i)
        {
            zmq::message_t* msg = msg_pack->GetMsg(i);
            integer_t* buffer = static_cast<integer_t*>(msg->data());
            integer_t table = buffer[0];
            integer_t row = buffer[1];
            integer_t col = buffer[2];
            if (row == -1)
            {
                TableIterator iter = tables_[table]->Iterator();
                while (iter.HasNext())
                {
                    integer_t request_row = iter.RowId();
                    lock_pool_.Lock(row);
                    Process_GetRow(table, request_row, col, msg_pack,
                        send_ret_size, reply);
                    lock_pool_.Unlock(row);
                    iter.Next();
                }
            }
            else
            {
                lock_pool_.Lock(row);
                Process_GetRow(table, row, col, msg_pack, send_ret_size, reply);
                lock_pool_.Unlock(row);
            }
        }
        zmq::message_t *tail = new zmq::message_t(sizeof(integer_t));
        integer_t* over_tag = static_cast<integer_t*>(tail->data());
        *over_tag = 1;
        reply->Push(tail);
        reply->Send(router_);
        delete reply;
    }

    // processing get row
    void Server::Process_GetRow(integer_t table, integer_t row, integer_t col,
        std::shared_ptr<MsgPack> msg_pack, int& send_ret_size, MsgPack*& reply)
    {
        integer_t row_size = (col >= 0) ? 1 :
            tables_[table]->GetRow(row)->NonzeroSize();
        int msg_size = sizeof(integer_t)* 3 + row_size *
            (sizeof(integer_t)+tables_[table]->ElementSize());
        if (send_ret_size + msg_size > kMaxMsgSize)
        {
            zmq::message_t *tail = new zmq::message_t(sizeof(integer_t));
            integer_t* over_tag = static_cast<integer_t*>(tail->data());
            *over_tag = 0;
            reply->Push(tail);
            reply->Send(router_);
            delete reply;
            reply = msg_pack->CreateReplyMsgPack();
            send_ret_size = 0;
        }
        zmq::message_t *row_msg = new zmq::message_t(msg_size);
        integer_t *buffer = static_cast<integer_t*>(row_msg->data());
        // Format: table_id, row_id, number
        //         col_1, col2, ..., col_n, val_1, val_2, ..., val_n;
        buffer[0] = table;
        buffer[1] = row;
        if (col >= 0)
        {
            buffer[2] = 1;
            buffer[3] = col;
            tables_[table]->GetRow(row)->At(col, buffer + 4);
        }
        else
        {
            tables_[table]->GetRow(row)->Serialize(buffer + 2);
        }
        reply->Push(row_msg);
        send_ret_size += msg_size;
    }

    // processes add message
    void Server::Process_Add(std::shared_ptr<MsgPack> msg_pack)
    {
        for (int i = 1; i < msg_pack->Size(); ++i)
        {
            zmq::message_t* msg = msg_pack->GetMsg(i);
            integer_t* buffer = static_cast<integer_t*>(msg->data());
            integer_t table = buffer[0];
            integer_t row = buffer[1];
            lock_pool_.Lock(row);
            tables_[table]->GetRow(row)->BatchAdd(buffer + 2);
            lock_pool_.Unlock(row);
        }
    }
    //-- end of server process routine ---------------------------------------/

    void Server::DumpModel()
    {
        Log::Info("Server %d: Dump model...\n", server_id_);
        for (int i = 0; i < tables_.size(); ++i)
        {
            // dump model to file server_$server_id$_table_$table_id$.model
            std::string file_name = "server_" + std::to_string(server_id_)
                + "_table_" + std::to_string(i) + ".model";
            std::ofstream fout(file_name);

            Table *table = tables_[i];
            TableIterator iter = table->Iterator();
            int size = table->ElementSize();
            while (iter.HasNext())
            {
                fout << iter.Row()->ToString() << std::endl;
                iter.Next();
            }
            fout.close();
        }
    }
}
<commit_msg>fix a bug when server process end train<commit_after>#include <algorithm>
#include "log.h"
#include "row.h"
#include "table.h"
#include "table_iter.h"
#include "zmq_util.h"
#include "msg_pack.h"
#include "server.h"
#include "stop_watch.h"

namespace multiverso
{
    // Initializes the basic info and starts a server thread.
    Server::Server(int server_id, int num_worker_process, std::string endpoint) :
        clocks_(num_worker_process, 0),
        clock_msg_(num_worker_process, nullptr),
        lock_pool_(41)
    {
        server_id_ = server_id;
        worker_proc_count_ = num_worker_process;
        endpoint_ = endpoint;
        max_delay_ = -1;

        is_working_ = false;
        inited_ = false;
        server_thread_ = std::thread(&Server::StartThread, this);
        // keep waiting until the server thread goes into the working routine
        while (!is_working_)
        {
            std::this_thread::sleep_for(std::chrono::microseconds(10));
        }
    }

    // Closes and destroy the server
    Server::~Server()
    {
        is_working_ = false;
        WaitToComplete();
        Log::Info("Server %d closed.\n", server_id_);
    }

    // Waits for the server thread completed
    void Server::WaitToComplete()
    {
        if (server_thread_.joinable())
        {
            server_thread_.join();
        }
    }

    // Initialization at the beginning of the server thread.
    void Server::Init()
    {
        // communication stuffs
        router_ = new zmq::socket_t(ZMQUtil::GetZMQContext(), ZMQ_ROUTER);
        router_->bind(endpoint_.c_str());
        poll_count_ = 1;
        poll_items_ = new zmq::pollitem_t[poll_count_];
        // for vs2013
        poll_items_[0] = { static_cast<void*>(*router_), 0, ZMQ_POLLIN, 0 };
        // for vs2012
        //poll_items_[0].socket = *router_;
        //poll_items_[0].fd = 0;
        //poll_items_[0].events = ZMQ_POLLIN;
        //poll_items_[0].revents = 0;
        update_thread_ = std::thread(&Server::StartUpdateThread, this);
        Log::Info("Server %d starts: num_workers=%d endpoint=%s\n",
            server_id_, worker_proc_count_, endpoint_.c_str());
    }

    // Clean up at the end of the server thread
    void Server::Clear()
    {
        update_queue_.Exit();
        if (update_thread_.joinable())
        {
            update_thread_.join();
        }
        delete router_;
        delete []poll_items_;
        // Dump model before Clear
        DumpModel();
        for (auto &table : tables_)
        {
            delete table;
        }
    }

    // Server background thread function
    void Server::StartThread()
    {
        MsgType msg_type;
        MsgArrow arrow;
        int src, dst;

        Init();
        std::vector<zmq::socket_t*> sockets;
        sockets.push_back(router_);
        std::queue<std::shared_ptr<MsgPack>> msg_queue;
        is_working_ = true;
        while (is_working_)
        {
            ZMQUtil::ZMQPoll(poll_items_, poll_count_, sockets, msg_queue);
            while (!msg_queue.empty())
            {
                std::shared_ptr<MsgPack> msg_pack = msg_queue.front();
                msg_queue.pop();
                msg_pack->GetHeaderInfo(&msg_type, &arrow, &src, &dst);
                switch (msg_type)
                {
                case MsgType::Register: Process_Register(msg_pack); break;
                case MsgType::Close: Process_Close(msg_pack); break;
                case MsgType::Barrier: inited_ = Process_Barrier(msg_pack); break;
                case MsgType::CreateTable: Process_CreateTable(msg_pack); break;
                case MsgType::SetRow: Process_SetRow(msg_pack); break;
                case MsgType::Clock: Process_Clock(msg_pack); break;
                case MsgType::EndTrain: Process_EndTrain(msg_pack); break;
                case MsgType::Get: Process_Get(msg_pack); break;
                case MsgType::Add: inited_ ? update_queue_.Push(msg_pack)
                    : Process_Add(msg_pack); break;
                // case MsgType::Add: Process_Add(msg_pack); break;
                // other message process...
                }
            }
        }
        Clear();
    }

    void Server::StartUpdateThread()
    {
        std::shared_ptr<MsgPack> msg_pack;
        while (update_queue_.Pop(msg_pack))
        {
            Process_Add(msg_pack);
        }
    }

    // REMARK (feiyan): consider a Register pattern
    //-- Server process routine ---------------------------------------------//
    // processes register message
    void Server::Process_Register(std::shared_ptr<MsgPack> msg_pack)
    {
        waiting_msg_.push_back(msg_pack);
        // If all expected workers come, process the information, assign them
        // IDs and reply all back
        if (waiting_msg_.size() == worker_proc_count_)
        {
            // basic statistics
            int total_trainers = 0;
            int server_count = 0;
            for (auto &msg : waiting_msg_)
            {
                int *buffer = static_cast<int*>(msg->GetMsg(1)->data());
                total_trainers += buffer[0];    // sum up number of trainers
                if (server_count == 0)          // verify the number of servers
                {
                    server_count = buffer[1];
                }
                else if (server_count != buffer[1])
                {
                    server_count = -1;
                }
                max_delay_ = std::max<int>(max_delay_, buffer[2]);
            }
            // reply each worker process
            for (int rank = 0; rank < waiting_msg_.size(); ++rank)
            {
                MsgPack *reply = waiting_msg_[rank]->CreateReplyMsgPack();
                zmq::message_t *msg = new zmq::message_t(4 * sizeof(int));
                int *buffer = static_cast<int*>(msg->data());
                buffer[0] = rank;               // assigned process rank
                buffer[1] = worker_proc_count_; // number of worker processes
                buffer[2] = server_count;       // number of servers
                buffer[3] = total_trainers;     // total number of trainers
                reply->Push(msg);
                reply->Send(router_);
                delete reply;
            }
            waiting_msg_.clear();

            Log::Info(
                "Server %d: Worker registratrion completed: workers=%d trainers=%d servers=%d\n",
                server_id_, worker_proc_count_, total_trainers, server_count);
        } // end if
    }

    // processes close message
    void Server::Process_Close(std::shared_ptr<MsgPack> msg_pack)
    {
        MsgType msg_type;
        MsgArrow arrow;
        int src, dst;
        msg_pack->GetHeaderInfo(&msg_type, &arrow, &src, &dst);
        Log::Info("Server %d: Received close message from worker %d.\n", server_id_, src);
        // if the last worker comes, stop the server thread
        if (Process_Barrier(msg_pack))
        {
            is_working_ = false;
        }
    }

    // process barrier message, returns true if the last one comes,
    // or false otherwise
    bool Server::Process_Barrier(std::shared_ptr<MsgPack> msg_pack)
    {
        waiting_msg_.push_back(msg_pack);
        // if the last expected worker comes, reply all pending workers
        if (waiting_msg_.size() == worker_proc_count_)
        {
            for (auto &msg : waiting_msg_)
            {
                MsgPack *reply = msg->CreateReplyMsgPack();
                reply->Send(router_);
                delete reply;
            }
            waiting_msg_.clear();
            return true;
        }
        return false;
    }

    // process create table message
    void Server::Process_CreateTable(std::shared_ptr<MsgPack> msg_pack)
    {
        integer_t table_id, rows, cols;
        Type type;
        Format format;
        integer_t *buf = static_cast<integer_t*>(msg_pack->GetMsg(1)->data());
        table_id = buf[0];                          // table_id
        rows = buf[1];                              // rows
        cols = buf[2];                              // cols
        int *buf_i = static_cast<int*>(buf + 3);
        type = static_cast<Type>(buf_i[0]);         // type
        format = static_cast<Format>(buf_i[1]);     // default format

        // the calling should be in order starting from 0, process the first
        // come and ignore the others
        if (table_id == tables_.size())
        {
            tables_.push_back(new Table(table_id, rows, cols, type, format));
        }
    }

    // process set row message
    void Server::Process_SetRow(std::shared_ptr<MsgPack> msg_pack)
    {
        integer_t table_id, row_id, capacity;
        Format format;
        for (int idx = 1; idx < msg_pack->Size(); ++idx)
        {
            integer_t *buf = static_cast<integer_t*>(msg_pack->GetMsg(idx)->data());
            table_id = buf[0];                      // table_id
            row_id = buf[1];                        // row_id
            capacity = buf[2];                      // capacity
            memcpy(&format, buf + 3, sizeof(int));  // format
            tables_[table_id]->SetRow(row_id, format, capacity);
        }
    }

    void Server::Process_Clock(std::shared_ptr<MsgPack> msg_pack)
    {
        MsgType msg_type;
        MsgArrow arrow;
        int src, dst;
        msg_pack->GetHeaderInfo(&msg_type, &arrow, &src, &dst);

        if (max_delay_ < 0) // ASP model, reply immediately
        {
            MsgPack *reply = msg_pack->CreateReplyMsgPack();
            reply->Send(router_);
            delete reply;
        }
        else
        {
            clock_msg_[src] = msg_pack;
            clocks_[src]++;
            int upper_bound =
                *std::min_element(clocks_.begin(), clocks_.end()) + max_delay_;
            for (int worker = 0; worker < worker_proc_count_; ++worker)
            {
                if (clocks_[worker] <= upper_bound && clock_msg_[worker] != nullptr)
                {
                    MsgPack *reply = clock_msg_[worker]->CreateReplyMsgPack();
                    reply->Send(router_);
                    delete reply;
                    clock_msg_[worker] = nullptr;
                }
            }
        }
    }

    void Server::Process_EndTrain(std::shared_ptr<MsgPack> msg_pack)
    {
        MsgType msg_type;
        MsgArrow arrow;
        int src, dst;
        msg_pack->GetHeaderInfo(&msg_type, &arrow, &src, &dst);
        clocks_[src] = 1 << 30;
        int upper_bound =
            *std::min_element(clocks_.begin(), clocks_.end()) + max_delay_;
        for (int worker = 0; worker < worker_proc_count_; ++worker)
        {
            if (clocks_[worker] <= upper_bound && clock_msg_[worker] != nullptr)
            {
                MsgPack *reply = clock_msg_[worker]->CreateReplyMsgPack();
                reply->Send(router_);
                delete reply;
                clock_msg_[worker] = nullptr;
            }
        }
    }

    // processes get message
    void Server::Process_Get(std::shared_ptr<MsgPack> msg_pack)
    {
        MsgPack* reply = msg_pack->CreateReplyMsgPack();
        int send_ret_size = 0;
        for (int i = 1; i < msg_pack->Size(); ++i)
        {
            zmq::message_t* msg = msg_pack->GetMsg(i);
            integer_t* buffer = static_cast<integer_t*>(msg->data());
            integer_t table = buffer[0];
            integer_t row = buffer[1];
            integer_t col = buffer[2];
            if (row == -1)
            {
                TableIterator iter = tables_[table]->Iterator();
                while (iter.HasNext())
                {
                    integer_t request_row = iter.RowId();
                    lock_pool_.Lock(row);
                    Process_GetRow(table, request_row, col, msg_pack,
                        send_ret_size, reply);
                    lock_pool_.Unlock(row);
                    iter.Next();
                }
            }
            else
            {
                lock_pool_.Lock(row);
                Process_GetRow(table, row, col, msg_pack, send_ret_size, reply);
                lock_pool_.Unlock(row);
            }
        }
        zmq::message_t *tail = new zmq::message_t(sizeof(integer_t));
        integer_t* over_tag = static_cast<integer_t*>(tail->data());
        *over_tag = 1;
        reply->Push(tail);
        reply->Send(router_);
        delete reply;
    }

    // processing get row
    void Server::Process_GetRow(integer_t table, integer_t row, integer_t col,
        std::shared_ptr<MsgPack> msg_pack, int& send_ret_size, MsgPack*& reply)
    {
        integer_t row_size = (col >= 0) ? 1 :
            tables_[table]->GetRow(row)->NonzeroSize();
        int msg_size = sizeof(integer_t)* 3 + row_size *
            (sizeof(integer_t)+tables_[table]->ElementSize());
        if (send_ret_size + msg_size > kMaxMsgSize)
        {
            zmq::message_t *tail = new zmq::message_t(sizeof(integer_t));
            integer_t* over_tag = static_cast<integer_t*>(tail->data());
            *over_tag = 0;
            reply->Push(tail);
            reply->Send(router_);
            delete reply;
            reply = msg_pack->CreateReplyMsgPack();
            send_ret_size = 0;
        }
        zmq::message_t *row_msg = new zmq::message_t(msg_size);
        integer_t *buffer = static_cast<integer_t*>(row_msg->data());
        // Format: table_id, row_id, number
        //         col_1, col2, ..., col_n, val_1, val_2, ..., val_n;
        buffer[0] = table;
        buffer[1] = row;
        if (col >= 0)
        {
            buffer[2] = 1;
            buffer[3] = col;
            tables_[table]->GetRow(row)->At(col, buffer + 4);
        }
        else
        {
            tables_[table]->GetRow(row)->Serialize(buffer + 2);
        }
        reply->Push(row_msg);
        send_ret_size += msg_size;
    }

    // processes add message
    void Server::Process_Add(std::shared_ptr<MsgPack> msg_pack)
    {
        for (int i = 1; i < msg_pack->Size(); ++i)
        {
            zmq::message_t* msg = msg_pack->GetMsg(i);
            integer_t* buffer = static_cast<integer_t*>(msg->data());
            integer_t table = buffer[0];
            integer_t row = buffer[1];
            lock_pool_.Lock(row);
            tables_[table]->GetRow(row)->BatchAdd(buffer + 2);
            lock_pool_.Unlock(row);
        }
    }
    //-- end of server process routine ---------------------------------------/

    void Server::DumpModel()
    {
        Log::Info("Server %d: Dump model...\n", server_id_);
        for (int i = 0; i < tables_.size(); ++i)
        {
            // dump model to file server_$server_id$_table_$table_id$.model
            std::string file_name = "server_" + std::to_string(server_id_)
                + "_table_" + std::to_string(i) + ".model";
            std::ofstream fout(file_name);

            Table *table = tables_[i];
            TableIterator iter = table->Iterator();
            int size = table->ElementSize();
            while (iter.HasNext())
            {
                fout << iter.Row()->ToString() << std::endl;
                iter.Next();
            }
            fout.close();
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 Google Inc. All rights reserved
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// +build ignore

#include "dep.h"

#include <algorithm>
#include <memory>
#include <unordered_map>
#include <unordered_set>

#include "eval.h"
#include "fileutil.h"
#include "log.h"
#include "rule.h"
#include "strutil.h"
#include "var.h"

static vector<DepNode*>* g_dep_node_pool;

static StringPiece ReplaceSuffix(StringPiece s, StringPiece newsuf) {
  string r;
  AppendString(StripExt(s), &r);
  r += '.';
  AppendString(newsuf, &r);
  return Intern(r);
}

DepNode::DepNode(StringPiece o, bool p)
    : output(o),
      has_rule(false),
      is_order_only(false),
      is_phony(p),
      rule_vars(NULL) {
  g_dep_node_pool->push_back(this);
}

class DepBuilder {
 public:
  DepBuilder(Evaluator* ev,
             const vector<shared_ptr<Rule>>& rules,
             const unordered_map<StringPiece, Vars*>& rule_vars)
      : ev_(ev),
        rule_vars_(rule_vars),
        first_rule_(NULL) {
    PopulateRules(rules);
  }

  ~DepBuilder() {
  }

  void Build(vector<StringPiece> targets,
             vector<DepNode*>* nodes) {
    if (targets.empty()) {
      if (!first_rule_) {
        ERROR("*** No targets.");
      }
      CHECK(!first_rule_->outputs.empty());
      targets.push_back(first_rule_->outputs[0]);
    }

    // TODO: LogStats?

    for (StringPiece target : targets) {
      cur_rule_vars_.reset(new Vars);
      ev_->set_current_scope(cur_rule_vars_.get());
      DepNode* n = BuildPlan(target, "");
      nodes->push_back(n);
      ev_->set_current_scope(NULL);
      cur_rule_vars_.reset(NULL);
    }
  }

 private:
  bool Exists(StringPiece target) {
    auto found = rules_.find(target);
    if (found != rules_.end())
      return true;
    if (phony_.count(target))
      return true;
    return ::Exists(target);
  }

  void PopulateRules(const vector<shared_ptr<Rule>>& rules) {
    for (shared_ptr<Rule> rule : rules) {
      if (rule->outputs.empty()) {
        PopulateImplicitRule(rule);
      } else {
        PopulateExplicitRule(rule);
      }
    }
    reverse(implicit_rules_.begin(), implicit_rules_.end());
    for (auto& p : suffix_rules_) {
      reverse(p.second.begin(), p.second.end());
    }
  }

  bool PopulateSuffixRule(shared_ptr<Rule> rule, StringPiece output) {
    if (output.empty() || output[0] != '.')
      return false;

    StringPiece rest = output.substr(1);
    size_t dot_index = rest.find('.');
    // If there is only a single dot or the third dot, this is not a
    // suffix rule.
    if (dot_index == string::npos ||
        rest.substr(dot_index+1).find('.') != string::npos) {
      return false;
    }

    StringPiece input_suffix = rest.substr(0, dot_index);
    StringPiece output_suffix = rest.substr(dot_index+1);
    shared_ptr<Rule> r = make_shared<Rule>(*rule);
    r->inputs.clear();
    r->inputs.push_back(input_suffix);
    r->is_suffix_rule = true;
    suffix_rules_[output_suffix].push_back(r);
    return true;
  }

  shared_ptr<Rule> MergeRules(const Rule& old_rule,
                              const Rule& rule,
                              StringPiece output,
                              bool is_suffix_rule) {
    if (old_rule.is_double_colon != rule.is_double_colon) {
      ERROR("%s:%d: *** target file `%s' has both : and :: entries.",
            LOCF(rule.loc), output.as_string().c_str());
    }
    if (!old_rule.cmds.empty() && !rule.cmds.empty() &&
        !is_suffix_rule && !rule.is_double_colon) {
      WARN("%s:%d: overriding commands for target `%s'",
           LOCF(rule.cmd_loc()), output.as_string().c_str());
      WARN("%s:%d: ignoring old commands for target `%s'",
           LOCF(old_rule.cmd_loc()), output.as_string().c_str());
    }

    shared_ptr<Rule> r = make_shared<Rule>(rule);
    if (rule.is_double_colon) {
      r->cmds.clear();
      for (Value* c : old_rule.cmds)
        r->cmds.push_back(c);
      for (Value* c : rule.cmds)
        r->cmds.push_back(c);
    } else if (!old_rule.cmds.empty() && rule.cmds.empty()) {
      r->cmds = old_rule.cmds;
    }
    for (StringPiece p : old_rule.output_patterns) {
      r->output_patterns.push_back(p);
    }
    return r;
  }

  void PopulateExplicitRule(shared_ptr<Rule> rule) {
    for (StringPiece output : rule->outputs) {
      const bool is_suffix_rule = PopulateSuffixRule(rule, output);
      auto p = rules_.insert(make_pair(output, rule));
      if (p.second) {
        if (!first_rule_ && output.get(0) != '.') {
          first_rule_ = rule;
        }
      } else {
        p.first->second =
            MergeRules(*p.first->second, *rule, output, is_suffix_rule);
      }
    }
  }

  void PopulateImplicitRule(shared_ptr<Rule> rule) {
    for (StringPiece output_pattern : rule->output_patterns) {
      shared_ptr<Rule> r = make_shared<Rule>(*rule);
      r->output_patterns.clear();
      r->output_patterns.push_back(output_pattern);
      implicit_rules_.push_back(r);
    }
  }

  shared_ptr<Rule> LookupRule(StringPiece o) {
    auto found = rules_.find(o);
    if (found != rules_.end())
      return found->second;
    return NULL;
  }

  Vars* LookupRuleVars(StringPiece o) {
    auto found = rule_vars_.find(o);
    if (found != rule_vars_.end())
      return found->second;
    return NULL;
  }

  bool CanPickImplicitRule(shared_ptr<Rule> rule, StringPiece output) {
    CHECK(rule->output_patterns.size() == 1);
    Pattern pat(rule->output_patterns[0]);
    if (!pat.Match(output)) {
      return false;
    }
    for (StringPiece input : rule->inputs) {
      string buf;
      pat.AppendSubst(output, input, &buf);
      if (!Exists(buf))
        return false;
    }
    return true;
  }

  Vars* MergeImplicitRuleVars(StringPiece output, Vars* vars) {
    auto found = rule_vars_.find(output);
    if (found == rule_vars_.end())
      return vars;
    if (vars == NULL)
      return found->second;
    // TODO: leak.
    Vars* r = new Vars(*found->second);
    for (auto p : *vars) {
      (*r)[p.first] = p.second;
    }
    return r;
  }

  bool PickRule(StringPiece output,
                shared_ptr<Rule>* out_rule, Vars** out_var) {
    shared_ptr<Rule> rule = LookupRule(output);
    Vars* vars = LookupRuleVars(output);
    *out_rule = rule;
    *out_var = vars;
    if (rule) {
      if (!rule->cmds.empty()) {
        return true;
      }
    }

    for (shared_ptr<Rule> irule : implicit_rules_) {
      if (!CanPickImplicitRule(irule, output))
        continue;
      if (rule) {
        shared_ptr<Rule> r = make_shared<Rule>(*rule);
        r->output_patterns = irule->output_patterns;
        for (StringPiece input : irule->inputs)
          r->inputs.push_back(input);
        r->cmds = irule->cmds;
        r->loc = irule->loc;
        r->cmd_lineno = irule->cmd_lineno;
        *out_rule = r;
        return true;
      }
      if (vars) {
        CHECK(irule->output_patterns.size() == 1);
        vars = MergeImplicitRuleVars(irule->output_patterns[0], vars);
        *out_var = vars;
      }
      *out_rule = irule;
      return true;
    }

    StringPiece output_suffix = GetExt(output);
    if (output_suffix.get(0) != '.')
      return rule.get();
    output_suffix = output_suffix.substr(1);

    SuffixRuleMap::const_iterator found = suffix_rules_.find(output_suffix);
    if (found == suffix_rules_.end())
      return rule.get();

    for (shared_ptr<Rule> irule : found->second) {
      CHECK(irule->inputs.size() == 1);
      StringPiece input = ReplaceSuffix(output, irule->inputs[0]);
      if (!Exists(input))
        continue;

      if (rule) {
        shared_ptr<Rule> r = make_shared<Rule>(*rule);
        r->inputs.insert(r->inputs.begin(), input);
        r->cmds = irule->cmds;
        r->loc = irule->loc;
        r->cmd_lineno = irule->cmd_lineno;
        *out_rule = r;
        return true;
      }
      if (vars) {
        CHECK(irule->outputs.size() == 1);
        vars = MergeImplicitRuleVars(irule->outputs[0], vars);
        *out_var = vars;
      }
      *out_rule = irule;
      return true;
    }

    return rule.get();
  }

  DepNode* BuildPlan(StringPiece output, StringPiece needed_by) {
    LOG("BuildPlan: %s for %s",
        output.as_string().c_str(),
        needed_by.as_string().c_str());

    auto found = done_.find(output);
    if (found != done_.end()) {
      return found->second;
    }

    DepNode* n = new DepNode(output, phony_.count(output));
    done_[output] = n;

    shared_ptr<Rule> rule;
    Vars* vars;
    if (!PickRule(output, &rule, &vars)) {
      return n;
    }

    vector<unique_ptr<ScopedVar>> sv;
    if (vars) {
      for (const auto& p : *vars) {
        StringPiece name = p.first;
        RuleVar* var = reinterpret_cast<RuleVar*>(p.second);
        CHECK(var);
        Var* new_var = var->v();
        if (var->op() == AssignOp::PLUS_EQ) {
          Var* old_var = ev_->LookupVar(name);
          if (old_var->IsDefined()) {
            // TODO: This would be incorrect and has a leak.
            shared_ptr<string> s = make_shared<string>();
            old_var->Eval(ev_, s.get());
            if (!s->empty())
              *s += ' ';
            new_var->Eval(ev_, s.get());
            new_var = new SimpleVar(s, old_var->Origin());
          }
        } else if (var->op() == AssignOp::QUESTION_EQ) {
          Var* old_var = ev_->LookupVar(name);
          if (old_var->IsDefined()) {
            continue;
          }
        }
        sv.push_back(move(unique_ptr<ScopedVar>(
            new ScopedVar(cur_rule_vars_.get(), name, new_var))));
      }
    }

    for (StringPiece input : rule->inputs) {
      if (rule->output_patterns.size() > 0) {
        if (rule->output_patterns.size() > 1) {
          ERROR("TODO: multiple output pattern is not supported yet");
        }
        string o;
        Pattern(rule->output_patterns[0]).AppendSubst(output, input, &o);
        input = Intern(o);
      } else if (rule->is_suffix_rule) {
        input = Intern(ReplaceSuffix(output, input));
      }

      n->actual_inputs.push_back(input);
      DepNode* c = BuildPlan(input, output);
      n->deps.push_back(c);
    }

    // TODO: order only

    n->has_rule = true;
    n->cmds = rule->cmds;
    if (cur_rule_vars_->empty()) {
      n->rule_vars = NULL;
    } else {
      n->rule_vars = new Vars;
      for (auto p : *cur_rule_vars_) {
        n->rule_vars->insert(p);
      }
    }
    n->loc = rule->loc;
    if (!rule->cmds.empty() && rule->cmd_lineno)
      n->loc.lineno = rule->cmd_lineno;

    return n;
  }

  Evaluator* ev_;
  unordered_map<StringPiece, shared_ptr<Rule>> rules_;
  const unordered_map<StringPiece, Vars*>& rule_vars_;
  unique_ptr<Vars> cur_rule_vars_;

  vector<shared_ptr<Rule>> implicit_rules_;   // pattern=%. no prefix,suffix.
  //vector<Rule*> iprefix_rules_;   // pattern=prefix%..  may have suffix
  //vector<Rule*> isuffix_rules_;   // pattern=%suffix  no prefix
  typedef unordered_map<StringPiece, vector<shared_ptr<Rule>>> SuffixRuleMap;
  SuffixRuleMap suffix_rules_;

  shared_ptr<Rule> first_rule_;
  unordered_map<StringPiece, DepNode*> done_;
  unordered_set<StringPiece> phony_;
};

void MakeDep(Evaluator* ev,
             const vector<shared_ptr<Rule>>& rules,
             const unordered_map<StringPiece, Vars*>& rule_vars,
             const vector<StringPiece>& targets,
             vector<DepNode*>* nodes) {
  DepBuilder db(ev, rules, rule_vars);
  db.Build(targets, nodes);
}

void InitDepNodePool() {
  g_dep_node_pool = new vector<DepNode*>;
}

void QuitDepNodePool() {
  for (DepNode* n : *g_dep_node_pool)
    delete n;
  delete g_dep_node_pool;
}
<commit_msg>[C++] Create dependency for order only inputs<commit_after>// Copyright 2015 Google Inc. All rights reserved
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// +build ignore

#include "dep.h"

#include <algorithm>
#include <memory>
#include <unordered_map>
#include <unordered_set>

#include "eval.h"
#include "fileutil.h"
#include "log.h"
#include "rule.h"
#include "strutil.h"
#include "var.h"

static vector<DepNode*>* g_dep_node_pool;

static StringPiece ReplaceSuffix(StringPiece s, StringPiece newsuf) {
  string r;
  AppendString(StripExt(s), &r);
  r += '.';
  AppendString(newsuf, &r);
  return Intern(r);
}

DepNode::DepNode(StringPiece o, bool p)
    : output(o),
      has_rule(false),
      is_order_only(false),
      is_phony(p),
      rule_vars(NULL) {
  g_dep_node_pool->push_back(this);
}

class DepBuilder {
 public:
  DepBuilder(Evaluator* ev,
             const vector<shared_ptr<Rule>>& rules,
             const unordered_map<StringPiece, Vars*>& rule_vars)
      : ev_(ev),
        rule_vars_(rule_vars),
        first_rule_(NULL) {
    PopulateRules(rules);
  }

  ~DepBuilder() {
  }

  void Build(vector<StringPiece> targets,
             vector<DepNode*>* nodes) {
    if (targets.empty()) {
      if (!first_rule_) {
        ERROR("*** No targets.");
      }
      CHECK(!first_rule_->outputs.empty());
      targets.push_back(first_rule_->outputs[0]);
    }

    // TODO: LogStats?

    for (StringPiece target : targets) {
      cur_rule_vars_.reset(new Vars);
      ev_->set_current_scope(cur_rule_vars_.get());
      DepNode* n = BuildPlan(target, "");
      nodes->push_back(n);
      ev_->set_current_scope(NULL);
      cur_rule_vars_.reset(NULL);
    }
  }

 private:
  bool Exists(StringPiece target) {
    auto found = rules_.find(target);
    if (found != rules_.end())
      return true;
    if (phony_.count(target))
      return true;
    return ::Exists(target);
  }

  void PopulateRules(const vector<shared_ptr<Rule>>& rules) {
    for (shared_ptr<Rule> rule : rules) {
      if (rule->outputs.empty()) {
        PopulateImplicitRule(rule);
      } else {
        PopulateExplicitRule(rule);
      }
    }
    reverse(implicit_rules_.begin(), implicit_rules_.end());
    for (auto& p : suffix_rules_) {
      reverse(p.second.begin(), p.second.end());
    }
  }

  bool PopulateSuffixRule(shared_ptr<Rule> rule, StringPiece output) {
    if (output.empty() || output[0] != '.')
      return false;

    StringPiece rest = output.substr(1);
    size_t dot_index = rest.find('.');
    // If there is only a single dot or the third dot, this is not a
    // suffix rule.
    if (dot_index == string::npos ||
        rest.substr(dot_index+1).find('.') != string::npos) {
      return false;
    }

    StringPiece input_suffix = rest.substr(0, dot_index);
    StringPiece output_suffix = rest.substr(dot_index+1);
    shared_ptr<Rule> r = make_shared<Rule>(*rule);
    r->inputs.clear();
    r->inputs.push_back(input_suffix);
    r->is_suffix_rule = true;
    suffix_rules_[output_suffix].push_back(r);
    return true;
  }

  shared_ptr<Rule> MergeRules(const Rule& old_rule,
                              const Rule& rule,
                              StringPiece output,
                              bool is_suffix_rule) {
    if (old_rule.is_double_colon != rule.is_double_colon) {
      ERROR("%s:%d: *** target file `%s' has both : and :: entries.",
            LOCF(rule.loc), output.as_string().c_str());
    }
    if (!old_rule.cmds.empty() && !rule.cmds.empty() &&
        !is_suffix_rule && !rule.is_double_colon) {
      WARN("%s:%d: overriding commands for target `%s'",
           LOCF(rule.cmd_loc()), output.as_string().c_str());
      WARN("%s:%d: ignoring old commands for target `%s'",
           LOCF(old_rule.cmd_loc()), output.as_string().c_str());
    }

    shared_ptr<Rule> r = make_shared<Rule>(rule);
    if (rule.is_double_colon) {
      r->cmds.clear();
      for (Value* c : old_rule.cmds)
        r->cmds.push_back(c);
      for (Value* c : rule.cmds)
        r->cmds.push_back(c);
    } else if (!old_rule.cmds.empty() && rule.cmds.empty()) {
      r->cmds = old_rule.cmds;
    }
    for (StringPiece p : old_rule.output_patterns) {
      r->output_patterns.push_back(p);
    }
    return r;
  }

  void PopulateExplicitRule(shared_ptr<Rule> rule) {
    for (StringPiece output : rule->outputs) {
      const bool is_suffix_rule = PopulateSuffixRule(rule, output);
      auto p = rules_.insert(make_pair(output, rule));
      if (p.second) {
        if (!first_rule_ && output.get(0) != '.') {
          first_rule_ = rule;
        }
      } else {
        p.first->second =
            MergeRules(*p.first->second, *rule, output, is_suffix_rule);
      }
    }
  }

  void PopulateImplicitRule(shared_ptr<Rule> rule) {
    for (StringPiece output_pattern : rule->output_patterns) {
      shared_ptr<Rule> r = make_shared<Rule>(*rule);
      r->output_patterns.clear();
      r->output_patterns.push_back(output_pattern);
      implicit_rules_.push_back(r);
    }
  }

  shared_ptr<Rule> LookupRule(StringPiece o) {
    auto found = rules_.find(o);
    if (found != rules_.end())
      return found->second;
    return NULL;
  }

  Vars* LookupRuleVars(StringPiece o) {
    auto found = rule_vars_.find(o);
    if (found != rule_vars_.end())
      return found->second;
    return NULL;
  }

  bool CanPickImplicitRule(shared_ptr<Rule> rule, StringPiece output) {
    CHECK(rule->output_patterns.size() == 1);
    Pattern pat(rule->output_patterns[0]);
    if (!pat.Match(output)) {
      return false;
    }
    for (StringPiece input : rule->inputs) {
      string buf;
      pat.AppendSubst(output, input, &buf);
      if (!Exists(buf))
        return false;
    }
    return true;
  }

  Vars* MergeImplicitRuleVars(StringPiece output, Vars* vars) {
    auto found = rule_vars_.find(output);
    if (found == rule_vars_.end())
      return vars;
    if (vars == NULL)
      return found->second;
    // TODO: leak.
    Vars* r = new Vars(*found->second);
    for (auto p : *vars) {
      (*r)[p.first] = p.second;
    }
    return r;
  }

  bool PickRule(StringPiece output,
                shared_ptr<Rule>* out_rule, Vars** out_var) {
    shared_ptr<Rule> rule = LookupRule(output);
    Vars* vars = LookupRuleVars(output);
    *out_rule = rule;
    *out_var = vars;
    if (rule) {
      if (!rule->cmds.empty()) {
        return true;
      }
    }

    for (shared_ptr<Rule> irule : implicit_rules_) {
      if (!CanPickImplicitRule(irule, output))
        continue;
      if (rule) {
        shared_ptr<Rule> r = make_shared<Rule>(*rule);
        r->output_patterns = irule->output_patterns;
        for (StringPiece input : irule->inputs)
          r->inputs.push_back(input);
        r->cmds = irule->cmds;
        r->loc = irule->loc;
        r->cmd_lineno = irule->cmd_lineno;
        *out_rule = r;
        return true;
      }
      if (vars) {
        CHECK(irule->output_patterns.size() == 1);
        vars = MergeImplicitRuleVars(irule->output_patterns[0], vars);
        *out_var = vars;
      }
      *out_rule = irule;
      return true;
    }

    StringPiece output_suffix = GetExt(output);
    if (output_suffix.get(0) != '.')
      return rule.get();
    output_suffix = output_suffix.substr(1);

    SuffixRuleMap::const_iterator found = suffix_rules_.find(output_suffix);
    if (found == suffix_rules_.end())
      return rule.get();

    for (shared_ptr<Rule> irule : found->second) {
      CHECK(irule->inputs.size() == 1);
      StringPiece input = ReplaceSuffix(output, irule->inputs[0]);
      if (!Exists(input))
        continue;

      if (rule) {
        shared_ptr<Rule> r = make_shared<Rule>(*rule);
        r->inputs.insert(r->inputs.begin(), input);
        r->cmds = irule->cmds;
        r->loc = irule->loc;
        r->cmd_lineno = irule->cmd_lineno;
        *out_rule = r;
        return true;
      }
      if (vars) {
        CHECK(irule->outputs.size() == 1);
        vars = MergeImplicitRuleVars(irule->outputs[0], vars);
        *out_var = vars;
      }
      *out_rule = irule;
      return true;
    }

    return rule.get();
  }

  DepNode* BuildPlan(StringPiece output, StringPiece needed_by) {
    LOG("BuildPlan: %s for %s",
        output.as_string().c_str(),
        needed_by.as_string().c_str());

    auto found = done_.find(output);
    if (found != done_.end()) {
      return found->second;
    }

    DepNode* n = new DepNode(output, phony_.count(output));
    done_[output] = n;

    shared_ptr<Rule> rule;
    Vars* vars;
    if (!PickRule(output, &rule, &vars)) {
      return n;
    }

    vector<unique_ptr<ScopedVar>> sv;
    if (vars) {
      for (const auto& p : *vars) {
        StringPiece name = p.first;
        RuleVar* var = reinterpret_cast<RuleVar*>(p.second);
        CHECK(var);
        Var* new_var = var->v();
        if (var->op() == AssignOp::PLUS_EQ) {
          Var* old_var = ev_->LookupVar(name);
          if (old_var->IsDefined()) {
            // TODO: This would be incorrect and has a leak.
            shared_ptr<string> s = make_shared<string>();
            old_var->Eval(ev_, s.get());
            if (!s->empty())
              *s += ' ';
            new_var->Eval(ev_, s.get());
            new_var = new SimpleVar(s, old_var->Origin());
          }
        } else if (var->op() == AssignOp::QUESTION_EQ) {
          Var* old_var = ev_->LookupVar(name);
          if (old_var->IsDefined()) {
            continue;
          }
        }
        sv.push_back(move(unique_ptr<ScopedVar>(
            new ScopedVar(cur_rule_vars_.get(), name, new_var))));
      }
    }

    for (StringPiece input : rule->inputs) {
      if (rule->output_patterns.size() > 0) {
        if (rule->output_patterns.size() > 1) {
          ERROR("TODO: multiple output pattern is not supported yet");
        }
        string o;
        Pattern(rule->output_patterns[0]).AppendSubst(output, input, &o);
        input = Intern(o);
      } else if (rule->is_suffix_rule) {
        input = Intern(ReplaceSuffix(output, input));
      }

      n->actual_inputs.push_back(input);
      DepNode* c = BuildPlan(input, output);
      n->deps.push_back(c);
    }

    for (StringPiece input : rule->order_only_inputs) {
      DepNode* c = BuildPlan(input, output);
      c->is_order_only = true;
      n->deps.push_back(c);
    }

    n->has_rule = true;
    n->cmds = rule->cmds;
    if (cur_rule_vars_->empty()) {
      n->rule_vars = NULL;
    } else {
      n->rule_vars = new Vars;
      for (auto p : *cur_rule_vars_) {
        n->rule_vars->insert(p);
      }
    }
    n->loc = rule->loc;
    if (!rule->cmds.empty() && rule->cmd_lineno)
      n->loc.lineno = rule->cmd_lineno;

    return n;
  }

  Evaluator* ev_;
  unordered_map<StringPiece, shared_ptr<Rule>> rules_;
  const unordered_map<StringPiece, Vars*>& rule_vars_;
  unique_ptr<Vars> cur_rule_vars_;

  vector<shared_ptr<Rule>> implicit_rules_;   // pattern=%. no prefix,suffix.
  //vector<Rule*> iprefix_rules_;   // pattern=prefix%..  may have suffix
  //vector<Rule*> isuffix_rules_;   // pattern=%suffix  no prefix
  typedef unordered_map<StringPiece, vector<shared_ptr<Rule>>> SuffixRuleMap;
  SuffixRuleMap suffix_rules_;

  shared_ptr<Rule> first_rule_;
  unordered_map<StringPiece, DepNode*> done_;
  unordered_set<StringPiece> phony_;
};

void MakeDep(Evaluator* ev,
             const vector<shared_ptr<Rule>>& rules,
             const unordered_map<StringPiece, Vars*>& rule_vars,
             const vector<StringPiece>& targets,
             vector<DepNode*>* nodes) {
  DepBuilder db(ev, rules, rule_vars);
  db.Build(targets, nodes);
}

void InitDepNodePool() {
  g_dep_node_pool = new vector<DepNode*>;
}

void QuitDepNodePool() {
  for (DepNode* n : *g_dep_node_pool)
    delete n;
  delete g_dep_node_pool;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2016  P.L. Lucas
 *
 * 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.
*/

#include "driver/libbacklight_backend.h"

#ifdef __cplusplus
extern "C" {
#endif
#include "driver/libbacklight_backend.c"
#ifdef __cplusplus
}
#endif

#include "linuxbackend.h"
#include <QTimer>
#include <QDebug>

namespace LXQt {

LinuxBackend::LinuxBackend(QObject *parent):VirtualBackEnd(parent)
{
    maxBacklight = lxqt_backlight_backend_get_max();
    backlightStream = NULL;
    if( isBacklightAvailable() ) {
        char *driver = lxqt_backlight_backend_get_driver();
        fileSystemWatcher = new QFileSystemWatcher(this);
        QString path = QString("/sys/class/backlight/%1/actual_brightness").arg(driver);
        fileSystemWatcher->addPath(path);
        path = QString("/sys/class/backlight/%1/brightness").arg(driver);
        fileSystemWatcher->addPath(path);
        path = QString("/sys/class/backlight/%1/bl_power").arg(driver);
        fileSystemWatcher->addPath(path);
        free(driver);
        actualBacklight = lxqt_backlight_backend_get();
        connect(fileSystemWatcher, SIGNAL(fileChanged(const QString &)),
            this, SLOT(fileSystemChanged(const QString &)) );
    }
}

LinuxBackend::~LinuxBackend()
{
    delete backlightStream;
}

int LinuxBackend::getBacklight()
{
    actualBacklight = lxqt_backlight_backend_get();
    return actualBacklight;
}

int LinuxBackend::getMaxBacklight()
{
    return maxBacklight;
}

bool LinuxBackend::isBacklightAvailable()
{
    return maxBacklight > 0;
}

bool LinuxBackend::isBacklightOff()
{
    return lxqt_backlight_is_backlight_off() > 0;
}

void LinuxBackend::setBacklight(int value)
{
    if( ! isBacklightAvailable() )
        return;
    if( backlightStream == NULL ) {
        FILE *stream = lxqt_backlight_backend_get_write_stream();
        backlightStream = new QTextStream(stream);
        // Close stream after 60 seconds
        QTimer::singleShot(60000, this, SLOT(closeBacklightStream()));
    }
    if( value<maxBacklight && value>0 )
        *backlightStream << value << endl;
}

void LinuxBackend::closeBacklightStream()
{
    if( backlightStream != NULL ) {
        delete backlightStream;
        backlightStream = NULL;
    }
}

void LinuxBackend::fileSystemChanged(const QString & /*path*/)
{
    int value = actualBacklight;
    if( value != getBacklight() ) {
        emit backlightChanged(actualBacklight);
    }
}

} // namespace LXQt
<commit_msg>Normalize backlight value<commit_after>/*
 * Copyright (C) 2016  P.L. Lucas
 *
 * 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.
*/

#include "driver/libbacklight_backend.h"

#ifdef __cplusplus
extern "C" {
#endif
#include "driver/libbacklight_backend.c"
#ifdef __cplusplus
}
#endif

#include "linuxbackend.h"
#include <QTimer>
#include <QDebug>

namespace LXQt {

LinuxBackend::LinuxBackend(QObject *parent):VirtualBackEnd(parent)
{
    maxBacklight = lxqt_backlight_backend_get_max();
    backlightStream = NULL;
    if( isBacklightAvailable() ) {
        char *driver = lxqt_backlight_backend_get_driver();
        fileSystemWatcher = new QFileSystemWatcher(this);
        QString path = QString("/sys/class/backlight/%1/actual_brightness").arg(driver);
        fileSystemWatcher->addPath(path);
        path = QString("/sys/class/backlight/%1/brightness").arg(driver);
        fileSystemWatcher->addPath(path);
        path = QString("/sys/class/backlight/%1/bl_power").arg(driver);
        fileSystemWatcher->addPath(path);
        free(driver);
        actualBacklight = lxqt_backlight_backend_get();
        connect(fileSystemWatcher, SIGNAL(fileChanged(const QString &)),
            this, SLOT(fileSystemChanged(const QString &)) );
    }
}

LinuxBackend::~LinuxBackend()
{
    delete backlightStream;
}

int LinuxBackend::getBacklight()
{
    actualBacklight = lxqt_backlight_backend_get();
    return actualBacklight;
}

int LinuxBackend::getMaxBacklight()
{
    return maxBacklight;
}

bool LinuxBackend::isBacklightAvailable()
{
    return maxBacklight > 0;
}

bool LinuxBackend::isBacklightOff()
{
    return lxqt_backlight_is_backlight_off() > 0;
}

void LinuxBackend::setBacklight(int value)
{
    if( ! isBacklightAvailable() )
        return;
    if( backlightStream == NULL ) {
        FILE *stream = lxqt_backlight_backend_get_write_stream();
        backlightStream = new QTextStream(stream);
        // Close stream after 60 seconds
        QTimer::singleShot(60000, this, SLOT(closeBacklightStream()));
    }
    // normalize the value (to work around an issue in QSlider)
    value = qBound(0, value, maxBacklight);
    *backlightStream << value << endl;
}

void LinuxBackend::closeBacklightStream()
{
    if( backlightStream != NULL ) {
        delete backlightStream;
        backlightStream = NULL;
    }
}

void LinuxBackend::fileSystemChanged(const QString & /*path*/)
{
    int value = actualBacklight;
    if( value != getBacklight() ) {
        emit backlightChanged(actualBacklight);
    }
}

} // namespace LXQt
<|endoftext|>