<commit_before>#include "SteeringBehaviour.h"

SteeringBehaviour::SteeringBehaviour(Zombie *z, Scene *s): owner(z), seek_target(0),
wander_on(0), seek_on(0), flee_on(0), arrive_on(0), obstacle_avoidance_on(0), scene(s)
{
	steering_force = glm::vec2(0.0f, 0.0f);

	// ---------- WANDER INIT ---------- //
	wander_radius	= 3.0f;
	wander_distance = 5.0f;
	wander_jitter	= 1.f;
	float alpha = (float)(rand()%360) * (float)(PI/180.0f);
	wander_target = glm::vec2(wander_radius*cos(alpha), wander_radius*sin(alpha));
	wander_target_point.InitPoint(wander_target, 0.2, glm::vec3(0, 0, 1));

	obstacle_number = 0;
	intersection_number = 0;
	for(int i=0; i<20; ++i)
	{
		obstacle_position[i].InitPoint(glm::vec2(0, 0), 0.2, glm::vec3(0, 1, 0));
		obstacle_position[i].Hide();
	}
	for(int i=0; i<10; ++i)
	{
		intersection[i].InitPoint(glm::vec2(0, 0), 0.2, glm::vec3(1, 0, 0));
		intersection[i].Hide();
	}
	for(int i=0; i<4; ++i)
	{
		hiding_spot[i].InitPoint(glm::vec2(0, 0), 0.2, glm::vec3(1, 0, 1));
	}
	obstacle_x_axis.InitLine(glm::vec2(0, 0), glm::vec2(0, 0), glm::vec3(0, 1, 0));
	obstacle_y_axis.InitLine(glm::vec2(0, 0), glm::vec2(0, 0), glm::vec3(0, 1, 0));
	obstacle_box.InitRectangle(glm::vec2(0, 0), glm::vec2(1, MIN_DETECTION_BOX_LENGTH), glm::vec2(0.03,0.03), glm::vec3(0, 1, 0));
}

SteeringBehaviour::~SteeringBehaviour(void)
{

}

glm::vec2 SteeringBehaviour::CalculateSteeringForce(void)
{
	glm::vec2 force_wander = CalculateWander();
	glm::vec2 force_seek = CalculateSeek(seek_target);
	glm::vec2 force_oa = CalculateObstacleAvoidance();
	glm::vec2 force_hide = CalculateHide();
	steering_force = glm::vec2(0.0f, 0.0f);

	steering_force += force_seek;
	return steering_force;
/*
	if(GetLength(force_oa) > 0)
	{
		steering_force += force_oa * 1.f;
		//steering_force += force_seek * 0.2f;
		return steering_force;
	}
	else
	{

	}*/
}

void SteeringBehaviour::Draw(void)
{
	wander_target_point.DrawPoint();

	for(int i=0; i<obstacle_number; ++i)
		obstacle_position[i].DrawPoint();
	for(int i=0; i<intersection_number; ++i)
		intersection[i].DrawPoint();
	for(int i=0; i<4; ++i)
		hiding_spot[i].DrawPoint();
	obstacle_x_axis.DrawLine();
	obstacle_y_axis.DrawLine();
	obstacle_box.DrawRectngle();
}

glm::vec2 SteeringBehaviour::CalculateWander(void)
{
	int sign1 = (((float)rand()/RAND_MAX - 0.5)>0) ? 1:-1;
	int sign2 = (((float)rand()/RAND_MAX - 0.5)>0) ? 1:-1;

	wander_target += glm::vec2((double)sign1 * wander_jitter, (double)sign2 * wander_jitter);
	Normalize(wander_target);
	wander_target *= wander_radius;

	glm::vec2 target_local(wander_target + glm::vec2(0, wander_distance));

	glm::mat4 rot = glm::rotate(glm::mat4(1.0f), GetAngle(glm::vec2(0, 1), owner->object_heading), glm::vec3(0, 0, 1));
	glm::vec2 target_world(rot * glm::vec4(target_local, 0.0f, 0.0f));
	target_world += owner->object_position;

	wander_target_point.UpdatePoint(target_world, 0.2, glm::vec3(0, 0, 1));

	return target_world - owner->object_position;
}

glm::vec2 SteeringBehaviour::CalculateSeek(const glm::vec2 &target)
{
	glm::vec2 desired_velocity = target - owner->object_position;
	double distance = GetDistance(owner->GetObjectPosition(), target);
	SetLength(desired_velocity, ZOMBIE_MAX_SPEED);
	if (distance > 0){
		double Decelerate = 0.01;
		double speed = distance / Decelerate;
		if (speed > ZOMBIE_MAX_SPEED){
			speed = ZOMBIE_MAX_SPEED;
		}
		desired_velocity *= speed / distance;

		return desired_velocity - owner->object_velocity;
	}

	return glm::vec2(0, 0);
}

glm::vec2 SteeringBehaviour::CalculateFlee(void)
{
	return glm::vec2(0, 0);
}

glm::vec2 SteeringBehaviour::CalculateArrive(void)
{
	return glm::vec2(0, 0);
}

glm::vec2 SteeringBehaviour::CalculateObstacleAvoidance(void)
{
	GameEntity *object = 0;
	float detection_box_length = (GetLength(owner->object_velocity)/ZOMBIE_MAX_SPEED);
	detection_box_length *=	MIN_DETECTION_BOX_LENGTH;
	detection_box_length += MIN_DETECTION_BOX_LENGTH;
	float distance = 0.0f;

	float dist_to_closest_ip = 999999.0f;
	GameEntity *pointer_to_closest_ob = 0;
	glm::vec2 local_position_of_closest_ob = glm::vec2(0, 0);

	obstacle_number = 0;
	for(int i=0; i<obstacle_number; ++i)
		obstacle_position[i].Hide();
	intersection_number = 0;
	for(int i=0; i<intersection_number; ++i)
		intersection[i].Hide();

	obstacle_x_axis.UpdateLine(owner->GetObjectPosition() - GetPerpendicular(owner->object_heading) * glm::vec2(33, 33), owner->GetObjectPosition() + GetPerpendicular(owner->object_heading) * glm::vec2(33, 33), glm::vec3(0, 1, 0));
	obstacle_y_axis.UpdateLine(owner->GetObjectPosition() - owner->GetObjectHeading() * glm::vec2(33, 33), owner->GetObjectPosition() + owner->GetObjectHeading()  * glm::vec2(33, 33), glm::vec3(0, 1, 0));
	obstacle_box.UpdateRectangle(glm::vec2(0.f, 0.f), glm::vec2(1.f, detection_box_length), glm::vec3(0, 1, 0));

	float angle = GetAngle(glm::vec2(0, 1), owner->object_heading);

	for(unsigned int i=0; i<owner->scene->objects.size(); ++i)
	{
		object = owner->scene->objects[i];

		if(object == owner || object == owner->scene->player)
			continue;

		if ((GetDistance(object->GetObjectPosition(), owner->GetObjectPosition())) > detection_box_length+ object->GetCollisionRadius()){
			//cout << GetDistance(object->GetObjectPosition(), owner->GetObjectPosition()) + object->GetCollisionRadius() << ", " << detection_box_length << "\n";
			continue;
		}

		glm::mat4 rot = glm::rotate(glm::mat4(1.0f), (float)(-angle), glm::vec3(0, 0, 1));
		glm::vec2 local_position(rot * glm::vec4(object->GetObjectPosition() - owner->GetObjectPosition(), 0.0f, 0.0f));

		if (local_position.y < 0)
			continue;

		obstacle_position[obstacle_number].Hide();
		obstacle_position[obstacle_number++].UpdatePoint(local_position, object->GetCollisionRadius(), glm::vec3(0, 1, 0));

		float expanded_radius = object->GetCollisionRadius() + owner->GetCollisionRadius();

		if (fabs(local_position.x) > expanded_radius)
			continue;

		cout << expanded_radius << endl;

		double cX = local_position.x;
		double cY = local_position.y;

		double sqrt_part = sqrt(expanded_radius*expanded_radius - cX*cX);

		double ip = cY - sqrt_part;
		if(ip <= 0) ip = cY + sqrt_part;

		intersection[intersection_number].Hide();
		intersection[intersection_number++].UpdatePoint(glm::vec2(0, ip) , 0.2f, glm::vec3(1, 0, 0));

		if(ip < dist_to_closest_ip)
		{
			dist_to_closest_ip = (float)ip;
			pointer_to_closest_ob = object;
			local_position_of_closest_ob = local_position;
		}
	}

	glm::vec2 force(0.0f, 0.0f);

	if(pointer_to_closest_ob == 0)
		return force;

	double multiplier = 1.0 + (detection_box_length - local_position_of_closest_ob.y) / detection_box_length;

	// lateral force
	force.x = (float)((pointer_to_closest_ob->GetCollisionRadius() - local_position_of_closest_ob.x) * multiplier);

	const double braking_weight = 0.2;

	force.y = (float)((pointer_to_closest_ob->GetCollisionRadius() - local_position_of_closest_ob.y) * braking_weight);

	glm::mat4 rot = glm::rotate(glm::mat4(1.0f), GetAngle(glm::vec2(0, 1), owner->object_heading), glm::vec3(0, 0, 1));
	glm::vec2 force_world(rot * glm::vec4(force, 0.0f, 0.0f));

	return force_world;
}

glm::vec2 SteeringBehaviour::CalculateHidingSpot(const glm::vec2 &target, const glm::vec2 &obstacle, double radius)
{
	const double dist_from_boundry = 3.0;
	double dist = radius + dist_from_boundry;

	glm::vec2 to_obstacle = obstacle - target;
	Normalize(to_obstacle);
	to_obstacle *= dist;

	return to_obstacle + obstacle;
}

glm::vec2 SteeringBehaviour::CalculateHide(void)
{
	double best_dist = 999999.0;
	glm::vec2 best_spot;
	int best_index = -1;

	for(int i=0; i<scene->obstacles.size(); ++i)
	{
		glm::vec2 hide_spot = CalculateHidingSpot(scene->player->GetObjectPosition(), scene->obstacles[i]->GetObjectPosition(), scene->obstacles[i]->GetCollisionRadius());

		double dist = GetDistanceSqrt(hide_spot, owner->GetObjectPosition());

		if(dist < best_dist)
		{
			best_dist = dist;
			best_spot = hide_spot;
			best_index = i;
		}

		hiding_spot[i].UpdatePoint(hide_spot, 0.2f, glm::vec3(1, 0, 1));
	}

	hiding_spot[best_index].UpdatePoint(best_spot, 0.2f, glm::vec3(1, 1, 0));

	return CalculateSeek(best_spot);  // !!!!!! ZMIENIC NA ARRIVE !!!!!!!
}
<commit_msg>It's ALIVE !!!!! aka avoid works<commit_after>#include "SteeringBehaviour.h"

SteeringBehaviour::SteeringBehaviour(Zombie *z, Scene *s): owner(z), seek_target(0),
wander_on(0), seek_on(0), flee_on(0), arrive_on(0), obstacle_avoidance_on(0), scene(s)
{
	steering_force = glm::vec2(0.0f, 0.0f);

	// ---------- WANDER INIT ---------- //
	wander_radius	= 3.0f;
	wander_distance = 5.0f;
	wander_jitter	= 1.2f;
	float alpha = (float)(rand()%360) * (float)(PI/180.0f);
	wander_target = glm::vec2(wander_radius*cos(alpha), wander_radius*sin(alpha));
	wander_target_point.InitPoint(wander_target, 0.2, glm::vec3(0, 0, 1));

	obstacle_number = 0;
	intersection_number = 0;
	for(int i=0; i<20; ++i)
	{
		obstacle_position[i].InitPoint(glm::vec2(0, 0), 0.2, glm::vec3(0, 1, 0));
		obstacle_position[i].Hide();
	}
	for(int i=0; i<10; ++i)
	{
		intersection[i].InitPoint(glm::vec2(0, 0), 0.2, glm::vec3(1, 0, 0));
		intersection[i].Hide();
	}
	for(int i=0; i<4; ++i)
	{
		hiding_spot[i].InitPoint(glm::vec2(0, 0), 0.2, glm::vec3(1, 0, 1));
	}
	obstacle_x_axis.InitLine(glm::vec2(0, 0), glm::vec2(0, 0), glm::vec3(0, 1, 0));
	obstacle_y_axis.InitLine(glm::vec2(0, 0), glm::vec2(0, 0), glm::vec3(0, 1, 0));
	obstacle_box.InitRectangle(glm::vec2(0, 0), glm::vec2(1, MIN_DETECTION_BOX_LENGTH), glm::vec2(0.03,0.03), glm::vec3(0, 1, 0));
}

SteeringBehaviour::~SteeringBehaviour(void)
{

}

glm::vec2 SteeringBehaviour::CalculateSteeringForce(void)
{
	glm::vec2 force_wander = CalculateWander();
	glm::vec2 force_seek = CalculateSeek(seek_target);
	glm::vec2 force_oa = CalculateObstacleAvoidance();
	glm::vec2 force_hide = CalculateHide();
	steering_force = glm::vec2(0.0f, 0.0f);

	if(GetLength(force_oa) > 0)
	{
		steering_force += force_oa * 0.8f;
		steering_force += force_seek * 0.2f;
		return steering_force;
	}
	else
	{
		steering_force += force_seek;
		return steering_force;
	}
}

void SteeringBehaviour::Draw(void)
{
	wander_target_point.DrawPoint();

	for(int i=0; i<obstacle_number; ++i)
		obstacle_position[i].DrawPoint();
	for(int i=0; i<intersection_number; ++i)
		intersection[i].DrawPoint();
	for(int i=0; i<4; ++i)
		hiding_spot[i].DrawPoint();
	obstacle_x_axis.DrawLine();
	obstacle_y_axis.DrawLine();
	obstacle_box.DrawRectngle();
}

glm::vec2 SteeringBehaviour::CalculateWander(void)
{
	int sign1 = (((float)rand()/RAND_MAX - 0.5)>0) ? 1:-1;
	int sign2 = (((float)rand()/RAND_MAX - 0.5)>0) ? 1:-1;

	wander_target += glm::vec2((double)sign1 * wander_jitter, (double)sign2 * wander_jitter);
	Normalize(wander_target);
	wander_target *= wander_radius;

	glm::vec2 target_local(wander_target + glm::vec2(0, wander_distance));

	glm::mat4 rot = glm::rotate(glm::mat4(1.0f), GetAngle(glm::vec2(0, 1), owner->object_heading), glm::vec3(0, 0, 1));
	glm::vec2 target_world(rot * glm::vec4(target_local, 0.0f, 0.0f));
	target_world += owner->object_position;

	wander_target_point.UpdatePoint(target_world, 0.2, glm::vec3(0, 0, 1));

	return (target_world - owner->object_position)*glm::vec2(3333,3333);
}

glm::vec2 SteeringBehaviour::CalculateSeek(const glm::vec2 &target)
{
	glm::vec2 desired_velocity = target - owner->object_position;
	double distance = GetDistance(owner->GetObjectPosition(), target);
	SetLength(desired_velocity, ZOMBIE_MAX_SPEED);
	if (distance > 0){
		double Decelerate = 0.01;
		double speed = distance / Decelerate;
		if (speed > ZOMBIE_MAX_SPEED){
			speed = ZOMBIE_MAX_SPEED;
		}
		desired_velocity *= speed / distance;

		return desired_velocity - owner->object_velocity;
	}

	return glm::vec2(0, 0);
}

glm::vec2 SteeringBehaviour::CalculateFlee(void)
{
	return glm::vec2(0, 0);
}

glm::vec2 SteeringBehaviour::CalculateArrive(void)
{
	return glm::vec2(0, 0);
}

glm::vec2 SteeringBehaviour::CalculateObstacleAvoidance(void)
{
	GameEntity *object = 0;
	float detection_box_length = (GetLength(owner->object_velocity)/ZOMBIE_MAX_SPEED);
	detection_box_length *=	MIN_DETECTION_BOX_LENGTH;
	detection_box_length += MIN_DETECTION_BOX_LENGTH;
	float distance = 0.0f;
	float dist_to_closest_ip = 9999.0f;

	GameEntity *pointer_to_closest_ob = 0;
	glm::vec2 local_position_of_closest_ob = glm::vec2(0, 0);

	//debug
	obstacle_number = 0;
	for(int i=0; i<obstacle_number; ++i)
		obstacle_position[i].Hide();
	intersection_number = 0;
	for(int i=0; i<intersection_number; ++i)
		intersection[i].Hide();

	//debug
	obstacle_x_axis.UpdateLine(owner->GetObjectPosition() - GetPerpendicular(owner->object_heading) * glm::vec2(2, 2), owner->GetObjectPosition() + GetPerpendicular(owner->object_heading) * glm::vec2(2, 2), glm::vec3(0, 1, 0));
	obstacle_y_axis.UpdateLine(owner->GetObjectPosition() - owner->GetObjectHeading() * glm::vec2(3, 3), owner->GetObjectPosition() + owner->GetObjectHeading()  * glm::vec2(7, 7), glm::vec3(0, 1, 0));
	obstacle_box.UpdateRectangle(glm::vec2(0.f, 0.f), glm::vec2(1.f, detection_box_length), glm::vec3(0, 1, 0));

	float angle = GetAngle(glm::vec2(0, 1), owner->object_heading);

	for(unsigned int i=0; i<owner->scene->obstacles.size(); ++i)
	{
		object = owner->scene->obstacles[i];

		//if dist(obj.pos + zom.pos) > detectionBox + obj.rad -> skip
		if ((GetDistance(object->GetObjectPosition(), owner->GetObjectPosition())) > detection_box_length+ object->GetCollisionRadius()) continue;

		//ToLocalSpace
		glm::mat4 rot = glm::rotate(glm::mat4(1.0f), (float)(-angle), glm::vec3(0, 0, 1));
		glm::vec2 local_position(rot * glm::vec4(object->GetObjectPosition() - owner->GetObjectPosition(), 0.0f, 0.0f));

		//if behind -> skip
		if (local_position.y < 0) continue;

		//debug
		obstacle_position[obstacle_number].Hide();
		obstacle_position[obstacle_number++].UpdatePoint(local_position, object->GetCollisionRadius(), glm::vec3(0, 1, 0));

		//obj.rad + zom.rad
		float expanded_radius = object->GetCollisionRadius() + owner->GetCollisionRadius();

		//if doesn't collide -> skip
		if (fabs(local_position.x) >= expanded_radius) continue;

		double cX = local_position.x;
		double cY = local_position.y;

		double sqrt_part = sqrt(expanded_radius*expanded_radius - cX*cX);

		//intersection point
		double ip = cY - sqrt_part;
		if(ip <= 0) ip = cY + sqrt_part;

		//debug
		intersection[intersection_number].Hide();
		intersection[intersection_number++].UpdatePoint(glm::vec2(0, ip) , 0.2f, glm::vec3(1, 0, 0));

		if(ip < dist_to_closest_ip)
		{
			dist_to_closest_ip = (float)ip;
			pointer_to_closest_ob = object;					//rember closest obj
			local_position_of_closest_ob = local_position;	//rember closest obj position in LocalSpace
		}
	}

	glm::vec2 force(0.0f, 0.0f);

	//if doesnt have IP return 0 force
	if(pointer_to_closest_ob == 0) return force;

	//stronger force the closer we are
	double multiplier = 1.0 + (detection_box_length - local_position_of_closest_ob.y) / detection_box_length;

	//if negative -> collapses zombie behaviour
	if (multiplier < 0) multiplier = 0.1;

	// lateral force with sides
	if (local_position_of_closest_ob.x<0)
		force.x = (float)((pointer_to_closest_ob->GetCollisionRadius() - local_position_of_closest_ob.x) * multiplier);
	else
		force.x = -(float)((pointer_to_closest_ob->GetCollisionRadius() + local_position_of_closest_ob.x) * multiplier);

	const double braking_weight = 0.2;

	force.y = (float)((pointer_to_closest_ob->GetCollisionRadius() - local_position_of_closest_ob.y) * braking_weight);

	glm::mat4 rot = glm::rotate(glm::mat4(1.0f), GetAngle(glm::vec2(0, 1), owner->object_heading), glm::vec3(0, 0, 1));
	glm::vec2 force_world(rot * glm::vec4(force, 0.0f, 0.0f));

	return force_world*glm::vec2(333,333);
}

glm::vec2 SteeringBehaviour::CalculateHidingSpot(const glm::vec2 &target, const glm::vec2 &obstacle, double radius)
{
	const double dist_from_boundry = 3.0;
	double dist = radius + dist_from_boundry;

	glm::vec2 to_obstacle = obstacle - target;
	Normalize(to_obstacle);
	to_obstacle *= dist;

	return to_obstacle + obstacle;
}

glm::vec2 SteeringBehaviour::CalculateHide(void)
{
	double best_dist = 999999.0;
	glm::vec2 best_spot;
	int best_index = -1;

	for(int i=0; i<scene->obstacles.size(); ++i)
	{
		glm::vec2 hide_spot = CalculateHidingSpot(scene->player->GetObjectPosition(), scene->obstacles[i]->GetObjectPosition(), scene->obstacles[i]->GetCollisionRadius());

		double dist = GetDistanceSqrt(hide_spot, owner->GetObjectPosition());

		if(dist < best_dist)
		{
			best_dist = dist;
			best_spot = hide_spot;
			best_index = i;
		}

		hiding_spot[i].UpdatePoint(hide_spot, 0.2f, glm::vec3(1, 0, 1));
	}

	hiding_spot[best_index].UpdatePoint(best_spot, 0.2f, glm::vec3(1, 1, 0));

	return CalculateSeek(best_spot);  // !!!!!! ZMIENIC NA ARRIVE !!!!!!!
}
<|endoftext|>


<commit_before>/**************************************************************************
* Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
*                                                                        *
* Author: The ALICE Off-line Project.                                    *
* Contributors are mentioned in the code where appropriate.              *
*                                                                        *
* Permission to use, copy, modify and distribute this software and its   *
* documentation strictly for non-commercial purposes is hereby granted   *
* without fee, provided that the above copyright notice appears in all   *
* copies and that both the copyright notice and this permission notice   *
* appear in the supporting documentation. The authors make no claims     *
* about the suitability of this software for any purpose. It is          *
* provided "as is" without express or implied warranty.                  *
**************************************************************************/

// $Id$

#include "AliMUONDigitCalibrator.h"

#include "AliLog.h"
#include "AliMpConstants.h"
#include "AliMUONCalibrationData.h"
#include "AliMUONVDigit.h"
#include "AliMUONVDigitStore.h"
#include "AliMUONLogger.h"
#include "AliMUONPadStatusMaker.h"
#include "AliMUONPadStatusMapMaker.h"
#include "AliMUONVStore.h"
#include "AliMUONVCalibParam.h"

/// \class AliMUONDigitCalibrator
/// Class used to calibrate digits (either real or simulated ones).
///
/// The calibration consists of subtracting the pedestal
/// and multiplying by a gain, so that
/// Signal = (ADC-pedestal)*gain
///
/// Please note also that for the moment, if a digit lies on a dead channel
/// we remove this digit from the list of digits.
/// FIXME: this has to be revisited. By using the AliMUONDigit::fFlags we
/// should in principle flag a digit as bad w/o removing it, but this
/// then requires some changes in the cluster finder to deal with this extra
/// information correctly (e.g. to set a quality for the cluster if it contains
/// bad digits).
///
/// \author Laurent Aphecetche

/// \cond CLASSIMP
ClassImp(AliMUONDigitCalibrator)
/// \endcond

//_____________________________________________________________________________
AliMUONDigitCalibrator::AliMUONDigitCalibrator(const AliMUONCalibrationData& calib,
                                               Bool_t createAndUseStatusMap)
: TObject(),
fCalibrationData(calib),
fStatusMap(0x0),
fLogger(new AliMUONLogger(1000))
{
  /// ctor
  if (createAndUseStatusMap)
  {
    AliMUONPadStatusMaker maker(fCalibrationData);

    // this is here that we decide on our "goodness" policy, i.e.
    // what do we call an invalid pad (a pad maybe bad because its HV
    // was too low, or its pedestals too high, etc..)
    // FIXME: find a way not to hard-code the goodness policy (i.e. the limits)
    // here...
    maker.SetHVSt12Limits(1300,1600);
    maker.SetHVSt345Limits(1500,2000);
    maker.SetPedMeanLimits(50,200);
    maker.SetPedSigmaLimits(0.1,3);

    // From this set of limits, compute the status of all tracker pads.
    AliMUONVStore* status = maker.MakeStatus();
    // we do not check that status is != 0x0, as this is supposed to be
    // the responsability of the padStatusMaker.

    AliMUONPadStatusMapMaker mapMaker(fCalibrationData);

    Int_t mask(0x8080);
    //FIXME: kind of fake one for the moment, we consider dead only
    // if ped and/or hv value missing.
    //WARNING : getting this mask wrong is a very effective way of getting
    //no digits at all out of this class ;-)

    fStatusMap = mapMaker.MakePadStatusMap(*status,mask);

    delete status;
    }
  else
  {
    // make a fake (empty) status map
    fStatusMap = AliMUONPadStatusMapMaker::MakeEmptyPadStatusMap();
  }
}

//_____________________________________________________________________________
AliMUONDigitCalibrator::~AliMUONDigitCalibrator()
{
  /// dtor.
  delete fStatusMap;

  AliInfo("Summary of messages:");
  fLogger->Print();

  delete fLogger;
}

//_____________________________________________________________________________
void
AliMUONDigitCalibrator::Calibrate(AliMUONVDigitStore& digitStore)
{
  /// Calibrate the digits contained in digitStore
  TIter next(digitStore.CreateTrackerIterator());
  AliMUONVDigit* digit;

  while ( ( digit = static_cast<AliMUONVDigit*>(next() ) ) )
  {
    CalibrateDigit(*digit);
  }
}

//_____________________________________________________________________________
void
AliMUONDigitCalibrator::CalibrateDigit(AliMUONVDigit& digit)
{
  /// Calibrate one digit

  if ( digit.IsCalibrated() )
  {
    fLogger->Log("ERROR : trying to calibrate a digit twice");
    return;
  }

  AliMUONVCalibParam* deadmap = static_cast<AliMUONVCalibParam*>
  (fStatusMap->FindObject(digit.DetElemId(),digit.ManuId()));
  Int_t statusMap = deadmap->ValueAsInt(digit.ManuChannel());
  digit.SetStatusMap(statusMap);
  digit.Calibrated(kTRUE);
  if ( ( statusMap & AliMUONPadStatusMapMaker::SelfDeadMask() ) != 0 )
  {
    // pad itself is bad (not testing its neighbours at this stage)
    digit.SetCharge(0);
    fLogger->Log(Form("%s:%d:Channel detElemId %d manuId %d "
                    "manuChannel %d is bad %x",__FILE__,__LINE__,
                    digit.DetElemId(),digit.ManuId(),
                    digit.ManuChannel(),digit.StatusMap()));
  }
  else
  {
    // If the channel is good, go on with the calibration itself.

    AliMUONVCalibParam* pedestal = static_cast<AliMUONVCalibParam*>
    (fCalibrationData.Pedestals(digit.DetElemId(),digit.ManuId()));

    AliMUONVCalibParam* gain = static_cast<AliMUONVCalibParam*>
      (fCalibrationData.Gains(digit.DetElemId(),digit.ManuId()));

    if (!pedestal)
    {
      AliFatal(Form("Got a null ped object for DE,manu=%d,%d",
                    digit.DetElemId(),digit.ManuId()));

    }
    if (!gain)
    {
      AliFatal(Form("Got a null gain object for DE,manu=%d,%d",
                    digit.DetElemId(),digit.ManuId()));
    }

    Int_t manuChannel = digit.ManuChannel();
    Float_t adc = digit.ADC();
    Float_t padc = adc-pedestal->ValueAsFloat(manuChannel,0);
    Float_t charge(0);
    if ( padc > 3.0*pedestal->ValueAsFloat(manuChannel,1) )
    {
      Float_t a0 = gain->ValueAsFloat(manuChannel,0);
      Float_t a1 = gain->ValueAsFloat(manuChannel,1);
      Int_t thres = gain->ValueAsInt(manuChannel,2);
      if ( padc < thres )
      {
        charge = a0*padc;
      }
      else
      {
        charge = a0*thres + a0*padc + a1*padc*padc;
      }
    }
    digit.SetCharge(charge);
    Int_t saturation = gain->ValueAsInt(manuChannel,4);
    if ( charge >= saturation )
    {
      digit.Saturated(kTRUE);
    }
  }
}
<commit_msg>Non-linear correction was incorrectly applied (Laurent)<commit_after>/**************************************************************************
* Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
*                                                                        *
* Author: The ALICE Off-line Project.                                    *
* Contributors are mentioned in the code where appropriate.              *
*                                                                        *
* Permission to use, copy, modify and distribute this software and its   *
* documentation strictly for non-commercial purposes is hereby granted   *
* without fee, provided that the above copyright notice appears in all   *
* copies and that both the copyright notice and this permission notice   *
* appear in the supporting documentation. The authors make no claims     *
* about the suitability of this software for any purpose. It is          *
* provided "as is" without express or implied warranty.                  *
**************************************************************************/

// $Id$

#include "AliMUONDigitCalibrator.h"

#include "AliLog.h"
#include "AliMpConstants.h"
#include "AliMUONCalibrationData.h"
#include "AliMUONVDigit.h"
#include "AliMUONVDigitStore.h"
#include "AliMUONLogger.h"
#include "AliMUONPadStatusMaker.h"
#include "AliMUONPadStatusMapMaker.h"
#include "AliMUONVStore.h"
#include "AliMUONVCalibParam.h"

/// \class AliMUONDigitCalibrator
/// Class used to calibrate digits (either real or simulated ones).
///
/// The calibration consists of subtracting the pedestal
/// and multiplying by a gain, so that
/// Signal = (ADC-pedestal)*gain
///
/// Please note also that for the moment, if a digit lies on a dead channel
/// we remove this digit from the list of digits.
/// FIXME: this has to be revisited. By using the AliMUONDigit::fFlags we
/// should in principle flag a digit as bad w/o removing it, but this
/// then requires some changes in the cluster finder to deal with this extra
/// information correctly (e.g. to set a quality for the cluster if it contains
/// bad digits).
///
/// \author Laurent Aphecetche

/// \cond CLASSIMP
ClassImp(AliMUONDigitCalibrator)
/// \endcond

//_____________________________________________________________________________
AliMUONDigitCalibrator::AliMUONDigitCalibrator(const AliMUONCalibrationData& calib,
                                               Bool_t createAndUseStatusMap)
: TObject(),
fCalibrationData(calib),
fStatusMap(0x0),
fLogger(new AliMUONLogger(1000))
{
  /// ctor
  if (createAndUseStatusMap)
  {
    AliMUONPadStatusMaker maker(fCalibrationData);

    // this is here that we decide on our "goodness" policy, i.e.
    // what do we call an invalid pad (a pad maybe bad because its HV
    // was too low, or its pedestals too high, etc..)
    // FIXME: find a way not to hard-code the goodness policy (i.e. the limits)
    // here...
    maker.SetHVSt12Limits(1300,1600);
    maker.SetHVSt345Limits(1500,2000);
    maker.SetPedMeanLimits(50,200);
    maker.SetPedSigmaLimits(0.1,3);

    // From this set of limits, compute the status of all tracker pads.
    AliMUONVStore* status = maker.MakeStatus();
    // we do not check that status is != 0x0, as this is supposed to be
    // the responsability of the padStatusMaker.

    AliMUONPadStatusMapMaker mapMaker(fCalibrationData);

    Int_t mask(0x8080);
    //FIXME: kind of fake one for the moment, we consider dead only
    // if ped and/or hv value missing.
    //WARNING : getting this mask wrong is a very effective way of getting
    //no digits at all out of this class ;-)

    fStatusMap = mapMaker.MakePadStatusMap(*status,mask);

    delete status;
    }
  else
  {
    // make a fake (empty) status map
    fStatusMap = AliMUONPadStatusMapMaker::MakeEmptyPadStatusMap();
  }
}

//_____________________________________________________________________________
AliMUONDigitCalibrator::~AliMUONDigitCalibrator()
{
  /// dtor.
  delete fStatusMap;

  AliInfo("Summary of messages:");
  fLogger->Print();

  delete fLogger;
}

//_____________________________________________________________________________
void
AliMUONDigitCalibrator::Calibrate(AliMUONVDigitStore& digitStore)
{
  /// Calibrate the digits contained in digitStore
  TIter next(digitStore.CreateTrackerIterator());
  AliMUONVDigit* digit;

  while ( ( digit = static_cast<AliMUONVDigit*>(next() ) ) )
  {
    CalibrateDigit(*digit);
  }
}

//_____________________________________________________________________________
void
AliMUONDigitCalibrator::CalibrateDigit(AliMUONVDigit& digit)
{
  /// Calibrate one digit

  if ( digit.IsCalibrated() )
  {
    fLogger->Log("ERROR : trying to calibrate a digit twice");
    return;
  }

  AliMUONVCalibParam* deadmap = static_cast<AliMUONVCalibParam*>
  (fStatusMap->FindObject(digit.DetElemId(),digit.ManuId()));
  Int_t statusMap = deadmap->ValueAsInt(digit.ManuChannel());
  digit.SetStatusMap(statusMap);
  digit.Calibrated(kTRUE);
  if ( ( statusMap & AliMUONPadStatusMapMaker::SelfDeadMask() ) != 0 )
  {
    // pad itself is bad (not testing its neighbours at this stage)
    digit.SetCharge(0);
    fLogger->Log(Form("%s:%d:Channel detElemId %d manuId %d "
                    "manuChannel %d is bad %x",__FILE__,__LINE__,
                    digit.DetElemId(),digit.ManuId(),
                    digit.ManuChannel(),digit.StatusMap()));
  }
  else
  {
    // If the channel is good, go on with the calibration itself.

    AliMUONVCalibParam* pedestal = static_cast<AliMUONVCalibParam*>
    (fCalibrationData.Pedestals(digit.DetElemId(),digit.ManuId()));

    AliMUONVCalibParam* gain = static_cast<AliMUONVCalibParam*>
      (fCalibrationData.Gains(digit.DetElemId(),digit.ManuId()));

    if (!pedestal)
    {
      AliFatal(Form("Got a null ped object for DE,manu=%d,%d",
                    digit.DetElemId(),digit.ManuId()));

    }
    if (!gain)
    {
      AliFatal(Form("Got a null gain object for DE,manu=%d,%d",
                    digit.DetElemId(),digit.ManuId()));
    }

    Int_t manuChannel = digit.ManuChannel();
    Float_t adc = digit.ADC();
    Float_t padc = adc-pedestal->ValueAsFloat(manuChannel,0);
    Float_t charge(0);
    if ( padc > 3.0*pedestal->ValueAsFloat(manuChannel,1) )
    {
      Float_t a0 = gain->ValueAsFloat(manuChannel,0);
      Float_t a1 = gain->ValueAsFloat(manuChannel,1);
      Int_t thres = gain->ValueAsInt(manuChannel,2);
      if ( padc < thres )
      {
        charge = a0*padc;
      }
      else
      {
        charge = a0*thres + a0*(padc-thres) + a1*(padc-thres)*(padc-thres);
      }
    }
    digit.SetCharge(charge);
    Int_t saturation = gain->ValueAsInt(manuChannel,4);
    if ( charge >= saturation )
    {
      digit.Saturated(kTRUE);
    }
  }
}
<|endoftext|>


<commit_before>// Copyright (c) 2011 Zeex
//
// 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.

#include <algorithm>
#include <functional>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <sstream>
#include <string>
#include <vector>

#include "amxcallstack.h"
#include "amxdebuginfo.h"

#include "amx/amx.h"
#include "amx/amxdbg.h"

static bool IsFunctionArgument(const AMXDebugInfo::Symbol &symbol, ucell functionAddress) {
	return symbol.IsLocal() && symbol.GetCodeStartAddress() == functionAddress;
}

class IsArgumentOf : public std::unary_function<AMXDebugInfo::Symbol, bool> {
public:
	IsArgumentOf(ucell function) : function_(function) {}

	bool operator()(AMXDebugInfo::Symbol symbol) const {
		return symbol.IsLocal() && symbol.GetCodeStartAddress() == function_;
	}

private:
	ucell function_;
};

static inline bool CompareArguments(const AMXDebugInfo::Symbol &left, const AMXDebugInfo::Symbol &right) {
	return left.GetAddress() < right.GetAddress();
}

class IsFunctionAt : public std::unary_function<const AMXDebugInfo::Symbol&, bool> {
public:
	IsFunctionAt(ucell address) : address_(address) {}

	bool operator()(const AMXDebugInfo::Symbol &symbol) const {
		return symbol.IsFunction() && symbol.GetAddress() == address_;
	}

private:
	ucell address_;
};

static inline const char *GetPublicFunctionName(AMX *amx, ucell address) {
	AMX_HEADER *hdr = reinterpret_cast<AMX_HEADER*>(amx->base);

	AMX_FUNCSTUBNT *publics = reinterpret_cast<AMX_FUNCSTUBNT*>(amx->base + hdr->publics);
	AMX_FUNCSTUBNT *natives = reinterpret_cast<AMX_FUNCSTUBNT*>(amx->base + hdr->natives);

	for (AMX_FUNCSTUBNT *p = publics; p < natives; ++p) {
		if (p->address == address) {
			return reinterpret_cast<const char*>(p->nameofs + amx->base);
		}
	}

	return 0;
}

static inline bool IsPublicFunction(AMX *amx, ucell address) {
	return GetPublicFunctionName(amx, address) != 0;
}

AMXStackFrame::AMXStackFrame(AMX *amx, ucell frameAddress, const AMXDebugInfo &debugInfo)
	: isPublic_(false)
	, frameAddress_(frameAddress)
	, callAddress_(0)
	, functionAddress_(0)
{
	if (IsOnStack(frameAddress_, amx)) {
		AMX_HEADER *hdr = reinterpret_cast<AMX_HEADER*>(amx->base);

		ucell data = reinterpret_cast<ucell>(amx->base + hdr->dat);
		ucell code = reinterpret_cast<ucell>(amx->base) + hdr->cod;

		callAddress_ = *(reinterpret_cast<ucell*>(data + frameAddress_) + 1) - 2*sizeof(cell);
		if (callAddress_ >= static_cast<ucell>(hdr->cod)
				&& callAddress_ < static_cast<ucell>(hdr->dat))
		{
			functionAddress_ = *reinterpret_cast<ucell*>(callAddress_ + sizeof(cell) + code) - code;
			Init(amx, debugInfo);
		} else {
			callAddress_ = 0;
		}
	}
}

AMXStackFrame::AMXStackFrame(AMX *amx, ucell frameAddress, ucell callAddress,
		ucell functionAddress, const AMXDebugInfo &debugInfo)
	: isPublic_(false)
	, frameAddress_(frameAddress)
	, callAddress_(callAddress)
	, functionAddress_(functionAddress)
{
	Init(amx, debugInfo);
}

void AMXStackFrame::Init(AMX *amx, const AMXDebugInfo &debugInfo) {
	isPublic_ = IsPublicFunction(amx, functionAddress_);

	if (debugInfo.IsLoaded()) {
		if (callAddress_ != 0) {
			fileName_ = debugInfo.GetFileName(callAddress_);
			lineNumber_ = debugInfo.GetLineNumber(callAddress_);
		} else {
			// Entry point
			fileName_ = debugInfo.GetFileName(functionAddress_);
			lineNumber_ = debugInfo.GetLineNumber(functionAddress_);
		}

		// Get function return value tag
		AMXDebugInfo::SymbolTable::const_iterator it = std::find_if(
			debugInfo.GetSymbols().begin(),
			debugInfo.GetSymbols().end(),
			IsFunctionAt(functionAddress_)
		);
		if (it != debugInfo.GetSymbols().end()) {
			functionResultTag_ = debugInfo.GetTagName((*it).GetTag()) + ":";
			if (functionResultTag_ == "_:") {
				functionResultTag_.clear();
			}
		}

		// Get function name
		functionName_ = debugInfo.GetFunctionName(functionAddress_);

		// Get parameters
		std::remove_copy_if(
			debugInfo.GetSymbols().begin(),
			debugInfo.GetSymbols().end(),
			std::back_inserter(arguments_),
			std::not1(IsArgumentOf(functionAddress_))
		);

		// Order them by address
		std::sort(arguments_.begin(), arguments_.end(), CompareArguments);

		// Build a comma-separated list of arguments and their values
		std::stringstream argStream;
		for (std::vector<AMXDebugInfo::Symbol>::const_iterator arg = arguments_.begin();
				arg != arguments_.end(); ++arg) {
			if (arg != arguments_.begin()) {
				argStream << ", ";
			}

			// For reference parameters, print the '&' sign in front of their tag
			if (arg->IsReference()) {
				argStream << "&";
			}

			// Get parameter's tag
			std::string tag = debugInfo.GetTag(arg->GetTag()).GetName() + ":";
			if (tag != "_:") {
				argStream << tag;
			}

			// Get parameter name
			argStream << arg->GetName();

			cell value = arg->GetValue(amx);
			if (arg->IsVariable()) {
				if (tag == "bool:") {
					argStream << "=" << value ? "true" : "false";
				} else if (tag == "Float:") {
					argStream << "=" << std::fixed << std::setprecision(5) << amx_ctof(value);
				} else {
					argStream << "=" << value;
				}
			} else {
				if (arg->IsArray() || arg->IsArrayRef()) {
					// Get array dimensions
					std::vector<AMXDebugInfo::SymbolDim> dims = arg->GetDims();
					for (std::size_t i = 0; i < dims.size(); ++i) {
						if (dims[i].GetSize() == 0) {
							argStream << "[]";
						} else {
							std::string tag = debugInfo.GetTagName(dims[i].GetTag()) + ":";
							if (tag == "_:") tag.clear();
							argStream << "[" << tag << dims[i].GetSize() << "]";
						}
					}
				}
				argStream << "=@0x" << std::hex << value << std::dec;
			}
		}

		// The function prototype is of the following form:
		// [public ][tag:]name([arg1=value1[, arg2=value2, [...]]])
		if (IsPublic()) {
			functionPrototype_.append("public ");
		}
		functionPrototype_
			.append(functionResultTag_)
			.append(functionName_)
			.append("(")
			.append(argStream.str())
			.append(")");
	} else {
		// No debug info available...
		const char *name = GetPublicFunctionName(amx, functionAddress_);
		if (name != 0) {
			functionName_.assign(name);
		}
	}
}

AMXCallStack::AMXCallStack(AMX *amx, const AMXDebugInfo &debugInfo, ucell topFrame) {
	AMX_HEADER *hdr = reinterpret_cast<AMX_HEADER*>(amx->base);
	ucell data = reinterpret_cast<ucell>(amx->base + hdr->dat);

	ucell frm = topFrame;
	if (frm == 0) {
		frm = amx->frm;
	}

	while (frm > static_cast<ucell>(amx->stk)) {
		AMXStackFrame frame(amx, frm, debugInfo);
		frames_.push_back(frame);
		if (frame.GetFunctionAddress() == 0) {
			// Invalid frame address
			return;
		}
		frm = *reinterpret_cast<ucell*>(data + frm);
	}

	// Correct entry point address (it's not on the stack)
	if (debugInfo.IsLoaded()) {
		if (frames_.size() > 1) {
			ucell epAddr = debugInfo.GetFunctionStartAddress(frames_[frames_.size() - 2].GetCallAddress());
			frames_.back() = AMXStackFrame(amx, frames_.back().GetFrameAddress(), 0, epAddr, debugInfo);
		} else if (frames_.size() != 0) {
			ucell epAddr = debugInfo.GetFunctionStartAddress(amx->cip);
			frames_.back() = AMXStackFrame(amx, frames_.back().GetFrameAddress(), 0, epAddr, debugInfo);
		}
	} else {
		// Can't fetch the address
		frames_.back() = AMXStackFrame(amx, 0, 0, 0);
	}
}
<commit_msg>Fix v3.9.1 regression: incomplete call stack<commit_after>// Copyright (c) 2011 Zeex
//
// 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.

#include <algorithm>
#include <functional>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <sstream>
#include <string>
#include <vector>

#include "amxcallstack.h"
#include "amxdebuginfo.h"

#include "amx/amx.h"
#include "amx/amxdbg.h"

static bool IsFunctionArgument(const AMXDebugInfo::Symbol &symbol, ucell functionAddress) {
	return symbol.IsLocal() && symbol.GetCodeStartAddress() == functionAddress;
}

class IsArgumentOf : public std::unary_function<AMXDebugInfo::Symbol, bool> {
public:
	IsArgumentOf(ucell function) : function_(function) {}

	bool operator()(AMXDebugInfo::Symbol symbol) const {
		return symbol.IsLocal() && symbol.GetCodeStartAddress() == function_;
	}

private:
	ucell function_;
};

static inline bool CompareArguments(const AMXDebugInfo::Symbol &left, const AMXDebugInfo::Symbol &right) {
	return left.GetAddress() < right.GetAddress();
}

class IsFunctionAt : public std::unary_function<const AMXDebugInfo::Symbol&, bool> {
public:
	IsFunctionAt(ucell address) : address_(address) {}

	bool operator()(const AMXDebugInfo::Symbol &symbol) const {
		return symbol.IsFunction() && symbol.GetAddress() == address_;
	}

private:
	ucell address_;
};

static inline const char *GetPublicFunctionName(AMX *amx, ucell address) {
	AMX_HEADER *hdr = reinterpret_cast<AMX_HEADER*>(amx->base);

	AMX_FUNCSTUBNT *publics = reinterpret_cast<AMX_FUNCSTUBNT*>(amx->base + hdr->publics);
	AMX_FUNCSTUBNT *natives = reinterpret_cast<AMX_FUNCSTUBNT*>(amx->base + hdr->natives);

	for (AMX_FUNCSTUBNT *p = publics; p < natives; ++p) {
		if (p->address == address) {
			return reinterpret_cast<const char*>(p->nameofs + amx->base);
		}
	}

	return 0;
}

static inline bool IsPublicFunction(AMX *amx, ucell address) {
	return GetPublicFunctionName(amx, address) != 0;
}

AMXStackFrame::AMXStackFrame(AMX *amx, ucell frameAddress, const AMXDebugInfo &debugInfo)
	: isPublic_(false)
	, frameAddress_(frameAddress)
	, callAddress_(0)
	, functionAddress_(0)
{
	if (IsOnStack(frameAddress_, amx)) {
		AMX_HEADER *hdr = reinterpret_cast<AMX_HEADER*>(amx->base);

		ucell data = reinterpret_cast<ucell>(amx->base + hdr->dat);
		ucell code = reinterpret_cast<ucell>(amx->base) + hdr->cod;

		callAddress_ = *(reinterpret_cast<ucell*>(data + frameAddress_) + 1) - 2*sizeof(cell);
		if (callAddress_ >= 0 && callAddress_ < static_cast<ucell>(hdr->dat - hdr->cod)) {
			functionAddress_ = *reinterpret_cast<ucell*>(callAddress_ + sizeof(cell) + code) - code;
			Init(amx, debugInfo);
		} else {
			callAddress_ = 0;
		}
	}
}

AMXStackFrame::AMXStackFrame(AMX *amx, ucell frameAddress, ucell callAddress,
		ucell functionAddress, const AMXDebugInfo &debugInfo)
	: isPublic_(false)
	, frameAddress_(frameAddress)
	, callAddress_(callAddress)
	, functionAddress_(functionAddress)
{
	Init(amx, debugInfo);
}

void AMXStackFrame::Init(AMX *amx, const AMXDebugInfo &debugInfo) {
	isPublic_ = IsPublicFunction(amx, functionAddress_);

	if (debugInfo.IsLoaded()) {
		if (callAddress_ != 0) {
			fileName_ = debugInfo.GetFileName(callAddress_);
			lineNumber_ = debugInfo.GetLineNumber(callAddress_);
		} else {
			// Entry point
			fileName_ = debugInfo.GetFileName(functionAddress_);
			lineNumber_ = debugInfo.GetLineNumber(functionAddress_);
		}

		// Get function return value tag
		AMXDebugInfo::SymbolTable::const_iterator it = std::find_if(
			debugInfo.GetSymbols().begin(),
			debugInfo.GetSymbols().end(),
			IsFunctionAt(functionAddress_)
		);
		if (it != debugInfo.GetSymbols().end()) {
			functionResultTag_ = debugInfo.GetTagName((*it).GetTag()) + ":";
			if (functionResultTag_ == "_:") {
				functionResultTag_.clear();
			}
		}

		// Get function name
		functionName_ = debugInfo.GetFunctionName(functionAddress_);

		// Get parameters
		std::remove_copy_if(
			debugInfo.GetSymbols().begin(),
			debugInfo.GetSymbols().end(),
			std::back_inserter(arguments_),
			std::not1(IsArgumentOf(functionAddress_))
		);

		// Order them by address
		std::sort(arguments_.begin(), arguments_.end(), CompareArguments);

		// Build a comma-separated list of arguments and their values
		std::stringstream argStream;
		for (std::vector<AMXDebugInfo::Symbol>::const_iterator arg = arguments_.begin();
				arg != arguments_.end(); ++arg) {
			if (arg != arguments_.begin()) {
				argStream << ", ";
			}

			// For reference parameters, print the '&' sign in front of their tag
			if (arg->IsReference()) {
				argStream << "&";
			}

			// Get parameter's tag
			std::string tag = debugInfo.GetTag(arg->GetTag()).GetName() + ":";
			if (tag != "_:") {
				argStream << tag;
			}

			// Get parameter name
			argStream << arg->GetName();

			cell value = arg->GetValue(amx);
			if (arg->IsVariable()) {
				if (tag == "bool:") {
					argStream << "=" << value ? "true" : "false";
				} else if (tag == "Float:") {
					argStream << "=" << std::fixed << std::setprecision(5) << amx_ctof(value);
				} else {
					argStream << "=" << value;
				}
			} else {
				if (arg->IsArray() || arg->IsArrayRef()) {
					// Get array dimensions
					std::vector<AMXDebugInfo::SymbolDim> dims = arg->GetDims();
					for (std::size_t i = 0; i < dims.size(); ++i) {
						if (dims[i].GetSize() == 0) {
							argStream << "[]";
						} else {
							std::string tag = debugInfo.GetTagName(dims[i].GetTag()) + ":";
							if (tag == "_:") tag.clear();
							argStream << "[" << tag << dims[i].GetSize() << "]";
						}
					}
				}
				argStream << "=@0x" << std::hex << value << std::dec;
			}
		}

		// The function prototype is of the following form:
		// [public ][tag:]name([arg1=value1[, arg2=value2, [...]]])
		if (IsPublic()) {
			functionPrototype_.append("public ");
		}
		functionPrototype_
			.append(functionResultTag_)
			.append(functionName_)
			.append("(")
			.append(argStream.str())
			.append(")");
	} else {
		// No debug info available...
		const char *name = GetPublicFunctionName(amx, functionAddress_);
		if (name != 0) {
			functionName_.assign(name);
		}
	}
}

AMXCallStack::AMXCallStack(AMX *amx, const AMXDebugInfo &debugInfo, ucell topFrame) {
	AMX_HEADER *hdr = reinterpret_cast<AMX_HEADER*>(amx->base);
	ucell data = reinterpret_cast<ucell>(amx->base + hdr->dat);

	ucell frm = topFrame;
	if (frm == 0) {
		frm = amx->frm;
	}

	while (frm > static_cast<ucell>(amx->stk)) {
		AMXStackFrame frame(amx, frm, debugInfo);
		frames_.push_back(frame);
		if (frame.GetFunctionAddress() == 0) {
			// Invalid frame address
			return;
		}
		frm = *reinterpret_cast<ucell*>(data + frm);
	}

	// Correct entry point address (it's not on the stack)
	if (debugInfo.IsLoaded()) {
		if (frames_.size() > 1) {
			ucell epAddr = debugInfo.GetFunctionStartAddress(frames_[frames_.size() - 2].GetCallAddress());
			frames_.back() = AMXStackFrame(amx, frames_.back().GetFrameAddress(), 0, epAddr, debugInfo);
		} else if (frames_.size() != 0) {
			ucell epAddr = debugInfo.GetFunctionStartAddress(amx->cip);
			frames_.back() = AMXStackFrame(amx, frames_.back().GetFrameAddress(), 0, epAddr, debugInfo);
		}
	} else {
		// Can't fetch the address
		frames_.back() = AMXStackFrame(amx, 0, 0, 0);
	}
}
<|endoftext|>


<commit_before>/*
   For more information, please see: http://software.sci.utah.edu

   The MIT License

   Copyright (c) 2008 Scientific Computing and Imaging Institute,
   University of Utah.

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included
   in all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   DEALINGS IN THE SOFTWARE.
*/

/**
  \file    ConsoleOut.cpp
  \author  Jens Krueger
           SCI Institute
           University of Utah
  \date    August 2008
*/

#include "ConsoleOut.h"
#include "Basics/Console.h"

/// ANSI escape codes for various colors.
///@{
static const char C_DGRAY[]  = "\033[01;30m";
static const char C_NORM[]   = "\033[00m";
static const char C_RED[]    = "\033[01;31m";
static const char C_YELLOW[] = "\033[01;33m";
static const char C_GREEN[]  = "\033[01;32m";
static const char C_MAG[]    = "\033[01;35m";
static const char C_LBLUE[]  = "\033[01;36m";
static const char C_WHITE[]  = "\033[01;27m";
///@}

ConsoleOut::ConsoleOut() {
  Message("ConsoleOut::ConsoleOut:","Starting up ConsoleDebug out");
}

ConsoleOut::~ConsoleOut() {
  Message("ConsoleOut::~ConsoleOut:","Shutting down ConsoleDebug out");
}

void ConsoleOut::printf(const char* format, ...) const
{
  if (!m_bShowOther) return;

  char buff[16384];
  va_list args;
  va_start(args, format);
#ifdef WIN32
  _vsnprintf_s( buff, 16384, sizeof(buff), format, args);
#else
  vsnprintf( buff, sizeof(buff), format, args);
#endif
  Console::printf("%s\n",buff);
}

void ConsoleOut::Message(const char* source, const char* format, ...) {
  if (!m_bShowMessages) return;
  char buff[16384];
  va_list args;
  va_start(args, format);
#ifdef WIN32
  _vsnprintf_s( buff, 16384, sizeof(buff), format, args);
#else
  vsnprintf( buff, sizeof(buff), format, args);
#endif

#ifndef TUVOK_OS_WINDOWS
  this->printf("%sMESSAGE%s (%s): %s", C_DGRAY, C_NORM, source, buff);
#else
  this->printf("MESSAGE (%s): %s", source, buff);
#endif
}

void ConsoleOut::Warning(const char* source, const char* format, ...) {
  if (!m_bShowWarnings) return;
  char buff[16384];
  va_list args;
  va_start(args, format);
#ifdef WIN32
  _vsnprintf_s( buff, 16384, sizeof(buff), format, args);
#else
  vsnprintf( buff, sizeof(buff), format, args);
#endif
#ifndef TUVOK_OS_WINDOWS
  this->printf("%sWARNING%s (%s): %s", C_DGRAY, C_NORM, source, buff);
#else
  this->printf("WARNING (%s): %s", source, buff);
#endif
}

void ConsoleOut::Error(const char* source, const char* format, ...) {
  if (!m_bShowErrors) return;
  char buff[16384];
  va_list args;
  va_start(args, format);
#ifdef WIN32
  _vsnprintf_s( buff, 16384, sizeof(buff), format, args);
#else
  vsnprintf( buff, sizeof(buff), format, args);
#endif

#ifndef TUVOK_OS_WINDOWS
  this->printf("%sERROR%s (%s): %s", C_RED, C_NORM, source, buff);
#else
  this->printf("ERROR (%s): %s", source, buff);
#endif
}
<commit_msg>Fix color of warnings.<commit_after>/*
   For more information, please see: http://software.sci.utah.edu

   The MIT License

   Copyright (c) 2008 Scientific Computing and Imaging Institute,
   University of Utah.

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included
   in all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   DEALINGS IN THE SOFTWARE.
*/

/**
  \file    ConsoleOut.cpp
  \author  Jens Krueger
           SCI Institute
           University of Utah
  \date    August 2008
*/

#include "ConsoleOut.h"
#include "Basics/Console.h"

/// ANSI escape codes for various colors.
///@{
static const char C_DGRAY[]  = "\033[01;30m";
static const char C_NORM[]   = "\033[00m";
static const char C_RED[]    = "\033[01;31m";
static const char C_YELLOW[] = "\033[01;33m";
static const char C_GREEN[]  = "\033[01;32m";
static const char C_MAG[]    = "\033[01;35m";
static const char C_LBLUE[]  = "\033[01;36m";
static const char C_WHITE[]  = "\033[01;27m";
///@}

ConsoleOut::ConsoleOut() {
  Message("ConsoleOut::ConsoleOut:","Starting up ConsoleDebug out");
}

ConsoleOut::~ConsoleOut() {
  Message("ConsoleOut::~ConsoleOut:","Shutting down ConsoleDebug out");
}

void ConsoleOut::printf(const char* format, ...) const
{
  if (!m_bShowOther) return;

  char buff[16384];
  va_list args;
  va_start(args, format);
#ifdef WIN32
  _vsnprintf_s( buff, 16384, sizeof(buff), format, args);
#else
  vsnprintf( buff, sizeof(buff), format, args);
#endif
  Console::printf("%s\n",buff);
}

void ConsoleOut::Message(const char* source, const char* format, ...) {
  if (!m_bShowMessages) return;
  char buff[16384];
  va_list args;
  va_start(args, format);
#ifdef WIN32
  _vsnprintf_s( buff, 16384, sizeof(buff), format, args);
#else
  vsnprintf( buff, sizeof(buff), format, args);
#endif

#ifndef TUVOK_OS_WINDOWS
  this->printf("%sMESSAGE%s (%s): %s", C_DGRAY, C_NORM, source, buff);
#else
  this->printf("MESSAGE (%s): %s", source, buff);
#endif
}

void ConsoleOut::Warning(const char* source, const char* format, ...) {
  if (!m_bShowWarnings) return;
  char buff[16384];
  va_list args;
  va_start(args, format);
#ifdef WIN32
  _vsnprintf_s( buff, 16384, sizeof(buff), format, args);
#else
  vsnprintf( buff, sizeof(buff), format, args);
#endif
#ifndef TUVOK_OS_WINDOWS
  this->printf("%sWARNING%s (%s): %s", C_YELLOW, C_NORM, source, buff);
#else
  this->printf("WARNING (%s): %s", source, buff);
#endif
}

void ConsoleOut::Error(const char* source, const char* format, ...) {
  if (!m_bShowErrors) return;
  char buff[16384];
  va_list args;
  va_start(args, format);
#ifdef WIN32
  _vsnprintf_s( buff, 16384, sizeof(buff), format, args);
#else
  vsnprintf( buff, sizeof(buff), format, args);
#endif

#ifndef TUVOK_OS_WINDOWS
  this->printf("%sERROR%s (%s): %s", C_RED, C_NORM, source, buff);
#else
  this->printf("ERROR (%s): %s", source, buff);
#endif
}
<|endoftext|>


<commit_before>#include "Calculator.h"
#include "Validator.h"
#include "Exception.h"
#include <algorithm>
#include <iostream>

namespace Pslrk
{
namespace Core
{

std::vector <int> Calculator::CalculateAcf (const std::string & stringView)
{
    if (Validator::ValidateStringView (stringView) != viewIsValid) {
        throw ExceptionInvalidStringView ();
    }

    std::vector <int> acf {};

    //   |+--|
    // +-|-  |
    //  +|-- |
    //   |+--|
    //   | +-|-
    //   |  +|--
    const int range = stringView.length () - 1;
    for (int i {range}; i >= -range; --i) {
        const int begin {      - i >     0 ?        -i :     0};
        const int end   {range - i < range ? range - i : range};
        int sum {0};
        for (int j {begin}; j <= end; ++j) {
            const int a {stringView [    j] == '+' ? 1 : -1};
            const int b {stringView [i + j] == '+' ? 1 : -1};
            sum += a * b;
        }
        acf.push_back (sum);
    }

    return acf;
}

std::vector <int> Calculator::CalculateCcf (const std::string & stringViewOne, const std::string & stringViewTwo)
{
    if (Validator::ValidateStringView (stringViewOne) != viewIsValid) {
        throw ExceptionInvalidStringView ();
    }

    if (Validator::ValidateStringView (stringViewTwo) != viewIsValid) {
        throw ExceptionInvalidStringView ();
    }

    std::vector <int> ccf {};

    //    |+-++|
    //  +-|-   |
    //   +|--  |
    //    |+-- |
    //    | +--|
    //    |  +-|-
    //    |   +|--

    //    |+--|
    // +-+|+  |
    //  +-|++ |
    //   +|-++|
    //    |+-+|+
    //    | +-|++
    //    |  +|-++
    const int rangeOne = stringViewOne.length () - 1;
    const int rangeTwo = stringViewTwo.length () - 1;
    for (int i {-rangeTwo}; i <= rangeOne; ++i) {
        const int begin {i <                   0 ?       -i :            0};
        const int end   {i < rangeOne - rangeTwo ? rangeTwo : rangeOne - i};
        int sum {0};
        for (int j {begin}; j <= end; ++j) {
            const int a {stringViewTwo [    j] == '+' ? 1 : -1};
            const int b {stringViewOne [i + j] == '+' ? 1 : -1};
            sum += a * b;
        }
        ccf.push_back (sum);
    }

    return ccf;
}

int Calculator::CalculatePsl (const std::string & stringView)
{
    if (stringView.empty () ) {
        return 0;
    }

    if (Validator::ValidateStringView (stringView) != viewIsValid) {
        throw ExceptionInvalidStringView ();
    }

    const size_t range {stringView.length () - 1};
    std::vector <int> acf {CalculateAcf (stringView)};
    std::transform (acf.begin (), acf.begin () + range, acf.begin (), abs);
    return * std::max_element (acf.begin (), acf.begin () + range);
}

unsigned int Calculator::CalculateE (const std::string & stringView)
{
    // Calculate energy of binary sequence.
    //
    //        N - 1  / N - k            \ 2
    //        ____   | ____             |
    // E = 2  \      | \     a + a      |
    //        /___   | /___   i   i + k |
    //        n = 1  \ i = 1            /
    //
    // N - energy of sequence.
    // n - 0 < n < N;
    // k - 0 < k < N;
    // N - length of sequence.

    unsigned int e {0u};

    const auto acf = CalculateAcf (stringView);
    for (size_t i = 0; i < stringView.size () - 1; ++i) {
        e += pow (acf [i], 2);
    }
    e *= 2u;

    return e;
}

float Calculator::CalculateIsl (const std::string & stringView)
{
    // Calculate integrated sidelobe level of binary sequence.
    //
    //              /  E  |
    // I = 10 log   | ----|
    //          10  |   2 |
    //              \  N  /
    //
    // I - integrated sidelobe level of sequence.
    // E - energy of sequence.
    // N - length of sequence.

    const auto e = CalculateE (stringView);

    const float isl = 10 * log10 (e / pow (stringView.size (), 2) );

    return isl;
}

float Calculator::CalculateMf (const std::string & stringView)
{
    // Calculate merit factor of binary sequence.
    //
    //       2
    //      N
    // M = ----
    //      E
    //
    // M - merit factor of sequence.
    // E - energy of sequence.
    // N - length of sequence.

    const auto e = CalculateE (stringView);

    const float mf = pow (stringView.size (), 2) / e;

    return mf;
}

float Calculator::CalculateDb (const int ml, const int psl)
{
    return 20.0f * log10f (static_cast <float> (psl) / static_cast <float> (ml) );
}

}// namespace Core
}// namespace Pslrk
<commit_msg>Minor fixes (fixed application crash when calculated Energy of the empty sequence).<commit_after>#include "Calculator.h"
#include "Validator.h"
#include "Exception.h"
#include <algorithm>
#include <iostream>

namespace Pslrk
{
namespace Core
{

std::vector <int> Calculator::CalculateAcf (const std::string & stringView)
{
    if (Validator::ValidateStringView (stringView) != viewIsValid) {
        throw ExceptionInvalidStringView ();
    }

    std::vector <int> acf {};

    //   |+--|
    // +-|-  |
    //  +|-- |
    //   |+--|
    //   | +-|-
    //   |  +|--
    const int range = stringView.length () - 1;
    for (int i {range}; i >= -range; --i) {
        const int begin {      - i >     0 ?        -i :     0};
        const int end   {range - i < range ? range - i : range};
        int sum {0};
        for (int j {begin}; j <= end; ++j) {
            const int a {stringView [    j] == '+' ? 1 : -1};
            const int b {stringView [i + j] == '+' ? 1 : -1};
            sum += a * b;
        }
        acf.push_back (sum);
    }

    return acf;
}

std::vector <int> Calculator::CalculateCcf (const std::string & stringViewOne, const std::string & stringViewTwo)
{
    if (Validator::ValidateStringView (stringViewOne) != viewIsValid) {
        throw ExceptionInvalidStringView ();
    }

    if (Validator::ValidateStringView (stringViewTwo) != viewIsValid) {
        throw ExceptionInvalidStringView ();
    }

    std::vector <int> ccf {};

    //    |+-++|
    //  +-|-   |
    //   +|--  |
    //    |+-- |
    //    | +--|
    //    |  +-|-
    //    |   +|--

    //    |+--|
    // +-+|+  |
    //  +-|++ |
    //   +|-++|
    //    |+-+|+
    //    | +-|++
    //    |  +|-++
    const int rangeOne = stringViewOne.length () - 1;
    const int rangeTwo = stringViewTwo.length () - 1;
    for (int i {-rangeTwo}; i <= rangeOne; ++i) {
        const int begin {i <                   0 ?       -i :            0};
        const int end   {i < rangeOne - rangeTwo ? rangeTwo : rangeOne - i};
        int sum {0};
        for (int j {begin}; j <= end; ++j) {
            const int a {stringViewTwo [    j] == '+' ? 1 : -1};
            const int b {stringViewOne [i + j] == '+' ? 1 : -1};
            sum += a * b;
        }
        ccf.push_back (sum);
    }

    return ccf;
}

int Calculator::CalculatePsl (const std::string & stringView)
{
    if (stringView.empty () ) {
        return 0;
    }

    if (Validator::ValidateStringView (stringView) != viewIsValid) {
        throw ExceptionInvalidStringView ();
    }

    const size_t range {stringView.length () - 1};
    std::vector <int> acf {CalculateAcf (stringView)};
    std::transform (acf.begin (), acf.begin () + range, acf.begin (), abs);
    return * std::max_element (acf.begin (), acf.begin () + range);
}

unsigned int Calculator::CalculateE (const std::string & stringView)
{
    // Calculate energy of binary sequence.
    //
    //        N - 1  / N - k            \ 2
    //        ____   | ____             |
    // E = 2  \      | \     a + a      |
    //        /___   | /___   i   i + k |
    //        n = 1  \ i = 1            /
    //
    // N - energy of sequence.
    // n - 0 < n < N;
    // k - 0 < k < N;
    // N - length of sequence.

    unsigned int e {0u};

    if (stringView.size () ) {
        const auto acf = CalculateAcf (stringView);
        for (size_t i = 0; i < stringView.size () - 1; ++i) {
            e += pow (acf [i], 2);
        }
        e *= 2u;
    }

    return e;
}

float Calculator::CalculateIsl (const std::string & stringView)
{
    // Calculate integrated sidelobe level of binary sequence.
    //
    //              /  E  |
    // I = 10 log   | ----|
    //          10  |   2 |
    //              \  N  /
    //
    // I - integrated sidelobe level of sequence.
    // E - energy of sequence.
    // N - length of sequence.

    const auto e = CalculateE (stringView);

    const float isl = 10 * log10 (e / pow (stringView.size (), 2) );

    return isl;
}

float Calculator::CalculateMf (const std::string & stringView)
{
    // Calculate merit factor of binary sequence.
    //
    //       2
    //      N
    // M = ----
    //      E
    //
    // M - merit factor of sequence.
    // E - energy of sequence.
    // N - length of sequence.

    const auto e = CalculateE (stringView);

    const float mf = pow (stringView.size (), 2) / e;

    return mf;
}

float Calculator::CalculateDb (const int ml, const int psl)
{
    return 20.0f * log10f (static_cast <float> (psl) / static_cast <float> (ml) );
}

}// namespace Core
}// namespace Pslrk
<|endoftext|>


<commit_before>/* -------------------------------------------------------------------------- *
 *                                   Lepton                                   *
 * -------------------------------------------------------------------------- *
 * This is part of the Lepton expression parser originating from              *
 * Simbios, the NIH National Center for Physics-Based Simulation of           *
 * Biological Structures at Stanford, funded under the NIH Roadmap for        *
 * Medical Research, grant U54 GM072970. See https://simtk.org.               *
 *                                                                            *
 * Portions copyright (c) 2013 Stanford University and the Authors.           *
 * Authors: Peter Eastman                                                     *
 * Contributors:                                                              *
 *                                                                            *
 * Permission is hereby granted, free of charge, to any person obtaining a    *
 * copy of this software and associated documentation files (the "Software"), *
 * to deal in the Software without restriction, including without limitation  *
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,   *
 * and/or sell copies of the Software, and to permit persons to whom the      *
 * Software is furnished to do so, subject to the following conditions:       *
 *                                                                            *
 * The above copyright notice and this permission notice shall be included in *
 * all copies or substantial portions of the Software.                        *
 *                                                                            *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,   *
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL    *
 * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,    *
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR      *
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE  *
 * USE OR OTHER DEALINGS IN THE SOFTWARE.                                     *
 * -------------------------------------------------------------------------- */

#include "lepton/CompiledExpression.h"
#include "lepton/Operation.h"
#include "lepton/ParsedExpression.h"
#include <utility>

using namespace Lepton;
using namespace std;
#ifdef LEPTON_USE_JIT
    using namespace asmjit;
#endif

CompiledExpression::CompiledExpression() : jitCode(NULL) {
}

CompiledExpression::CompiledExpression(const ParsedExpression& expression) : jitCode(NULL) {
    ParsedExpression expr = expression.optimize(); // Just in case it wasn't already optimized.
    vector<pair<ExpressionTreeNode, int> > temps;
    compileExpression(expr.getRootNode(), temps);
    int maxArguments = 1;
    for (int i = 0; i < (int) operation.size(); i++)
        if (operation[i]->getNumArguments() > maxArguments)
            maxArguments = operation[i]->getNumArguments();
    argValues.resize(maxArguments);
#ifdef LEPTON_USE_JIT
    generateJitCode();
#endif
}

CompiledExpression::~CompiledExpression() {
    for (int i = 0; i < (int) operation.size(); i++)
        if (operation[i] != NULL)
            delete operation[i];
}

CompiledExpression::CompiledExpression(const CompiledExpression& expression) : jitCode(NULL) {
    *this = expression;
}

CompiledExpression& CompiledExpression::operator=(const CompiledExpression& expression) {
    arguments = expression.arguments;
    target = expression.target;
    variableIndices = expression.variableIndices;
    variableNames = expression.variableNames;
    workspace.resize(expression.workspace.size());
    argValues.resize(expression.argValues.size());
    operation.resize(expression.operation.size());
    for (int i = 0; i < (int) operation.size(); i++)
        operation[i] = expression.operation[i]->clone();
#ifdef LEPTON_USE_JIT
    generateJitCode();
#endif
    return *this;
}

void CompiledExpression::compileExpression(const ExpressionTreeNode& node, vector<pair<ExpressionTreeNode, int> >& temps) {
    if (findTempIndex(node, temps) != -1)
        return; // We have already processed a node identical to this one.

    // Process the child nodes.

    vector<int> args;
    for (int i = 0; i < node.getChildren().size(); i++) {
        compileExpression(node.getChildren()[i], temps);
        args.push_back(findTempIndex(node.getChildren()[i], temps));
    }

    // Process this node.

    if (node.getOperation().getId() == Operation::VARIABLE) {
        variableIndices[node.getOperation().getName()] = (int) workspace.size();
        variableNames.insert(node.getOperation().getName());
    }
    else {
        int stepIndex = (int) arguments.size();
        arguments.push_back(vector<int>());
        target.push_back((int) workspace.size());
        operation.push_back(node.getOperation().clone());
        if (args.size() == 0)
            arguments[stepIndex].push_back(0); // The value won't actually be used.  We just need something there.
        else {
            // If the arguments are sequential, we can just pass a pointer to the first one.

            bool sequential = true;
            for (int i = 1; i < args.size(); i++)
                if (args[i] != args[i-1]+1)
                    sequential = false;
            if (sequential)
                arguments[stepIndex].push_back(args[0]);
            else
                arguments[stepIndex] = args;
        }
    }
    temps.push_back(make_pair(node, (int) workspace.size()));
    workspace.push_back(0.0);
}

int CompiledExpression::findTempIndex(const ExpressionTreeNode& node, vector<pair<ExpressionTreeNode, int> >& temps) {
    for (int i = 0; i < (int) temps.size(); i++)
        if (temps[i].first == node)
            return i;
    return -1;
}

const set<string>& CompiledExpression::getVariables() const {
    return variableNames;
}

double& CompiledExpression::getVariableReference(const string& name) {
    map<string, int>::iterator index = variableIndices.find(name);
    if (index == variableIndices.end())
        throw Exception("getVariableReference: Unknown variable '"+name+"'");
    return workspace[index->second];
}

double CompiledExpression::evaluate() const {
#ifdef LEPTON_USE_JIT
    return ((double (*)()) jitCode)();
#else
    // Loop over the operations and evaluate each one.

    for (int step = 0; step < operation.size(); step++) {
        const vector<int>& args = arguments[step];
        if (args.size() == 1)
            workspace[target[step]] = operation[step]->evaluate(&workspace[args[0]], dummyVariables);
        else {
            for (int i = 0; i < args.size(); i++)
                argValues[i] = workspace[args[i]];
            workspace[target[step]] = operation[step]->evaluate(&argValues[0], dummyVariables);
        }
    }
    return workspace[workspace.size()-1];
#endif
}

#ifdef LEPTON_USE_JIT
static double evaluateOperation(Operation* op, double* args) {
    map<string, double>* dummyVariables = NULL;
    return op->evaluate(args, *dummyVariables);
}

void CompiledExpression::generateJitCode() {
    X86Compiler c(&runtime);
    c.addFunc(kFuncConvHost, FuncBuilder0<double>());
    vector<X86XmmVar> workspaceVar(workspace.size());
    for (int i = 0; i < (int) workspaceVar.size(); i++)
        workspaceVar[i] = c.newXmmVar(kX86VarTypeXmmSd);
    X86GpVar workspacePointer(c);
    X86GpVar argsPointer(c);
    c.mov(workspacePointer, imm_ptr(&workspace[0]));
    c.mov(argsPointer, imm_ptr(&argValues[0]));

    // Load the arguments into variables.

    for (set<string>::const_iterator iter = variableNames.begin(); iter != variableNames.end(); ++iter) {
        map<string, int>::iterator index = variableIndices.find(*iter);
        c.movsd(workspaceVar[index->second], x86::ptr(workspacePointer, 8*index->second, 0));
    }

    // Make a list of all constants that will be needed for evaluation.

    vector<int> operationConstantIndex(operation.size(), -1);
    for (int step = 0; step < (int) operation.size(); step++) {
        // Find the constant value (if any) used by this operation.

        Operation& op = *operation[step];
        double value;
        if (op.getId() == Operation::CONSTANT)
            value = dynamic_cast<Operation::Constant&>(op).getValue();
        else if (op.getId() == Operation::ADD_CONSTANT)
            value = dynamic_cast<Operation::AddConstant&>(op).getValue();
        else if (op.getId() == Operation::MULTIPLY_CONSTANT)
            value = dynamic_cast<Operation::MultiplyConstant&>(op).getValue();
        else if (op.getId() == Operation::RECIPROCAL)
            value = 1.0;
        else if (op.getId() == Operation::STEP)
            value = 1.0;
        else if (op.getId() == Operation::DELTA)
            value = 1.0;
        else
            continue;

        // See if we already have a variable for this constant.

        for (int i = 0; i < (int) constants.size(); i++)
            if (value == constants[i]) {
                operationConstantIndex[step] = i;
                break;
            }
        if (operationConstantIndex[step] == -1) {
            operationConstantIndex[step] = constants.size();
            constants.push_back(value);
        }
    }

    // Load constants into variables.

    vector<X86XmmVar> constantVar(constants.size());
    if (constants.size() > 0) {
        X86GpVar constantsPointer(c);
        c.mov(constantsPointer, imm_ptr(&constants[0]));
        for (int i = 0; i < (int) constants.size(); i++) {
            constantVar[i] = c.newXmmVar(kX86VarTypeXmmSd);
            c.movsd(constantVar[i], x86::ptr(constantsPointer, 8*i, 0));
        }
    }

    // Evaluate the operations.

    for (int step = 0; step < (int) operation.size(); step++) {
        Operation& op = *operation[step];
        vector<int> args = arguments[step];
        if (args.size() == 1) {
            // One or more sequential arguments.  Fill out the list.

            for (int i = 1; i < op.getNumArguments(); i++)
                args.push_back(args[0]+i);
        }

        // Generate instructions to execute this operation.

        switch (op.getId()) {
            case Operation::CONSTANT:
                c.movsd(workspaceVar[target[step]], constantVar[operationConstantIndex[step]]);
                break;
            case Operation::ADD:
                c.movsd(workspaceVar[target[step]], workspaceVar[args[0]]);
                c.addsd(workspaceVar[target[step]], workspaceVar[args[1]]);
                break;
            case Operation::SUBTRACT:
                c.movsd(workspaceVar[target[step]], workspaceVar[args[0]]);
                c.subsd(workspaceVar[target[step]], workspaceVar[args[1]]);
                break;
            case Operation::MULTIPLY:
                c.movsd(workspaceVar[target[step]], workspaceVar[args[0]]);
                c.mulsd(workspaceVar[target[step]], workspaceVar[args[1]]);
                break;
            case Operation::DIVIDE:
                c.movsd(workspaceVar[target[step]], workspaceVar[args[0]]);
                c.divsd(workspaceVar[target[step]], workspaceVar[args[1]]);
                break;
            case Operation::NEGATE:
                c.xorps(workspaceVar[target[step]], workspaceVar[target[step]]);
                c.subsd(workspaceVar[target[step]], workspaceVar[args[0]]);
                break;
            case Operation::SQRT:
                c.sqrtsd(workspaceVar[target[step]], workspaceVar[args[0]]);
                break;
            case Operation::EXP:
                generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], exp);
                break;
            case Operation::LOG:
                generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], log);
                break;
            case Operation::SIN:
                generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], sin);
                break;
            case Operation::COS:
                generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], cos);
                break;
            case Operation::TAN:
                generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], tan);
                break;
            case Operation::ASIN:
                generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], asin);
                break;
            case Operation::ACOS:
                generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], acos);
                break;
            case Operation::ATAN:
                generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], atan);
                break;
            case Operation::SINH:
                generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], sinh);
                break;
            case Operation::COSH:
                generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], cosh);
                break;
            case Operation::TANH:
                generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], tanh);
                break;
            case Operation::STEP:
                c.xorps(workspaceVar[target[step]], workspaceVar[target[step]]);
                c.cmpsd(workspaceVar[target[step]], workspaceVar[args[0]], imm(18)); // Comparison mode is _CMP_LE_OQ = 18
                c.andps(workspaceVar[target[step]], constantVar[operationConstantIndex[step]]);
                break;
            case Operation::DELTA:
                c.xorps(workspaceVar[target[step]], workspaceVar[target[step]]);
                c.cmpsd(workspaceVar[target[step]], workspaceVar[args[0]], imm(16)); // Comparison mode is _CMP_EQ_OS = 16
                c.andps(workspaceVar[target[step]], constantVar[operationConstantIndex[step]]);
                break;
            case Operation::SQUARE:
                c.movsd(workspaceVar[target[step]], workspaceVar[args[0]]);
                c.mulsd(workspaceVar[target[step]], workspaceVar[args[0]]);
                break;
            case Operation::CUBE:
                c.movsd(workspaceVar[target[step]], workspaceVar[args[0]]);
                c.mulsd(workspaceVar[target[step]], workspaceVar[args[0]]);
                c.mulsd(workspaceVar[target[step]], workspaceVar[args[0]]);
                break;
            case Operation::RECIPROCAL:
                c.movsd(workspaceVar[target[step]], constantVar[operationConstantIndex[step]]);
                c.divsd(workspaceVar[target[step]], workspaceVar[args[0]]);
                break;
            case Operation::ADD_CONSTANT:
                c.movsd(workspaceVar[target[step]], workspaceVar[args[0]]);
                c.addsd(workspaceVar[target[step]], constantVar[operationConstantIndex[step]]);
                break;
            case Operation::MULTIPLY_CONSTANT:
                c.movsd(workspaceVar[target[step]], workspaceVar[args[0]]);
                c.mulsd(workspaceVar[target[step]], constantVar[operationConstantIndex[step]]);
                break;
            case Operation::ABS:
                generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], fabs);
                break;
            default:
                // Just invoke evaluateOperation().

                for (int i = 0; i < (int) args.size(); i++)
                    c.movsd(x86::ptr(argsPointer, 8*i, 0), workspaceVar[args[i]]);
                X86GpVar fn(c, kVarTypeIntPtr);
                c.mov(fn, imm_ptr((void*) evaluateOperation));
                X86CallNode* call = c.call(fn, kFuncConvHost, FuncBuilder2<double, Operation*, double*>());
                call->setArg(0, imm_ptr(&op));
                call->setArg(1, imm_ptr(&argValues[0]));
                call->setRet(0, workspaceVar[target[step]]);
        }
    }
    c.ret(workspaceVar[workspace.size()-1]);
    c.endFunc();
    jitCode = c.make();
}

void CompiledExpression::generateSingleArgCall(X86Compiler& c, X86XmmVar& dest, X86XmmVar& arg, double (*function)(double)) {
    X86GpVar fn(c, kVarTypeIntPtr);
    c.mov(fn, imm_ptr((void*) function));
    X86CallNode* call = c.call(fn, kFuncConvHost, FuncBuilder1<double, double>());
    call->setArg(0, arg);
    call->setRet(0, dest);
}
#endif
<commit_msg>Signed unsigned comparison.<commit_after>/* -------------------------------------------------------------------------- *
 *                                   Lepton                                   *
 * -------------------------------------------------------------------------- *
 * This is part of the Lepton expression parser originating from              *
 * Simbios, the NIH National Center for Physics-Based Simulation of           *
 * Biological Structures at Stanford, funded under the NIH Roadmap for        *
 * Medical Research, grant U54 GM072970. See https://simtk.org.               *
 *                                                                            *
 * Portions copyright (c) 2013 Stanford University and the Authors.           *
 * Authors: Peter Eastman                                                     *
 * Contributors:                                                              *
 *                                                                            *
 * Permission is hereby granted, free of charge, to any person obtaining a    *
 * copy of this software and associated documentation files (the "Software"), *
 * to deal in the Software without restriction, including without limitation  *
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,   *
 * and/or sell copies of the Software, and to permit persons to whom the      *
 * Software is furnished to do so, subject to the following conditions:       *
 *                                                                            *
 * The above copyright notice and this permission notice shall be included in *
 * all copies or substantial portions of the Software.                        *
 *                                                                            *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,   *
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL    *
 * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,    *
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR      *
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE  *
 * USE OR OTHER DEALINGS IN THE SOFTWARE.                                     *
 * -------------------------------------------------------------------------- */

#include "lepton/CompiledExpression.h"
#include "lepton/Operation.h"
#include "lepton/ParsedExpression.h"
#include <utility>

using namespace Lepton;
using namespace std;
#ifdef LEPTON_USE_JIT
    using namespace asmjit;
#endif

CompiledExpression::CompiledExpression() : jitCode(NULL) {
}

CompiledExpression::CompiledExpression(const ParsedExpression& expression) : jitCode(NULL) {
    ParsedExpression expr = expression.optimize(); // Just in case it wasn't already optimized.
    vector<pair<ExpressionTreeNode, int> > temps;
    compileExpression(expr.getRootNode(), temps);
    int maxArguments = 1;
    for (int i = 0; i < (int) operation.size(); i++)
        if (operation[i]->getNumArguments() > maxArguments)
            maxArguments = operation[i]->getNumArguments();
    argValues.resize(maxArguments);
#ifdef LEPTON_USE_JIT
    generateJitCode();
#endif
}

CompiledExpression::~CompiledExpression() {
    for (int i = 0; i < (int) operation.size(); i++)
        if (operation[i] != NULL)
            delete operation[i];
}

CompiledExpression::CompiledExpression(const CompiledExpression& expression) : jitCode(NULL) {
    *this = expression;
}

CompiledExpression& CompiledExpression::operator=(const CompiledExpression& expression) {
    arguments = expression.arguments;
    target = expression.target;
    variableIndices = expression.variableIndices;
    variableNames = expression.variableNames;
    workspace.resize(expression.workspace.size());
    argValues.resize(expression.argValues.size());
    operation.resize(expression.operation.size());
    for (int i = 0; i < (int) operation.size(); i++)
        operation[i] = expression.operation[i]->clone();
#ifdef LEPTON_USE_JIT
    generateJitCode();
#endif
    return *this;
}

void CompiledExpression::compileExpression(const ExpressionTreeNode& node, vector<pair<ExpressionTreeNode, int> >& temps) {
    if (findTempIndex(node, temps) != -1)
        return; // We have already processed a node identical to this one.

    // Process the child nodes.

    vector<int> args;
    for (size_t i = 0; i < node.getChildren().size(); i++) {
        compileExpression(node.getChildren()[i], temps);
        args.push_back(findTempIndex(node.getChildren()[i], temps));
    }

    // Process this node.

    if (node.getOperation().getId() == Operation::VARIABLE) {
        variableIndices[node.getOperation().getName()] = (int) workspace.size();
        variableNames.insert(node.getOperation().getName());
    }
    else {
        int stepIndex = (int) arguments.size();
        arguments.push_back(vector<int>());
        target.push_back((int) workspace.size());
        operation.push_back(node.getOperation().clone());
        if (args.size() == 0)
            arguments[stepIndex].push_back(0); // The value won't actually be used.  We just need something there.
        else {
            // If the arguments are sequential, we can just pass a pointer to the first one.

            bool sequential = true;
            for (size_t i = 1; i < args.size(); i++)
                if (args[i] != args[i-1]+1)
                    sequential = false;
            if (sequential)
                arguments[stepIndex].push_back(args[0]);
            else
                arguments[stepIndex] = args;
        }
    }
    temps.push_back(make_pair(node, (int) workspace.size()));
    workspace.push_back(0.0);
}

int CompiledExpression::findTempIndex(const ExpressionTreeNode& node, vector<pair<ExpressionTreeNode, int> >& temps) {
    for (int i = 0; i < (int) temps.size(); i++)
        if (temps[i].first == node)
            return i;
    return -1;
}

const set<string>& CompiledExpression::getVariables() const {
    return variableNames;
}

double& CompiledExpression::getVariableReference(const string& name) {
    map<string, int>::iterator index = variableIndices.find(name);
    if (index == variableIndices.end())
        throw Exception("getVariableReference: Unknown variable '"+name+"'");
    return workspace[index->second];
}

double CompiledExpression::evaluate() const {
#ifdef LEPTON_USE_JIT
    return ((double (*)()) jitCode)();
#else
    // Loop over the operations and evaluate each one.

    for (size_t step = 0; step < operation.size(); step++) {
        const vector<int>& args = arguments[step];
        if (args.size() == 1)
            workspace[target[step]] = operation[step]->evaluate(&workspace[args[0]], dummyVariables);
        else {
            for (size_t i = 0; i < args.size(); i++)
                argValues[i] = workspace[args[i]];
            workspace[target[step]] = operation[step]->evaluate(&argValues[0], dummyVariables);
        }
    }
    return workspace[workspace.size()-1];
#endif
}

#ifdef LEPTON_USE_JIT
static double evaluateOperation(Operation* op, double* args) {
    map<string, double>* dummyVariables = NULL;
    return op->evaluate(args, *dummyVariables);
}

void CompiledExpression::generateJitCode() {
    X86Compiler c(&runtime);
    c.addFunc(kFuncConvHost, FuncBuilder0<double>());
    vector<X86XmmVar> workspaceVar(workspace.size());
    for (int i = 0; i < (int) workspaceVar.size(); i++)
        workspaceVar[i] = c.newXmmVar(kX86VarTypeXmmSd);
    X86GpVar workspacePointer(c);
    X86GpVar argsPointer(c);
    c.mov(workspacePointer, imm_ptr(&workspace[0]));
    c.mov(argsPointer, imm_ptr(&argValues[0]));

    // Load the arguments into variables.

    for (set<string>::const_iterator iter = variableNames.begin(); iter != variableNames.end(); ++iter) {
        map<string, int>::iterator index = variableIndices.find(*iter);
        c.movsd(workspaceVar[index->second], x86::ptr(workspacePointer, 8*index->second, 0));
    }

    // Make a list of all constants that will be needed for evaluation.

    vector<int> operationConstantIndex(operation.size(), -1);
    for (int step = 0; step < (int) operation.size(); step++) {
        // Find the constant value (if any) used by this operation.

        Operation& op = *operation[step];
        double value;
        if (op.getId() == Operation::CONSTANT)
            value = dynamic_cast<Operation::Constant&>(op).getValue();
        else if (op.getId() == Operation::ADD_CONSTANT)
            value = dynamic_cast<Operation::AddConstant&>(op).getValue();
        else if (op.getId() == Operation::MULTIPLY_CONSTANT)
            value = dynamic_cast<Operation::MultiplyConstant&>(op).getValue();
        else if (op.getId() == Operation::RECIPROCAL)
            value = 1.0;
        else if (op.getId() == Operation::STEP)
            value = 1.0;
        else if (op.getId() == Operation::DELTA)
            value = 1.0;
        else
            continue;

        // See if we already have a variable for this constant.

        for (int i = 0; i < (int) constants.size(); i++)
            if (value == constants[i]) {
                operationConstantIndex[step] = i;
                break;
            }
        if (operationConstantIndex[step] == -1) {
            operationConstantIndex[step] = constants.size();
            constants.push_back(value);
        }
    }

    // Load constants into variables.

    vector<X86XmmVar> constantVar(constants.size());
    if (constants.size() > 0) {
        X86GpVar constantsPointer(c);
        c.mov(constantsPointer, imm_ptr(&constants[0]));
        for (int i = 0; i < (int) constants.size(); i++) {
            constantVar[i] = c.newXmmVar(kX86VarTypeXmmSd);
            c.movsd(constantVar[i], x86::ptr(constantsPointer, 8*i, 0));
        }
    }

    // Evaluate the operations.

    for (int step = 0; step < (int) operation.size(); step++) {
        Operation& op = *operation[step];
        vector<int> args = arguments[step];
        if (args.size() == 1) {
            // One or more sequential arguments.  Fill out the list.

            for (int i = 1; i < op.getNumArguments(); i++)
                args.push_back(args[0]+i);
        }

        // Generate instructions to execute this operation.

        switch (op.getId()) {
            case Operation::CONSTANT:
                c.movsd(workspaceVar[target[step]], constantVar[operationConstantIndex[step]]);
                break;
            case Operation::ADD:
                c.movsd(workspaceVar[target[step]], workspaceVar[args[0]]);
                c.addsd(workspaceVar[target[step]], workspaceVar[args[1]]);
                break;
            case Operation::SUBTRACT:
                c.movsd(workspaceVar[target[step]], workspaceVar[args[0]]);
                c.subsd(workspaceVar[target[step]], workspaceVar[args[1]]);
                break;
            case Operation::MULTIPLY:
                c.movsd(workspaceVar[target[step]], workspaceVar[args[0]]);
                c.mulsd(workspaceVar[target[step]], workspaceVar[args[1]]);
                break;
            case Operation::DIVIDE:
                c.movsd(workspaceVar[target[step]], workspaceVar[args[0]]);
                c.divsd(workspaceVar[target[step]], workspaceVar[args[1]]);
                break;
            case Operation::NEGATE:
                c.xorps(workspaceVar[target[step]], workspaceVar[target[step]]);
                c.subsd(workspaceVar[target[step]], workspaceVar[args[0]]);
                break;
            case Operation::SQRT:
                c.sqrtsd(workspaceVar[target[step]], workspaceVar[args[0]]);
                break;
            case Operation::EXP:
                generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], exp);
                break;
            case Operation::LOG:
                generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], log);
                break;
            case Operation::SIN:
                generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], sin);
                break;
            case Operation::COS:
                generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], cos);
                break;
            case Operation::TAN:
                generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], tan);
                break;
            case Operation::ASIN:
                generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], asin);
                break;
            case Operation::ACOS:
                generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], acos);
                break;
            case Operation::ATAN:
                generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], atan);
                break;
            case Operation::SINH:
                generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], sinh);
                break;
            case Operation::COSH:
                generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], cosh);
                break;
            case Operation::TANH:
                generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], tanh);
                break;
            case Operation::STEP:
                c.xorps(workspaceVar[target[step]], workspaceVar[target[step]]);
                c.cmpsd(workspaceVar[target[step]], workspaceVar[args[0]], imm(18)); // Comparison mode is _CMP_LE_OQ = 18
                c.andps(workspaceVar[target[step]], constantVar[operationConstantIndex[step]]);
                break;
            case Operation::DELTA:
                c.xorps(workspaceVar[target[step]], workspaceVar[target[step]]);
                c.cmpsd(workspaceVar[target[step]], workspaceVar[args[0]], imm(16)); // Comparison mode is _CMP_EQ_OS = 16
                c.andps(workspaceVar[target[step]], constantVar[operationConstantIndex[step]]);
                break;
            case Operation::SQUARE:
                c.movsd(workspaceVar[target[step]], workspaceVar[args[0]]);
                c.mulsd(workspaceVar[target[step]], workspaceVar[args[0]]);
                break;
            case Operation::CUBE:
                c.movsd(workspaceVar[target[step]], workspaceVar[args[0]]);
                c.mulsd(workspaceVar[target[step]], workspaceVar[args[0]]);
                c.mulsd(workspaceVar[target[step]], workspaceVar[args[0]]);
                break;
            case Operation::RECIPROCAL:
                c.movsd(workspaceVar[target[step]], constantVar[operationConstantIndex[step]]);
                c.divsd(workspaceVar[target[step]], workspaceVar[args[0]]);
                break;
            case Operation::ADD_CONSTANT:
                c.movsd(workspaceVar[target[step]], workspaceVar[args[0]]);
                c.addsd(workspaceVar[target[step]], constantVar[operationConstantIndex[step]]);
                break;
            case Operation::MULTIPLY_CONSTANT:
                c.movsd(workspaceVar[target[step]], workspaceVar[args[0]]);
                c.mulsd(workspaceVar[target[step]], constantVar[operationConstantIndex[step]]);
                break;
            case Operation::ABS:
                generateSingleArgCall(c, workspaceVar[target[step]], workspaceVar[args[0]], fabs);
                break;
            default:
                // Just invoke evaluateOperation().

                for (int i = 0; i < (int) args.size(); i++)
                    c.movsd(x86::ptr(argsPointer, 8*i, 0), workspaceVar[args[i]]);
                X86GpVar fn(c, kVarTypeIntPtr);
                c.mov(fn, imm_ptr((void*) evaluateOperation));
                X86CallNode* call = c.call(fn, kFuncConvHost, FuncBuilder2<double, Operation*, double*>());
                call->setArg(0, imm_ptr(&op));
                call->setArg(1, imm_ptr(&argValues[0]));
                call->setRet(0, workspaceVar[target[step]]);
        }
    }
    c.ret(workspaceVar[workspace.size()-1]);
    c.endFunc();
    jitCode = c.make();
}

void CompiledExpression::generateSingleArgCall(X86Compiler& c, X86XmmVar& dest, X86XmmVar& arg, double (*function)(double)) {
    X86GpVar fn(c, kVarTypeIntPtr);
    c.mov(fn, imm_ptr((void*) function));
    X86CallNode* call = c.call(fn, kFuncConvHost, FuncBuilder1<double, double>());
    call->setArg(0, arg);
    call->setRet(0, dest);
}
#endif
<|endoftext|>