<commit_before>#include "CommonFunctions.h"

// open sqlite db and return it as the db object i need
sqlite3* OpenSqliteDB()
{
	char*		sqlErrMsg;
	int			sqlValue;
	sqlite3* 	opendb;
	BString		tmpString;
	ErrorAlert*	eAlert;

	sqlErrMsg = 0;
	opendb = NULL;
	app_info info;
	be_app->GetAppInfo(&info);
	BPath path(&info.ref);
	path.GetParent(&path);
	BString tmpPath = path.Path();
	tmpPath += "/MasterPiece.db";
	sqlValue = sqlite3_open_v2(tmpPath, &opendb, SQLITE_OPEN_READWRITE, NULL); // open db
	if(sqlite3_errcode(opendb) == 14) // if error is SQLITE_CANTOPEN, then create db with structure
	{
		sqlValue = sqlite3_open_v2(tmpPath, &opendb, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
		if(sqlite3_errcode(opendb) == 0) // sqlite_ok
		{
			tmpString = "CREATE TABLE ideatable(ideaid integer primary key autoincrement, ideaname text, ideatext text, ismp integer, mpid integer, ordernumber integer);";
			sqlValue = sqlite3_exec(opendb, tmpString, NULL, NULL, &sqlErrMsg);
			if(sqlValue == SQLITE_OK) // if sql was successful
			{
				// no error, so i will return opendb at end;
			}
			else // sql not successful
			{
				eAlert = new ErrorAlert("1.1 Sql Error: ", sqlErrMsg);
				eAlert->Launch();
			}
		}
		else // some kind of failure
		{
			eAlert = new ErrorAlert("1.0 Sql Error: ", sqlite3_errmsg(opendb));
			eAlert->Launch();
		}
	}
	else if(sqlite3_errcode(opendb) == 0) // sqlite_OK, it exists
	{
		//no error, so i will return opendb at end;
	}
	else // if error is not ok or not existing, then display error in alert
	{
		eAlert = new ErrorAlert("1.2 Sql Error: ", sqlite3_errmsg(opendb));
		eAlert->Launch();
	}
	return opendb;
}
int PrepareSql(sqlite3* tmpdb, const char* sqlquery, sqlite3_stmt** tmpstatement, const char* errornumber, int tmpint=-1, const char** unused=NULL)
{
	ErrorAlert* eAlert;
	BString		tmpString;
	int			tmpReturn;

	tmpReturn = sqlite3_prepare_v2(tmpdb, sqlquery, tmpint, tmpstatement, unused);
	//int tmpReturn =
	// if else for prepare_v2 statement... automate error statements with # string input in functions
	return 1;
}
<commit_msg>working on function<commit_after>#include "CommonFunctions.h"

// open sqlite db and return it as the db object i need
sqlite3* OpenSqliteDB()
{
	char*		sqlErrMsg;
	int			sqlValue;
	sqlite3* 	opendb;
	BString		tmpString;
	ErrorAlert*	eAlert;

	sqlErrMsg = 0;
	opendb = NULL;
	app_info info;
	be_app->GetAppInfo(&info);
	BPath path(&info.ref);
	path.GetParent(&path);
	BString tmpPath = path.Path();
	tmpPath += "/MasterPiece.db";
	sqlValue = sqlite3_open_v2(tmpPath, &opendb, SQLITE_OPEN_READWRITE, NULL); // open db
	if(sqlite3_errcode(opendb) == 14) // if error is SQLITE_CANTOPEN, then create db with structure
	{
		sqlValue = sqlite3_open_v2(tmpPath, &opendb, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
		if(sqlite3_errcode(opendb) == 0) // sqlite_ok
		{
			tmpString = "CREATE TABLE ideatable(ideaid integer primary key autoincrement, ideaname text, ideatext text, ismp integer, mpid integer, ordernumber integer);";
			sqlValue = sqlite3_exec(opendb, tmpString, NULL, NULL, &sqlErrMsg);
			if(sqlValue == SQLITE_OK) // if sql was successful
			{
				// no error, so i will return opendb at end;
			}
			else // sql not successful
			{
				eAlert = new ErrorAlert("1.1 Sql Error: ", sqlErrMsg);
				eAlert->Launch();
			}
		}
		else // some kind of failure
		{
			eAlert = new ErrorAlert("1.0 Sql Error: ", sqlite3_errmsg(opendb));
			eAlert->Launch();
		}
	}
	else if(sqlite3_errcode(opendb) == 0) // sqlite_OK, it exists
	{
		//no error, so i will return opendb at end;
	}
	else // if error is not ok or not existing, then display error in alert
	{
		eAlert = new ErrorAlert("1.2 Sql Error: ", sqlite3_errmsg(opendb));
		eAlert->Launch();
	}
	return opendb;
}
int PrepareSql(sqlite3* tmpdb, const char* sqlquery, sqlite3_stmt** tmpstatement, const char* errornumber, int tmpint=-1, const char** unused=NULL)
{
	ErrorAlert* eAlert;
	BString		tmpString;
	int			tmpReturn;

	tmpReturn = sqlite3_prepare_v2(tmpdb, sqlquery, tmpint, tmpstatement, unused);
	if(tmpReturn == SQLITE_OK) // sql statement was prepared
	{
		return SQLITE_OK;
	}
	else
	{
		tmpString = errornumber;
		tmpString += " Sql Error: Prepare Statement Failed";
		eAlert = new ErrorAlert(tmpString);
		eAlert->Launch();
		return -15;
	}
	//int tmpReturn =
	// if else for prepare_v2 statement... automate error statements with # string input in functions
	return 1;
}
<|endoftext|>


<commit_before>/// Implementation for entity

#include <AFP/Entity/Entity.hpp>
#include <iostream>

/// Constructor
AFP::Entity::Entity(int hitpoints):
    mBody(), mHitpoints(hitpoints)
{
}

/// Set velocity of mBody
void AFP::Entity::setVelocity(b2Vec2 velocity)
{
    mBody->SetLinearVelocity(velocity);
}

/// Set position in world
void AFP::Entity::setBodyPosition(b2Vec2 target)
{
    target.x /= AFP::PTM_RATIO;
    target.y /= AFP::PTM_RATIO;
    mBody->SetTransform(target, 0);
    mBody->SetAwake(true);
}

/// Applies impulse to mBody
void AFP::Entity::applyImpulse(b2Vec2 impulse)
{
    mBody->ApplyLinearImpulse(impulse, mBody->GetWorldCenter() );
}

/// Applies force to mBody
void AFP::Entity::applyForce(b2Vec2 force)
{
    mBody->ApplyForce(force, mBody->GetWorldCenter());
}

/// Return velocty of mBody
b2Vec2 AFP::Entity::getVelocity() const
{
    return mBody->GetLinearVelocity();
}

/// Return mass of mBody
float AFP::Entity::getMass() const
{
    return mBody->GetMass();
}

/// Convert position to pixels
sf::Vector2f AFP::Entity::getPosition() const
{
    if ( mBody == NULL ) {
        return sf::Vector2f(0.f, 0.f);
    }

    sf::Vector2f getPos;
    b2Vec2 position = mBody->GetPosition();

    /// Calculate positions and invert y axis.
    /// 1 meter = 16 pixels
    getPos.x = position.x * AFP::PTM_RATIO;
    getPos.y = position.y * AFP::PTM_RATIO;

    return getPos;
}

/// Return body position in meters
b2Vec2 AFP::Entity::getBodyPosition() const
{
    return mBody->GetPosition();

}

/// Return pointer to world
b2World* AFP::Entity::getWorld() const
{
    return mBody->GetWorld();

}

/// Return entity hitpoints
int AFP::Entity::getHitpoints() const
{
    return mHitpoints;

}

/// Create body
void AFP::Entity::createBody(b2World* world, float posX, float posY,
                             float sizeX, float sizeY, float density,
                             float friction)
{

    b2BodyDef bodyDef;
    b2PolygonShape dynamicBox;
    b2FixtureDef fixtureDef;

    // Create body based on category
    if (getCategory() & Category::Character)
    {
        bodyDef.type = b2_dynamicBody;
        bodyDef.fixedRotation = true;
    }

    if (getCategory() & Category::Scene)
    {
        bodyDef.type = b2_staticBody;
    }

    if (getCategory() & Category::Projectile)
    {
        bodyDef.type = b2_dynamicBody;
        bodyDef.bullet = true;
    }

    if (getCategory() & Category::Collectable)
    {
        fixtureDef.isSensor = true;
    }

    /// Convert to meters
    posX /= AFP::PTM_RATIO;
    posY /= AFP::PTM_RATIO;

    bodyDef.position.Set(posX, posY);
    mBody = world->CreateBody(&bodyDef);

    /// Set this entity in the body's user data
    mBody->SetUserData(this);

    dynamicBox.SetAsBox(sizeX / 2.f, sizeY / 2.f);

    fixtureDef.shape = &dynamicBox;
    fixtureDef.density = density;
    fixtureDef.friction = friction;

    mBody->CreateFixture(&fixtureDef);

}

void AFP::Entity::createHead(b2World* world)
{
    b2BodyDef bodyDef;
    b2CircleShape circleShape;
    b2FixtureDef fixtureDef;

    bodyDef.type = b2_dynamicBody;
    bodyDef.fixedRotation = false;
    bodyDef.position.Set(mBody->GetPosition().x, mBody->GetPosition().y);
    mHead = world->CreateBody(&bodyDef);

    circleShape.m_radius = 0.5f;

    fixtureDef.shape = &circleShape;

    mHead->CreateFixture(&fixtureDef);

    b2RevoluteJointDef jointDef;
    jointDef.bodyA = mBody;
    jointDef.bodyB = mHead;

    jointDef.collideConnected = false;

    mJoint = (b2RevoluteJoint*)world->CreateJoint(&jointDef);

    // Rotate head
    mHead->SetAngularVelocity(1.0f);
}

b2Fixture* AFP::Entity::attachSensorToBody(const b2FixtureDef* sensor)
{
    return mBody->CreateFixture(sensor);
}

b2Fixture* AFP::Entity::attachSensorToHead(const b2FixtureDef* sensor)
{
    return mHead->CreateFixture(sensor);
}

/// Decreases hitpoints
void AFP::Entity::damage(int points)
{
    assert(points > 0);

    mHitpoints -= points;

}

/// Increases hitpoints
void AFP::Entity::heal(int points)
{
    assert(points > 0);

    mHitpoints += points;
}

/// Destroy entity
void AFP::Entity::destroy()
{
    mHitpoints= 0;

}

/// Returns true if hitpoints are below or equal to zero
bool AFP::Entity::isDestroyed() const
{
    return mHitpoints <= 0;

}

/// Destroy body
void AFP::Entity::destroyBody()
{
    mBody->SetUserData(nullptr);
    mBody->GetWorld()->DestroyBody(mBody);
}

/// Update entity
void AFP::Entity::updateCurrent(sf::Time, CommandQueue&)
{
    /// Set position of entity
    sf::Vector2f position = getPosition();
    position -= getParentPosition();
    setPosition(position);

}
<commit_msg>Minor fixes to entity.<commit_after>/// Implementation for entity

#include <AFP/Entity/Entity.hpp>
#include <iostream>

/// Constructor
AFP::Entity::Entity(int hitpoints):
    mBody(nullptr), mHead(nullptr), mJoint(nullptr), mHitpoints(hitpoints)
{
}

/// Set velocity of mBody
void AFP::Entity::setVelocity(b2Vec2 velocity)
{
    mBody->SetLinearVelocity(velocity);
}

/// Set position in world
void AFP::Entity::setBodyPosition(b2Vec2 target)
{
    target.x /= AFP::PTM_RATIO;
    target.y /= AFP::PTM_RATIO;
    mBody->SetTransform(target, 0);
    mBody->SetAwake(true);
}

/// Applies impulse to mBody
void AFP::Entity::applyImpulse(b2Vec2 impulse)
{
    mBody->ApplyLinearImpulse(impulse, mBody->GetWorldCenter() );
}

/// Applies force to mBody
void AFP::Entity::applyForce(b2Vec2 force)
{
    mBody->ApplyForce(force, mBody->GetWorldCenter());
}

/// Return velocty of mBody
b2Vec2 AFP::Entity::getVelocity() const
{
    return mBody->GetLinearVelocity();
}

/// Return mass of mBody
float AFP::Entity::getMass() const
{
    return mBody->GetMass();
}

/// Convert position to pixels
sf::Vector2f AFP::Entity::getPosition() const
{
    if ( mBody == NULL ) {
        return sf::Vector2f(0.f, 0.f);
    }

    sf::Vector2f getPos;
    b2Vec2 position = mBody->GetPosition();

    /// Calculate positions and invert y axis.
    /// 1 meter = 16 pixels
    getPos.x = position.x * AFP::PTM_RATIO;
    getPos.y = position.y * AFP::PTM_RATIO;

    return getPos;
}

/// Return body position in meters
b2Vec2 AFP::Entity::getBodyPosition() const
{
    return mBody->GetPosition();

}

/// Return pointer to world
b2World* AFP::Entity::getWorld() const
{
    return mBody->GetWorld();

}

/// Return entity hitpoints
int AFP::Entity::getHitpoints() const
{
    return mHitpoints;

}

/// Create body
void AFP::Entity::createBody(b2World* world, float posX, float posY,
                             float sizeX, float sizeY, float density,
                             float friction)
{

    b2BodyDef bodyDef;
    b2PolygonShape dynamicBox;
    b2FixtureDef fixtureDef;

    // Create body based on category
    if (getCategory() & Category::Character)
    {
        bodyDef.type = b2_dynamicBody;
        bodyDef.fixedRotation = true;
    }

    if (getCategory() & Category::Scene)
    {
        bodyDef.type = b2_staticBody;
    }

    if (getCategory() & Category::Projectile)
    {
        bodyDef.type = b2_dynamicBody;
        bodyDef.bullet = true;
    }

    if (getCategory() & Category::Collectable)
    {
        fixtureDef.isSensor = true;
    }

    /// Convert to meters
    posX /= AFP::PTM_RATIO;
    posY /= AFP::PTM_RATIO;

    bodyDef.position.Set(posX, posY);
    mBody = world->CreateBody(&bodyDef);

    /// Set this entity in the body's user data
    mBody->SetUserData(this);

    dynamicBox.SetAsBox(sizeX / 2.f, sizeY / 2.f);

    fixtureDef.shape = &dynamicBox;
    fixtureDef.density = density;
    fixtureDef.friction = friction;

    mBody->CreateFixture(&fixtureDef);

}

void AFP::Entity::createHead(b2World* world)
{
    b2BodyDef bodyDef;
    b2CircleShape circleShape;
    b2FixtureDef fixtureDef;

    bodyDef.type = b2_dynamicBody;
    bodyDef.fixedRotation = false;
    bodyDef.position.Set(mBody->GetPosition().x, mBody->GetPosition().y);
    mHead = world->CreateBody(&bodyDef);

    circleShape.m_radius = 0.5f;

    fixtureDef.shape = &circleShape;

    mHead->CreateFixture(&fixtureDef);

    b2RevoluteJointDef jointDef;
    jointDef.bodyA = mBody;
    jointDef.bodyB = mHead;

    jointDef.collideConnected = false;

    mJoint = (b2RevoluteJoint*)world->CreateJoint(&jointDef);

    // Rotate head
    mHead->SetAngularVelocity(1.0f);
}

b2Fixture* AFP::Entity::attachSensorToBody(const b2FixtureDef* sensor)
{
    return mBody->CreateFixture(sensor);
}

b2Fixture* AFP::Entity::attachSensorToHead(const b2FixtureDef* sensor)
{
    return mHead->CreateFixture(sensor);
}

/// Decreases hitpoints
void AFP::Entity::damage(int points)
{
    assert(points > 0);

    mHitpoints -= points;

}

/// Increases hitpoints
void AFP::Entity::heal(int points)
{
    assert(points > 0);

    mHitpoints += points;
}

/// Destroy entity
void AFP::Entity::destroy()
{
    mHitpoints= 0;

}

/// Returns true if hitpoints are below or equal to zero
bool AFP::Entity::isDestroyed() const
{
    return mHitpoints <= 0;

}

/// Destroy body
void AFP::Entity::destroyBody()
{
    mBody->SetUserData(nullptr);

    if(mHead != nullptr)
    {
        mHead->GetWorld()->DestroyJoint(mJoint);
        mHead->GetWorld()->DestroyBody(mHead);
    }

    mBody->GetWorld()->DestroyBody(mBody);
}

/// Update entity
void AFP::Entity::updateCurrent(sf::Time, CommandQueue&)
{
    /// Set position of entity
    sf::Vector2f position = getPosition();
    position -= getParentPosition();
    setPosition(position);

}
<|endoftext|>


<commit_before>//
// Copyright 2016 Google Inc.
//
// 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 "FirebaseArduino.h"

// This is needed to compile std::string on esp8266.
template class std::basic_string<char>;

void FirebaseArduino::begin(const String& host, const String& auth) {
  host_ = host.c_str();
  auth_ = auth.c_str();
}

void FirebaseArduino::initStream() {
  stream_http_.reset(FirebaseHttpClient::create());
  stream_http_->setReuseConnection(true);
  stream_.reset(new FirebaseStream(stream_http_));
}

void FirebaseArduino::initRequest() {
  req_http_.reset(FirebaseHttpClient::create());
  req_http_->setReuseConnection(true);
  req_.reset(new FirebaseRequest(req_http_));
}

String FirebaseArduino::pushInt(const String& path, int value) {
  return push(path, value);
}

String FirebaseArduino::pushFloat(const String& path, float value) {
  return push(path, value);
}

String FirebaseArduino::pushBool(const String& path, bool value) {
  return push(path, value);
}

String FirebaseArduino::pushString(const String& path, const String& value) {
  JsonVariant json(value.c_str());
  return push(path, json);
}

String FirebaseArduino::push(const String& path, const JsonVariant& value) {
  String buf;
  value.printTo(buf);
  initRequest();
  int status = req_.get()->sendRequest(host_, auth_, "POST", path.c_str(), buf.c_str());
  error_ = req_.get()->error();
  const char* name = req_.get()->json()["name"].as<const char*>();
  return name;
}

void FirebaseArduino::setInt(const String& path, int value) {
  set(path, value);
}

void FirebaseArduino::setFloat(const String& path, float value) {
  set(path, value);
}

void FirebaseArduino::setBool(const String& path, bool value) {
  set(path, value);
}

void FirebaseArduino::setString(const String& path, const String& value) {
  JsonVariant json(value.c_str());
  set(path, json);
}

void FirebaseArduino::set(const String& path, const JsonVariant& value) {
  String buf;
  value.printTo(buf);
  initRequest();
  req_.get()->sendRequest(host_, auth_, "PUT", path.c_str(), buf.c_str());
  error_ = req_.get()->error();
}

void FirebaseArduino::getRequest(const String& path) {
  initRequest();
  req_.get()->sendRequest(host_, auth_, "GET", path.c_str());
  error_ = req_.get()->error();
}

FirebaseObject FirebaseArduino::get(const String& path) {
  getRequest(path);
  if (failed()) {
    return FirebaseObject{""};
  }
  return FirebaseObject(req_.get()->response().c_str());
}

int FirebaseArduino::getInt(const String& path) {
  getRequest(path);
  if (failed()) {
    return 0;
  }
  return FirebaseObject(req_.get()->response().c_str()).getInt();
}

float FirebaseArduino::getFloat(const String& path) {
  getRequest(path);
  if (failed()) {
    return 0.0f;
  }
  return FirebaseObject(req_.get()->response().c_str()).getFloat();
}

String FirebaseArduino::getString(const String& path) {
  getRequest(path);
  if (failed()) {
    return "";
  }
  return FirebaseObject(req_.get()->response().c_str()).getString();
}

bool FirebaseArduino::getBool(const String& path) {
  getRequest(path);
  if (failed()) {
    return "";
  }
  return FirebaseObject(req_.get()->response().c_str()).getBool();
}
void FirebaseArduino::remove(const String& path) {
  initRequest();
  req_.get()->sendRequest(host_, auth_, "DELETE", path.c_str());
  error_ = req_.get()->error();
}

void FirebaseArduino::stream(const String& path) {
  initStream();
  stream_.get()->startStreaming(host_, auth_, path.c_str());
  error_ = stream_.get()->error();
}

bool FirebaseArduino::available() {
  if (stream_http_.get() == nullptr) {
    return 0;
  }
  auto client = stream_http_.get()->getStreamPtr();
  return (client == nullptr) ? false : client->available();
}

FirebaseObject FirebaseArduino::readEvent() {
  if (stream_http_.get() == nullptr) {
    return FirebaseObject("");
  }
  auto client = stream_http_.get()->getStreamPtr();
  if (client == nullptr) {
      return FirebaseObject("");
  }
  String type = client->readStringUntil('\n').substring(7);;
  String event = client->readStringUntil('\n').substring(6);
  client->readStringUntil('\n'); // consume separator
  FirebaseObject obj = FirebaseObject(event.c_str());
  obj.getJsonVariant().asObject()["type"] = type;
  return obj;
}

bool FirebaseArduino::success() {
  return error_.code() == 0;
}

bool FirebaseArduino::failed() {
  return error_.code() != 0;
}

const String& FirebaseArduino::error() {
  return error_.message().c_str();
}

FirebaseArduino Firebase;
<commit_msg>Fixing a problem with reusing same client.<commit_after>//
// Copyright 2016 Google Inc.
//
// 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 "FirebaseArduino.h"

// This is needed to compile std::string on esp8266.
template class std::basic_string<char>;

void FirebaseArduino::begin(const String& host, const String& auth) {
  host_ = host.c_str();
  auth_ = auth.c_str();
}

void FirebaseArduino::initStream() {
  if (stream_http_.get() == nullptr) {
    stream_http_.reset(FirebaseHttpClient::create());
    stream_http_->setReuseConnection(true);
    stream_.reset(new FirebaseStream(stream_http_));
  }
}

void FirebaseArduino::initRequest() {
  if (req_http_.get() == nullptr) {
    req_http_.reset(FirebaseHttpClient::create());
    req_http_->setReuseConnection(true);
    req_.reset(new FirebaseRequest(req_http_));
  }
}

String FirebaseArduino::pushInt(const String& path, int value) {
  return push(path, value);
}

String FirebaseArduino::pushFloat(const String& path, float value) {
  return push(path, value);
}

String FirebaseArduino::pushBool(const String& path, bool value) {
  return push(path, value);
}

String FirebaseArduino::pushString(const String& path, const String& value) {
  JsonVariant json(value.c_str());
  return push(path, json);
}

String FirebaseArduino::push(const String& path, const JsonVariant& value) {
  String buf;
  value.printTo(buf);
  initRequest();
  int status = req_.get()->sendRequest(host_, auth_, "POST", path.c_str(), buf.c_str());
  error_ = req_.get()->error();
  const char* name = req_.get()->json()["name"].as<const char*>();
  return name;
}

void FirebaseArduino::setInt(const String& path, int value) {
  set(path, value);
}

void FirebaseArduino::setFloat(const String& path, float value) {
  set(path, value);
}

void FirebaseArduino::setBool(const String& path, bool value) {
  set(path, value);
}

void FirebaseArduino::setString(const String& path, const String& value) {
  JsonVariant json(value.c_str());
  set(path, json);
}

void FirebaseArduino::set(const String& path, const JsonVariant& value) {
  String buf;
  value.printTo(buf);
  initRequest();
  req_.get()->sendRequest(host_, auth_, "PUT", path.c_str(), buf.c_str());
  error_ = req_.get()->error();
}

void FirebaseArduino::getRequest(const String& path) {
  initRequest();
  req_.get()->sendRequest(host_, auth_, "GET", path.c_str());
  error_ = req_.get()->error();
}

FirebaseObject FirebaseArduino::get(const String& path) {
  getRequest(path);
  if (failed()) {
    return FirebaseObject{""};
  }
  return FirebaseObject(req_.get()->response().c_str());
}

int FirebaseArduino::getInt(const String& path) {
  getRequest(path);
  if (failed()) {
    return 0;
  }
  return FirebaseObject(req_.get()->response().c_str()).getInt();
}

float FirebaseArduino::getFloat(const String& path) {
  getRequest(path);
  if (failed()) {
    return 0.0f;
  }
  return FirebaseObject(req_.get()->response().c_str()).getFloat();
}

String FirebaseArduino::getString(const String& path) {
  getRequest(path);
  if (failed()) {
    return "";
  }
  return FirebaseObject(req_.get()->response().c_str()).getString();
}

bool FirebaseArduino::getBool(const String& path) {
  getRequest(path);
  if (failed()) {
    return "";
  }
  return FirebaseObject(req_.get()->response().c_str()).getBool();
}
void FirebaseArduino::remove(const String& path) {
  initRequest();
  req_.get()->sendRequest(host_, auth_, "DELETE", path.c_str());
  error_ = req_.get()->error();
}

void FirebaseArduino::stream(const String& path) {
  initStream();
  stream_.get()->startStreaming(host_, auth_, path.c_str());
  error_ = stream_.get()->error();
}

bool FirebaseArduino::available() {
  if (stream_http_.get() == nullptr) {
    return 0;
  }
  auto client = stream_http_.get()->getStreamPtr();
  return (client == nullptr) ? false : client->available();
}

FirebaseObject FirebaseArduino::readEvent() {
  if (stream_http_.get() == nullptr) {
    return FirebaseObject("");
  }
  auto client = stream_http_.get()->getStreamPtr();
  if (client == nullptr) {
      return FirebaseObject("");
  }
  String type = client->readStringUntil('\n').substring(7);;
  String event = client->readStringUntil('\n').substring(6);
  client->readStringUntil('\n'); // consume separator
  FirebaseObject obj = FirebaseObject(event.c_str());
  obj.getJsonVariant().asObject()["type"] = type;
  return obj;
}

bool FirebaseArduino::success() {
  return error_.code() == 0;
}

bool FirebaseArduino::failed() {
  return error_.code() != 0;
}

const String& FirebaseArduino::error() {
  return error_.message().c_str();
}

FirebaseArduino Firebase;
<|endoftext|>


<commit_before>
//@HEADER
// ************************************************************************
//
//               HPCG: Simple Conjugate Gradient Benchmark Code
// Questions? Contact Michael A. Heroux (maherou@sandia.gov)
//
// ************************************************************************
//@HEADER

/////////////////////////////////////////////////////////////////////////

// Routine to read a sparse matrix, right hand side, initial guess,
// and exact solution (as computed by a direct solver).

/////////////////////////////////////////////////////////////////////////

#if defined(DEBUG) || defined(DETAILEDDEBUG)
#include <iostream>
using std::cout;
using std::cerr;
using std::endl;
#include <cstdlib>
#include <cstdio>
#include <cassert>
#endif

#include "GenerateProblem.hpp"

#ifndef HPCG_NOMPI
#include <mpi.h>
#endif

#ifndef HPCG_NOOPENMP
#include <omp.h>
#endif

void GenerateProblem(const Geometry & geom, SparseMatrix & A, double **x, double **b, double **xexact) {

	int size = geom.size;
	int rank = geom.rank;
	int nx = geom.nx;
	int ny = geom.ny;
	int nz = geom.nz;
	int npx = geom.npx;
	int npy = geom.npy;
	int npz = geom.npz;
	int ipx = geom.ipx;
	int ipy = geom.ipy;
	int ipz = geom.ipz;
	int gnx = nx*npx;
	int gny = ny*npy;
	int gnz = nz*npz;

	local_int_t localNumberOfRows = nx*ny*nz; // This is the size of our subblock
	int numberOfNonzerosPerRow = 27; // We are approximating a 27-point finite element/volume/difference 3D stencil

	global_int_t totalNumberOfRows = localNumberOfRows*size; // Total number of grid points in mesh

	// Allocate arrays that are of length localNumberOfRows
	char * nonzerosInRow = new char[localNumberOfRows];
	global_int_t ** mtxIndG = new global_int_t*[localNumberOfRows];
	//local_int_t  ** mtxIndL = new local_int_t*[localNumberOfRows];
	double ** matrixValues = new double*[localNumberOfRows];
	double ** matrixDiagonal = new double*[localNumberOfRows];

	*x = new double[localNumberOfRows];
	*b = new double[localNumberOfRows];
	*xexact = new double[localNumberOfRows];
	A.localToGlobalMap.resize(localNumberOfRows);

	global_int_t localNumberOfNonzeros = 0;
	// TODO:  This triply nested loop could be flattened or use nested parallelism
#ifndef HPCG_NOOPENMP
#pragma omp parallel for
#endif
	for (local_int_t iz=0; iz<nz; iz++) {
		global_int_t giz = ipz*nz+iz;
		for (local_int_t iy=0; iy<ny; iy++) {
			global_int_t giy = ipy*ny+iy;
			for (local_int_t ix=0; ix<nx; ix++) {
				global_int_t gix = ipx*nx+ix;
				local_int_t currentLocalRow = iz*nx*ny+iy*nx+ix;
				global_int_t currentGlobalRow = giz*gnx*gny+giy*gnx+gix;
				A.globalToLocalMap[currentGlobalRow] = currentLocalRow;
				A.localToGlobalMap[currentLocalRow] = currentGlobalRow;
#ifdef DETAILEDDEBUG
				cout << " rank, globalRow, localRow = " << rank << " " << currentGlobalRow << " " << A.globalToLocalMap[currentGlobalRow] << endl;
#endif
				local_int_t numberOfNonzerosInRow = 0;
				matrixValues[currentLocalRow] = new double[numberOfNonzerosPerRow]; // Allocate a row worth of values.
				mtxIndG[currentLocalRow] = new global_int_t[numberOfNonzerosPerRow]; // Allocate a row worth of indices.
				double * currentValuePointer = matrixValues[currentLocalRow]; // Pointer to current value in current row
				global_int_t * currentIndexPointerG = mtxIndG[currentLocalRow]; // Pointer to current index in current row
				for (int sz=-1; sz<=1; sz++) {
					if (giz+sz>-1 && giz+sz<gnz) {
						for (int sy=-1; sy<=1; sy++) {
							if (giy+sy>-1 && giy+sy<gny) {
								for (int sx=-1; sx<=1; sx++) {
									if (gix+sx>-1 && gix+sx<gnx) {
										global_int_t curcol = currentGlobalRow+sz*gnx*gny+sy*gnx+sx;
										if (curcol==currentGlobalRow) {
											matrixDiagonal[currentLocalRow] = currentValuePointer;
											*currentValuePointer++ = 27.0;
										}
										else {
											*currentValuePointer++ = -1.0;
										}
										*currentIndexPointerG++ = curcol;
										numberOfNonzerosInRow++;
									} // end x bounds test
								} // end sx loop
							} // end y bounds test
						} // end sy loop
					} // end z bounds test
				} // end sz loop
				nonzerosInRow[currentLocalRow] = numberOfNonzerosInRow;
#ifndef HPCG_NOOPENMP
#pragma omp atomic
#endif
				localNumberOfNonzeros += numberOfNonzerosInRow; // Protect this with an atomic
				(*x)[currentLocalRow] = 0.0;
				(*b)[currentLocalRow] = 27.0 - ((double) (numberOfNonzerosInRow-1));
				(*xexact)[currentLocalRow] = 1.0;
			} // end ix loop
		} // end iy loop
	} // end iz loop
#ifdef DEBUG
	cout 	  << "Process " << rank << " of " << size <<" has " << localNumberOfRows    << " rows."     << endl
			  << "Process " << rank << " of " << size <<" has " << localNumberOfNonzeros<< " nonzeros." <<endl;
#endif

#ifndef HPCG_NOMPI
  // Use MPI's reduce function to sum all nonzeros
  global_int_t totalNumberOfNonzeros = 0;
  MPI_Allreduce(&localNumberOfNonzeros, &totalNumberOfNonzeros, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
#else
  global_int_t totalNumberOfNonzeros = localNumberOfNonzeros;
#endif

	A.title = 0;
	A.totalNumberOfRows = totalNumberOfRows;
	A.totalNumberOfNonzeros = totalNumberOfNonzeros;
	A.localNumberOfRows = localNumberOfRows;
	A.localNumberOfColumns = localNumberOfRows;
	A.localNumberOfNonzeros = localNumberOfNonzeros;
	A.nonzerosInRow = nonzerosInRow;
	A.mtxIndG = mtxIndG;
	//A.mtxIndL = mtxIndL;
	A.matrixValues = matrixValues;
	A.matrixDiagonal = matrixDiagonal;

	return;
}
<commit_msg>In progress.<commit_after>
//@HEADER
// ************************************************************************
//
//               HPCG: Simple Conjugate Gradient Benchmark Code
// Questions? Contact Michael A. Heroux (maherou@sandia.gov)
//
// ************************************************************************
//@HEADER

/////////////////////////////////////////////////////////////////////////

// Routine to read a sparse matrix, right hand side, initial guess,
// and exact solution (as computed by a direct solver).

/////////////////////////////////////////////////////////////////////////

#if defined(DEBUG) || defined(DETAILEDDEBUG)
#include <iostream>
using std::cout;
using std::cerr;
using std::endl;
#include <cstdlib>
#include <cstdio>
#include <cassert>
#endif

#include "GenerateProblem.hpp"

#ifndef HPCG_NOMPI
#include <mpi.h>
#endif

#ifndef HPCG_NOOPENMP
#include <omp.h>
#endif

void GenerateProblem(const Geometry & geom, SparseMatrix & A, double **x, double **b, double **xexact) {

	int size = geom.size;
	int rank = geom.rank;
	int nx = geom.nx;
	int ny = geom.ny;
	int nz = geom.nz;
	int npx = geom.npx;
	int npy = geom.npy;
	int npz = geom.npz;
	int ipx = geom.ipx;
	int ipy = geom.ipy;
	int ipz = geom.ipz;
	int gnx = nx*npx;
	int gny = ny*npy;
	int gnz = nz*npz;

	local_int_t localNumberOfRows = nx*ny*nz; // This is the size of our subblock
	int numberOfNonzerosPerRow = 27; // We are approximating a 27-point finite element/volume/difference 3D stencil

	global_int_t totalNumberOfRows = localNumberOfRows*size; // Total number of grid points in mesh

	// Allocate arrays that are of length localNumberOfRows
	char * nonzerosInRow = new char[localNumberOfRows];
	global_int_t ** mtxIndG = new global_int_t*[localNumberOfRows];
	//local_int_t  ** mtxIndL = new local_int_t*[localNumberOfRows];
	double ** matrixValues = new double*[localNumberOfRows];
	double ** matrixDiagonal = new double*[localNumberOfRows];

	*x = new double[localNumberOfRows];
	*b = new double[localNumberOfRows];
	*xexact = new double[localNumberOfRows];
	A.localToGlobalMap.resize(localNumberOfRows);

	global_int_t localNumberOfNonzeros = 0;
	// TODO:  This triply nested loop could be flattened or use nested parallelism
#ifndef HPCG_NOOPENMP
//#pragma omp parallel for
#endif
	for (local_int_t iz=0; iz<nz; iz++) {
		global_int_t giz = ipz*nz+iz;
		for (local_int_t iy=0; iy<ny; iy++) {
			global_int_t giy = ipy*ny+iy;
			for (local_int_t ix=0; ix<nx; ix++) {
				global_int_t gix = ipx*nx+ix;
				local_int_t currentLocalRow = iz*nx*ny+iy*nx+ix;
				global_int_t currentGlobalRow = giz*gnx*gny+giy*gnx+gix;
				A.globalToLocalMap[currentGlobalRow] = currentLocalRow;
				A.localToGlobalMap[currentLocalRow] = currentGlobalRow;
#ifdef DETAILEDDEBUG
				cout << " rank, globalRow, localRow = " << rank << " " << currentGlobalRow << " " << A.globalToLocalMap[currentGlobalRow] << endl;
#endif
				local_int_t numberOfNonzerosInRow = 0;
				matrixValues[currentLocalRow] = new double[numberOfNonzerosPerRow]; // Allocate a row worth of values.
				mtxIndG[currentLocalRow] = new global_int_t[numberOfNonzerosPerRow]; // Allocate a row worth of indices.
				double * currentValuePointer = matrixValues[currentLocalRow]; // Pointer to current value in current row
				global_int_t * currentIndexPointerG = mtxIndG[currentLocalRow]; // Pointer to current index in current row
				for (int sz=-1; sz<=1; sz++) {
					if (giz+sz>-1 && giz+sz<gnz) {
						for (int sy=-1; sy<=1; sy++) {
							if (giy+sy>-1 && giy+sy<gny) {
								for (int sx=-1; sx<=1; sx++) {
									if (gix+sx>-1 && gix+sx<gnx) {
										global_int_t curcol = currentGlobalRow+sz*gnx*gny+sy*gnx+sx;
										if (curcol==currentGlobalRow) {
											matrixDiagonal[currentLocalRow] = currentValuePointer;
											*currentValuePointer++ = 27.0;
										}
										else {
											*currentValuePointer++ = -1.0;
										}
										*currentIndexPointerG++ = curcol;
										numberOfNonzerosInRow++;
									} // end x bounds test
								} // end sx loop
							} // end y bounds test
						} // end sy loop
					} // end z bounds test
				} // end sz loop
				nonzerosInRow[currentLocalRow] = numberOfNonzerosInRow;
#ifndef HPCG_NOOPENMP
#pragma omp atomic
#endif
				localNumberOfNonzeros += numberOfNonzerosInRow; // Protect this with an atomic
				(*x)[currentLocalRow] = 0.0;
				(*b)[currentLocalRow] = 27.0 - ((double) (numberOfNonzerosInRow-1));
				(*xexact)[currentLocalRow] = 1.0;
			} // end ix loop
		} // end iy loop
	} // end iz loop
#ifdef DEBUG
	cout 	  << "Process " << rank << " of " << size <<" has " << localNumberOfRows    << " rows."     << endl
			  << "Process " << rank << " of " << size <<" has " << localNumberOfNonzeros<< " nonzeros." <<endl;
#endif

#ifndef HPCG_NOMPI
  // Use MPI's reduce function to sum all nonzeros
  global_int_t totalNumberOfNonzeros = 0;
  MPI_Allreduce(&localNumberOfNonzeros, &totalNumberOfNonzeros, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
#else
  global_int_t totalNumberOfNonzeros = localNumberOfNonzeros;
#endif

	A.title = 0;
	A.totalNumberOfRows = totalNumberOfRows;
	A.totalNumberOfNonzeros = totalNumberOfNonzeros;
	A.localNumberOfRows = localNumberOfRows;
	A.localNumberOfColumns = localNumberOfRows;
	A.localNumberOfNonzeros = localNumberOfNonzeros;
	A.nonzerosInRow = nonzerosInRow;
	A.mtxIndG = mtxIndG;
	//A.mtxIndL = mtxIndL;
	A.matrixValues = matrixValues;
	A.matrixDiagonal = matrixDiagonal;

	return;
}
<|endoftext|>


<commit_before>#include "stdafx.h"
#include "PostmortemDebugging.h"
#include "Hook.h"
#include "Logging.h"

typedef BOOL (__stdcall *PDUMPFN)(
	HANDLE hProcess,
	DWORD ProcessId,
	HANDLE hFile,
	MINIDUMP_TYPE DumpType,
	PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
	PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
	PMINIDUMP_CALLBACK_INFORMATION CallbackParam
);

bool _collectDumps = false;
int _numRetainedMinidumps = 0;

std::wstring _dateTimeBuffer;
std::wstring _dumpFolder;
std::wstring _dumpName;
std::wstringstream _minidumpStringBuilder;
std::wstring _minidumpFileName;
std::wstring _minidumpPattern;
std::wstring _tmpPath;
std::wstring _oldestFileFullName;

BOOL CheckDumpNameConstraints(const wchar_t* dumpName)
{
	auto dumpNameLength = wcslen(dumpName);
	if (wcschr(dumpName, '/') != nullptr ||
		wcschr(dumpName, '\\') != nullptr ||
		wcsstr(dumpName, L"..") != nullptr ||
		wcsstr(dumpName, L":") != nullptr ||
		wcsstr(dumpName, L"*") != nullptr ||
		wcsstr(dumpName, L"?") != nullptr ||
		wcsstr(dumpName, L"\"") != nullptr ||
		dumpNameLength == 0)
	{
		return FALSE;
	}

	return TRUE;
}

BOOL CreateMinidumpFolder()
{
	SECURITY_ATTRIBUTES attr;
	ZeroMemory(&attr, sizeof(SECURITY_ATTRIBUTES));
	attr.nLength = sizeof(SECURITY_ATTRIBUTES);

	auto start = _dumpFolder.begin();
	auto it = start;
	auto end = _dumpFolder.end();
	while((it = std::find(it, end, '\\')) != end)
	{
		auto folder = std::wstring(start, it);
		if (!(folder.length() == 2 && folder[1] == ':'))
		{
			LOG2("Creating directory: '", folder);

			if (CreateDirectory(folder.c_str(), &attr) == FALSE)
			{
				HRESULT err = GetLastError();
				if (err != ERROR_ALREADY_EXISTS)
				{
					LOG4("CreateDirectory '", folder, "'failed: ", err);
					return FALSE;
				}
			}
		}

		// it points to the current '\\' and thus we want to increment it by 1 so
		// we can find the next occurence of '\\' and not the current one which would
		// create an endless loop ;)
		++it;
	}

	LOG1("Created directory");

	return TRUE;
}

BOOL RemoveOldMinidumps()
{
	WIN32_FIND_DATA fdFile;
	HANDLE hFind = nullptr;

	int numFiles = 0;
	FILETIME oldestFileTime;

	LOG2("Removing old minidumps, pattern: ", _minidumpPattern);

	const wchar_t* folder = _minidumpPattern.c_str();
	if ((hFind = FindFirstFile(folder, &fdFile)) == INVALID_HANDLE_VALUE)
	{
		auto err = GetLastError();
		if (err == ERROR_FILE_NOT_FOUND)
		{
			LOG1("No previous dump files found");
			return TRUE;
		}

		LOG2("FindFirstFile failed: ", err);

		return FALSE;
	}
	else
	{
		do
		{
			if(wcscmp(fdFile.cFileName, L".") != 0 && wcscmp(fdFile.cFileName, L"..") != 0)
			{
				_tmpPath.clear();
				_tmpPath.append(folder);
				_tmpPath.append(fdFile.cFileName);

				if(numFiles == 0)
				{
					oldestFileTime = fdFile.ftLastWriteTime;
					_oldestFileFullName = _tmpPath;
				}
				else if (CompareFileTime(&oldestFileTime, &fdFile.ftLastWriteTime) == 1)
				{
					oldestFileTime = fdFile.ftLastWriteTime;
					_oldestFileFullName = _tmpPath;
				}

				if (numFiles+1 >= _numRetainedMinidumps)
				{
					if (!DeleteFile(_oldestFileFullName.c_str()))
					{
						const auto err = GetLastError();
						LOG2("DeleteFile failed: ", err);
						return FALSE;
					}
				}
				else
				{
					++numFiles;
				}
			}
		} while(FindNextFile(hFind, &fdFile) != FALSE);
	}

	LOG1("Removed old minidumps");
	return TRUE;
}

void CreateMinidumpFileName()
{
	SYSTEMTIME time;
	GetLocalTime(&time);

	std::wstringstream& name = _minidumpStringBuilder;

	name << _dumpFolder;
	name << _dumpName;

	name << '_';

	if (time.wDay < 10)
		name << '0';
	name << time.wDay << '.';

	if (time.wMonth < 10)
		name << '0';
	name << time.wMonth;

	name << '.' << time.wYear;
	name << L" - " << time.wHour << '_' << time.wMinute << '_' << time.wSecond;
	name << L".dmp";
	_minidumpFileName = name.str();

	LOG2("Minidump file name: ", _minidumpFileName);
}

void CreateMiniDump(EXCEPTION_POINTERS* exceptionPointers,
					HANDLE processHandle,
					int processId,
					const wchar_t* dumpName)
{
	LOG1("Creating Mini dump...");

	if (CreateMinidumpFolder() == FALSE)
	{
		return;
	}

	// We shouldn't pe persuaded to give up writing the minidump just because we failed to
	// remove old dumps... writing the new one is much more important...
	if (RemoveOldMinidumps() == FALSE)
	{
		LOG1("Failed to remove old minidumps, ignoring it...");
	}

	LOG1("Creating name...");

	CreateMinidumpFileName();

	HANDLE hFile = CreateFile( _minidumpFileName.c_str(),
		GENERIC_READ | GENERIC_WRITE,
		0,
		NULL,
		CREATE_ALWAYS,
		FILE_ATTRIBUTE_NORMAL,
		NULL);

	if (hFile == INVALID_HANDLE_VALUE)
	{
		auto err = GetLastError();
		LOG2("CreateFile returned INVALID_HANDLE_VALUE: GetLastError()=", err)
		return;
	}

	HMODULE dbghelp = ::LoadLibrary(L"DbgHelp.dll");
	if (dbghelp == nullptr)
		return;

	PDUMPFN miniDumpWriteDump = (PDUMPFN)GetProcAddress(dbghelp, "MiniDumpWriteDump");
	if (miniDumpWriteDump == nullptr)
		return;

	if( ( hFile != nullptr ) && ( hFile != INVALID_HANDLE_VALUE ) )
	{
		MINIDUMP_EXCEPTION_INFORMATION info;

		info.ThreadId           = GetCurrentThreadId();
		info.ExceptionPointers  = exceptionPointers;
		info.ClientPointers     = TRUE;

		MINIDUMP_TYPE mdt       = MiniDumpNormal;

		BOOL rv = (*miniDumpWriteDump)(
			processHandle,
			processId,
			hFile,
			mdt,
			(exceptionPointers != nullptr) ? &info : nullptr,
			0,
			0);

		if (rv != FALSE)
		{
			LOG1("Minidump saved");
		}
		else
		{
			LOG1("MiniDumpWriteDump returned FALSE, unable to write a minidump");
		}

		if (CloseHandle( hFile ) == FALSE)
		{
			LOG2("CloseHandle failed: GetLastError()=", GetLastError());
		}
	}
}

void CreateMiniDump(EXCEPTION_POINTERS* exceptionPointers)
{
	if (_collectDumps)
	{
		CreateMiniDump(exceptionPointers,
			GetCurrentProcess(),
			GetCurrentProcessId(),
			_dumpName.c_str());
	}
	else
	{
		LOG1("NOT creating a minidump because InitDumpCollection has NOT been called (yet)");
	}
}

void failfast()
{
	LOG1("failfast()");

	abort();
}

LONG WINAPI OnUnhandledException(struct _EXCEPTION_POINTERS *exceptionPointers)
{
	LOG4("Caught unhandled exception, ExceptionCode=0x",
		exceptionPointers->ExceptionRecord->ExceptionCode,
		", ExceptionAddress=0x",
		exceptionPointers->ExceptionRecord->ExceptionAddress);

	CreateMiniDump(exceptionPointers);

	return EXCEPTION_EXECUTE_HANDLER;
}

void __cdecl OnCrtAssert( const wchar_t* message, const wchar_t* file, unsigned lineNumber )
{
	LOG1("Caught assert");

	CreateMiniDump(NULL);
	failfast();
}

void __cdecl OnCrtPurecall()
{
	LOG1("Caught pure virtual function call");

	CreateMiniDump(NULL);
	failfast();
}

extern "C" {

	BOOL InitLogging(const wchar_t* logFilePath)
	{
		if (!EnableLogging(logFilePath))
			return FALSE;

		return TRUE;
	}

	BOOL InitDumpCollection(int numRetainedMinidumps, const wchar_t* dumpFolder, const wchar_t* dumpName)
	{
		LOG1("Initializing mini dump collection...");

		if (_collectDumps)
		{
			SetLastError(ERROR_ACCESS_DENIED);
			return FALSE;
		}

		if (numRetainedMinidumps <= 0 || dumpFolder == NULL || dumpName == NULL)
		{
			SetLastError(ERROR_BAD_ARGUMENTS);
			return FALSE;
		}

		auto dumpFolderLength = wcslen(dumpFolder);
		if (wcschr(dumpFolder, '/') != NULL || dumpFolder[dumpFolderLength-1] != '\\' ||
			PathIsRelative(dumpFolder) == TRUE)
		{
			SetLastError(ERROR_BAD_ARGUMENTS);
			return FALSE;
		}

		if (CheckDumpNameConstraints(dumpName) == FALSE)
		{
			SetLastError(ERROR_BAD_ARGUMENTS);
			return FALSE;
		}

		_numRetainedMinidumps = numRetainedMinidumps;
		_dumpFolder = dumpFolder;
		_dumpName = dumpName;

		_minidumpPattern = _dumpFolder;
		_minidumpPattern += _dumpName;
		_minidumpPattern += L"*.dmp";

		_tmpPath.reserve(2048);
		_oldestFileFullName.reserve(2048);

		LOG1("Mini dump collection successfully installed!");

		_collectDumps = true;
		return TRUE;
	}

	BOOL InstallPostmortemDebugger(BOOL suppressErrorWindows,
								   BOOL handleUnhandledExceptions,
								   BOOL handleCrtAsserts,
								   BOOL handleCrtPurecalls,
								   CRuntimeVersions crtVersions)
	{
		std::wostringstream message;
		message << "Installing post mortem debugger:" << std::endl
			<< "  suppressErrorWindows=" << suppressErrorWindows << std::endl
			<< "  handleUnhandledExceptions=" << handleUnhandledExceptions << std::endl
			<< "  handleCrtAsserts=" << handleCrtAsserts << std::endl
			<< "  handleCrtPurecalls=" << handleCrtPurecalls;
		LOG1(message.str());

		if (suppressErrorWindows == TRUE)
		{
			if (SuppressCrtAbortMessages(crtVersions) == FALSE)
				return FALSE;
		}
		if (handleUnhandledExceptions == TRUE)
		{
			DoSetUnhandledExceptionFilter(OnUnhandledException);
		}
		if (handleCrtAsserts == TRUE)
		{
			if (InterceptCrtAssert(&OnCrtAssert, crtVersions) == FALSE)
				return FALSE;
		}
		if (handleCrtPurecalls == TRUE)
		{
			if (InterceptCrtPurecalls(&OnCrtPurecall, crtVersions) == FALSE)
				return FALSE;
		}

		LOG1("Post mortem debugger successfully installed!");
		return TRUE;
	}

	BOOL CreateMiniDump(
			int processId,
			const wchar_t* dumpName
			)
	{
		LOG1("CreateMiniDump");

		if (_collectDumps == false)
		{
			SetLastError(ERROR_ACCESS_DENIED);
			return FALSE;
		}

		if (CheckDumpNameConstraints(dumpName) == FALSE)
		{
			SetLastError(ERROR_BAD_ARGUMENTS);
			return FALSE;
		}

		HANDLE hProcess = OpenProcess(
			PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_DUP_HANDLE,
			FALSE,
			processId);
		if (hProcess == NULL)
		{
			LOG1("OpenProcess failed...");
			return FALSE;
		}

		CreateMiniDump(NULL,
			hProcess,
			processId,
			dumpName);

		CloseHandle(hProcess);

		return TRUE;
	}
}
<commit_msg>Added milliseconds to minidump name<commit_after>#include "stdafx.h"
#include "PostmortemDebugging.h"
#include "Hook.h"
#include "Logging.h"

typedef BOOL (__stdcall *PDUMPFN)(
	HANDLE hProcess,
	DWORD ProcessId,
	HANDLE hFile,
	MINIDUMP_TYPE DumpType,
	PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
	PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
	PMINIDUMP_CALLBACK_INFORMATION CallbackParam
);

bool _collectDumps = false;
int _numRetainedMinidumps = 0;

std::wstring _dateTimeBuffer;
std::wstring _dumpFolder;
std::wstring _dumpName;
std::wstringstream _minidumpStringBuilder;
std::wstring _minidumpFileName;
std::wstring _minidumpPattern;
std::wstring _tmpPath;
std::wstring _oldestFileFullName;

BOOL CheckDumpNameConstraints(const wchar_t* dumpName)
{
	auto dumpNameLength = wcslen(dumpName);
	if (wcschr(dumpName, '/') != nullptr ||
		wcschr(dumpName, '\\') != nullptr ||
		wcsstr(dumpName, L"..") != nullptr ||
		wcsstr(dumpName, L":") != nullptr ||
		wcsstr(dumpName, L"*") != nullptr ||
		wcsstr(dumpName, L"?") != nullptr ||
		wcsstr(dumpName, L"\"") != nullptr ||
		dumpNameLength == 0)
	{
		return FALSE;
	}

	return TRUE;
}

BOOL CreateMinidumpFolder()
{
	SECURITY_ATTRIBUTES attr;
	ZeroMemory(&attr, sizeof(SECURITY_ATTRIBUTES));
	attr.nLength = sizeof(SECURITY_ATTRIBUTES);

	auto start = _dumpFolder.begin();
	auto it = start;
	auto end = _dumpFolder.end();
	while((it = std::find(it, end, '\\')) != end)
	{
		auto folder = std::wstring(start, it);
		if (!(folder.length() == 2 && folder[1] == ':'))
		{
			LOG2("Creating directory: '", folder);

			if (CreateDirectory(folder.c_str(), &attr) == FALSE)
			{
				HRESULT err = GetLastError();
				if (err != ERROR_ALREADY_EXISTS)
				{
					LOG4("CreateDirectory '", folder, "'failed: ", err);
					return FALSE;
				}
			}
		}

		// it points to the current '\\' and thus we want to increment it by 1 so
		// we can find the next occurence of '\\' and not the current one which would
		// create an endless loop ;)
		++it;
	}

	LOG1("Created directory");

	return TRUE;
}

BOOL RemoveOldMinidumps()
{
	WIN32_FIND_DATA fdFile;
	HANDLE hFind = nullptr;

	int numFiles = 0;
	FILETIME oldestFileTime;

	LOG2("Removing old minidumps, pattern: ", _minidumpPattern);

	const wchar_t* folder = _minidumpPattern.c_str();
	if ((hFind = FindFirstFile(folder, &fdFile)) == INVALID_HANDLE_VALUE)
	{
		auto err = GetLastError();
		if (err == ERROR_FILE_NOT_FOUND)
		{
			LOG1("No previous dump files found");
			return TRUE;
		}

		LOG2("FindFirstFile failed: ", err);

		return FALSE;
	}
	else
	{
		do
		{
			if(wcscmp(fdFile.cFileName, L".") != 0 && wcscmp(fdFile.cFileName, L"..") != 0)
			{
				_tmpPath.clear();
				_tmpPath.append(folder);
				_tmpPath.append(fdFile.cFileName);

				if(numFiles == 0)
				{
					oldestFileTime = fdFile.ftLastWriteTime;
					_oldestFileFullName = _tmpPath;
				}
				else if (CompareFileTime(&oldestFileTime, &fdFile.ftLastWriteTime) == 1)
				{
					oldestFileTime = fdFile.ftLastWriteTime;
					_oldestFileFullName = _tmpPath;
				}

				if (numFiles+1 >= _numRetainedMinidumps)
				{
					if (!DeleteFile(_oldestFileFullName.c_str()))
					{
						const auto err = GetLastError();
						LOG2("DeleteFile failed: ", err);
						return FALSE;
					}
				}
				else
				{
					++numFiles;
				}
			}
		} while(FindNextFile(hFind, &fdFile) != FALSE);
	}

	LOG1("Removed old minidumps");
	return TRUE;
}

void CreateMinidumpFileName()
{
	SYSTEMTIME time;
	GetLocalTime(&time);

	std::wstringstream& name = _minidumpStringBuilder;

	name << _dumpFolder;
	name << _dumpName;

	name << '_';

	if (time.wDay < 10)
		name << '0';
	name << time.wDay << '.';

	if (time.wMonth < 10)
		name << '0';
	name << time.wMonth;

	name << '.' << time.wYear;
	name << L" - " << time.wHour << '_' << time.wMinute << '_' << time.wSecond << '.' << time.wMilliseconds;
	name << L".dmp";
	_minidumpFileName = name.str();

	LOG2("Minidump file name: ", _minidumpFileName);
}

void CreateMiniDump(EXCEPTION_POINTERS* exceptionPointers,
					HANDLE processHandle,
					int processId,
					const wchar_t* dumpName)
{
	LOG1("Creating Mini dump...");

	if (CreateMinidumpFolder() == FALSE)
	{
		return;
	}

	// We shouldn't pe persuaded to give up writing the minidump just because we failed to
	// remove old dumps... writing the new one is much more important...
	if (RemoveOldMinidumps() == FALSE)
	{
		LOG1("Failed to remove old minidumps, ignoring it...");
	}

	LOG1("Creating name...");

	CreateMinidumpFileName();

	HANDLE hFile = CreateFile( _minidumpFileName.c_str(),
		GENERIC_READ | GENERIC_WRITE,
		0,
		NULL,
		CREATE_ALWAYS,
		FILE_ATTRIBUTE_NORMAL,
		NULL);

	if (hFile == INVALID_HANDLE_VALUE)
	{
		auto err = GetLastError();
		LOG2("CreateFile returned INVALID_HANDLE_VALUE: GetLastError()=", err)
		return;
	}

	HMODULE dbghelp = ::LoadLibrary(L"DbgHelp.dll");
	if (dbghelp == nullptr)
		return;

	PDUMPFN miniDumpWriteDump = (PDUMPFN)GetProcAddress(dbghelp, "MiniDumpWriteDump");
	if (miniDumpWriteDump == nullptr)
		return;

	if( ( hFile != nullptr ) && ( hFile != INVALID_HANDLE_VALUE ) )
	{
		MINIDUMP_EXCEPTION_INFORMATION info;

		info.ThreadId           = GetCurrentThreadId();
		info.ExceptionPointers  = exceptionPointers;
		info.ClientPointers     = TRUE;

		MINIDUMP_TYPE mdt       = MiniDumpNormal;

		BOOL rv = (*miniDumpWriteDump)(
			processHandle,
			processId,
			hFile,
			mdt,
			(exceptionPointers != nullptr) ? &info : nullptr,
			0,
			0);

		if (rv != FALSE)
		{
			LOG1("Minidump saved");
		}
		else
		{
			LOG1("MiniDumpWriteDump returned FALSE, unable to write a minidump");
		}

		if (CloseHandle( hFile ) == FALSE)
		{
			LOG2("CloseHandle failed: GetLastError()=", GetLastError());
		}
	}
}

void CreateMiniDump(EXCEPTION_POINTERS* exceptionPointers)
{
	if (_collectDumps)
	{
		CreateMiniDump(exceptionPointers,
			GetCurrentProcess(),
			GetCurrentProcessId(),
			_dumpName.c_str());
	}
	else
	{
		LOG1("NOT creating a minidump because InitDumpCollection has NOT been called (yet)");
	}
}

void failfast()
{
	LOG1("failfast()");

	abort();
}

LONG WINAPI OnUnhandledException(struct _EXCEPTION_POINTERS *exceptionPointers)
{
	LOG4("Caught unhandled exception, ExceptionCode=0x",
		exceptionPointers->ExceptionRecord->ExceptionCode,
		", ExceptionAddress=0x",
		exceptionPointers->ExceptionRecord->ExceptionAddress);

	CreateMiniDump(exceptionPointers);

	return EXCEPTION_EXECUTE_HANDLER;
}

void __cdecl OnCrtAssert( const wchar_t* message, const wchar_t* file, unsigned lineNumber )
{
	LOG1("Caught assert");

	CreateMiniDump(NULL);
	failfast();
}

void __cdecl OnCrtPurecall()
{
	LOG1("Caught pure virtual function call");

	CreateMiniDump(NULL);
	failfast();
}

extern "C" {

	BOOL InitLogging(const wchar_t* logFilePath)
	{
		if (!EnableLogging(logFilePath))
			return FALSE;

		return TRUE;
	}

	BOOL InitDumpCollection(int numRetainedMinidumps, const wchar_t* dumpFolder, const wchar_t* dumpName)
	{
		LOG1("Initializing mini dump collection...");

		if (_collectDumps)
		{
			SetLastError(ERROR_ACCESS_DENIED);
			return FALSE;
		}

		if (numRetainedMinidumps <= 0 || dumpFolder == NULL || dumpName == NULL)
		{
			SetLastError(ERROR_BAD_ARGUMENTS);
			return FALSE;
		}

		auto dumpFolderLength = wcslen(dumpFolder);
		if (wcschr(dumpFolder, '/') != NULL || dumpFolder[dumpFolderLength-1] != '\\' ||
			PathIsRelative(dumpFolder) == TRUE)
		{
			SetLastError(ERROR_BAD_ARGUMENTS);
			return FALSE;
		}

		if (CheckDumpNameConstraints(dumpName) == FALSE)
		{
			SetLastError(ERROR_BAD_ARGUMENTS);
			return FALSE;
		}

		_numRetainedMinidumps = numRetainedMinidumps;
		_dumpFolder = dumpFolder;
		_dumpName = dumpName;

		_minidumpPattern = _dumpFolder;
		_minidumpPattern += _dumpName;
		_minidumpPattern += L"*.dmp";

		_tmpPath.reserve(2048);
		_oldestFileFullName.reserve(2048);

		LOG1("Mini dump collection successfully installed!");

		_collectDumps = true;
		return TRUE;
	}

	BOOL InstallPostmortemDebugger(BOOL suppressErrorWindows,
								   BOOL handleUnhandledExceptions,
								   BOOL handleCrtAsserts,
								   BOOL handleCrtPurecalls,
								   CRuntimeVersions crtVersions)
	{
		std::wostringstream message;
		message << "Installing post mortem debugger:" << std::endl
			<< "  suppressErrorWindows=" << suppressErrorWindows << std::endl
			<< "  handleUnhandledExceptions=" << handleUnhandledExceptions << std::endl
			<< "  handleCrtAsserts=" << handleCrtAsserts << std::endl
			<< "  handleCrtPurecalls=" << handleCrtPurecalls;
		LOG1(message.str());

		if (suppressErrorWindows == TRUE)
		{
			if (SuppressCrtAbortMessages(crtVersions) == FALSE)
				return FALSE;
		}
		if (handleUnhandledExceptions == TRUE)
		{
			DoSetUnhandledExceptionFilter(OnUnhandledException);
		}
		if (handleCrtAsserts == TRUE)
		{
			if (InterceptCrtAssert(&OnCrtAssert, crtVersions) == FALSE)
				return FALSE;
		}
		if (handleCrtPurecalls == TRUE)
		{
			if (InterceptCrtPurecalls(&OnCrtPurecall, crtVersions) == FALSE)
				return FALSE;
		}

		LOG1("Post mortem debugger successfully installed!");
		return TRUE;
	}

	BOOL CreateMiniDump(
			int processId,
			const wchar_t* dumpName
			)
	{
		LOG1("CreateMiniDump");

		if (_collectDumps == false)
		{
			SetLastError(ERROR_ACCESS_DENIED);
			return FALSE;
		}

		if (CheckDumpNameConstraints(dumpName) == FALSE)
		{
			SetLastError(ERROR_BAD_ARGUMENTS);
			return FALSE;
		}

		HANDLE hProcess = OpenProcess(
			PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_DUP_HANDLE,
			FALSE,
			processId);
		if (hProcess == NULL)
		{
			LOG1("OpenProcess failed...");
			return FALSE;
		}

		CreateMiniDump(NULL,
			hProcess,
			processId,
			dumpName);

		CloseHandle(hProcess);

		return TRUE;
	}
}
<|endoftext|>


<commit_before>/***************************Copyright-DO-NOT-REMOVE-THIS-LINE**
 * CONDOR Copyright Notice
 *
 * See LICENSE.TXT for additional notices and disclaimers.
 *
 * Copyright (c)1990-1998 CONDOR Team, Computer Sciences Department,
 * University of Wisconsin-Madison, Madison, WI.  All Rights Reserved.
 * No use of the CONDOR Software Program Source Code is authorized
 * without the express consent of the CONDOR Team.  For more information
 * contact: CONDOR Team, Attention: Professor Miron Livny,
 * 7367 Computer Sciences, 1210 W. Dayton St., Madison, WI 53706-1685,
 * (608) 262-0856 or miron@cs.wisc.edu.
 *
 * U.S. Government Rights Restrictions: Use, duplication, or disclosure
 * by the U.S. Government is subject to restrictions as set forth in
 * subparagraph (c)(1)(ii) of The Rights in Technical Data and Computer
 * Software clause at DFARS 252.227-7013 or subparagraphs (c)(1) and
 * (2) of Commercial Computer Software-Restricted Rights at 48 CFR
 * 52.227-19, as applicable, CONDOR Team, Attention: Professor Miron
 * Livny, 7367 Computer Sciences, 1210 W. Dayton St., Madison,
 * WI 53706-1685, (608) 262-0856 or miron@cs.wisc.edu.
****************************Copyright-DO-NOT-REMOVE-THIS-LINE**/
#include "condor_common.h"
#include "condor_debug.h"
#include "condor_classad.h"
#include "HashTable.h"
#include "hashkey.h"
#include "sched.h"
#include "condor_attributes.h"

#ifndef WIN32
#include <netinet/in.h>
#endif

extern "C" char * sin_to_string(struct sockaddr_in *);

template class HashTable<HashKey, ClassAd *>;
extern void parseIpPort (char *, char *);

void HashKey::sprint (char *s)
{
	if (ip_addr[0])
		sprintf (s, "< %s , %s >", name, ip_addr);
	else
		sprintf (s, "< %s >", name);
}

bool operator== (const HashKey &lhs, const HashKey &rhs)
{
    return (strcmp (lhs.name, rhs.name) == 0    &&
			strcmp (lhs.ip_addr, rhs.ip_addr) == 0);
}

ostream &operator<< (ostream &out, const HashKey &hk)
{
	out << "Hashkey: (" << hk.name << "," << hk.ip_addr;
	out << ")" << endl;
	return out;
}

int hashFunction (const HashKey &key, int numBuckets)
{
    unsigned int bkt = 0;
    int i;

    for (i = 0; key.name[i]   ; bkt += key.name[i++]);
    for (i = 0; key.ip_addr[i]; bkt += key.ip_addr[i++]);

    bkt %= numBuckets;

    return bkt;
}

int hashOnName (const HashKey &key, int numBuckets)
{
	unsigned int bkt = 0;
	int i;

	for (i = 0; key.name [i]; bkt += key.name[i++]);
	bkt %= numBuckets;

	return bkt;
}

// functions to make the hashkeys ...
// make hashkeys from the obtained ad
bool
makeStartdAdHashKey (HashKey &hk, ClassAd *ad, sockaddr_in *from)
{
	ExprTree *tree;
	char buffer [30];
	char buf2   [64];
	int  inferred = 0;

	// get the name of the startd
	if (!(tree = ad->Lookup ("Name")))
	{
		// ... if name was not specified
		dprintf(D_FULLDEBUG,"Warning: No 'Name' attribute; trying 'Machine'\n");
		tree = ad->Lookup ("Machine");
	}

	if (tree)
	{
		strcpy (hk.name, ((String *)tree->RArg())->Value());
	}
	else
	{
		// neither Name nor Machine specified in ad
		dprintf (D_ALWAYS, "Error: Neither 'Name' nor 'Machine' specified\n");
		return false;
	}

	// get the IP and port of the startd
	tree = ad->Lookup (ATTR_STARTD_IP_ADDR);

	// if not there, try to lookup the old style "STARTD_IP_ADDR" string
	if (!tree) tree = ad->Lookup ("STARTD_IP_ADDR");

	if (tree)
	{
		strcpy (buffer, ((String *)tree->RArg())->Value());
	}
	else
	{
		dprintf (D_FULLDEBUG,"Warning: No STARTD_IP_ADDR; inferring address\n");
		strcpy (buffer, sin_to_string (from));

		sprintf (buf2, "%s = \"%s\"", ATTR_STARTD_IP_ADDR, buffer);
		ad->Insert (buf2);
		dprintf (D_FULLDEBUG, "(Inferred address: %s)\n", buf2);
		inferred = 1;
	}

	parseIpPort (buffer, hk.ip_addr);

	return true;
}

bool
makeScheddAdHashKey (HashKey &hk, ClassAd *ad, sockaddr_in *from)
{
	ExprTree *tree;
	char buffer [30];
	char buf2   [64];
	int  inferred = 0;

	// get the name of the startd
	if (!(tree = ad->Lookup ("Name")))
	{
		dprintf(D_FULLDEBUG,"Warning: No 'Name' attribute; trying 'Machine'\n");
		// ... if name was not specified
		tree = ad->Lookup ("Machine");
	}

	if (tree)
	{
		strcpy (hk.name, ((String *)tree->RArg())->Value());
	}
	else
	{
		dprintf (D_ALWAYS, "Error: Neither 'Name' nor 'Machine' specified\n");
		// neither Name nor Machine specified
		return false;
	}

	// get the IP and port of the startd
	tree = ad->Lookup (ATTR_SCHEDD_IP_ADDR);

	if (!tree)
		tree = ad->Lookup ("SCHEDD_IP_ADDR");

	if (tree)
	{
		strcpy (buffer, ((String *)tree->RArg())->Value());
	}
	else
	{
		dprintf(D_FULLDEBUG,"Warning: No SCHEDD_IP_ADDR; inferring address\n");
		strcpy (buffer, sin_to_string (from));

        // since we have done the work ...
        sprintf (buf2, "%s = \"%s\"", ATTR_SCHEDD_IP_ADDR, buffer);
		ad->Insert (buf2);
		dprintf (D_FULLDEBUG, "(Inferred address: %s)\n", buf2);
		inferred = 1;
	}

	parseIpPort (buffer, hk.ip_addr);

	return true;
}

bool
makeLicenseAdHashKey (HashKey &hk, ClassAd *ad, sockaddr_in *from)
{
	ExprTree *tree;
	char buffer [30];
	char buf2   [64];
	int  inferred = 0;

	// get the name of the startd
	if (!(tree = ad->Lookup ("Name")))
	{
		dprintf(D_FULLDEBUG,"Warning: No 'Name' attribute; trying 'Machine'\n");
		// ... if name was not specified
		tree = ad->Lookup ("Machine");
	}

	if (tree)
	{
		strcpy (hk.name, ((String *)tree->RArg())->Value());
	}
	else
	{
		dprintf (D_ALWAYS, "Error: Neither 'Name' nor 'Machine' specified\n");
		// neither Name nor Machine specified
		return false;
	}

	// get the IP and port of the startd
	tree = ad->Lookup (ATTR_MY_ADDRESS);

	if (tree)
	{
		strcpy (buffer, ((String *)tree->RArg())->Value());
	}
	else
	{
		dprintf(D_FULLDEBUG,"Warning: No MY_ADDRESS; inferring address\n");
		strcpy (buffer, sin_to_string (from));

        // since we have done the work ...
        sprintf (buf2, "%s = \"%s\"", ATTR_MY_ADDRESS, buffer);
		ad->Insert (buf2);
		dprintf (D_FULLDEBUG, "(Inferred address: %s)\n", buf2);
		inferred = 1;
	}

	parseIpPort (buffer, hk.ip_addr);

	return true;
}

bool
makeMasterAdHashKey (HashKey &hk, ClassAd *ad, sockaddr_in *from)
{
	ExprTree *tree;

	if (!(tree = ad->Lookup ("Name")))
	{
		dprintf( D_FULLDEBUG,
				 "Warning: No 'Name' attribute; trying 'Machine'\n" );
			// ... if name was not specified
		tree = ad->Lookup ("Machine");
	}

	if (tree)
	{
		strcpy (hk.name, ((String *)tree->RArg())->Value ());
	}
	else
	{
		dprintf (D_ALWAYS, "Error: Neither 'Name' nor 'Machine' specified\n");
		// neither Name nor Machine specified
		return false;
	}

	// ip_addr not necessary
	hk.ip_addr [0] = '\0';

	return true;
}

bool
makeCkptSrvrAdHashKey (HashKey &hk, ClassAd *ad, sockaddr_in *from)
{
	if (!ad->LookupString ("Machine", hk.name))
	{
		dprintf (D_ALWAYS, "Error:  No 'Machine' attribute\n");
		return false;
	}

	hk.ip_addr[0] = '\0';

	return true;
}

bool
makeCollectorAdHashKey (HashKey &hk, ClassAd *ad, sockaddr_in *from)
{
	if (!ad->LookupString ("Machine", hk.name))
	{
		dprintf (D_ALWAYS, "Error:  No 'Machine' attribute\n");
		return false;
	}

	hk.ip_addr[0] = '\0';

	return true;
}

bool
makeStorageAdHashKey (HashKey &hk, ClassAd *ad, sockaddr_in *from)
{
	if (!ad->LookupString ("Name", hk.name))
	{
		dprintf (D_ALWAYS, "Error:  No 'Name' attribute\n");
		return false;
	}

	hk.ip_addr[0] = '\0';

	return true;
}

// utility function:  parse the string <aaa.bbb.ccc.ddd:pppp>
void
parseIpPort (char *ip_port_pair, char *ip_addr)
{
    char *ip_port = ip_port_pair + 1;
    char *ip = ip_addr;
    while (*ip_port != ':')
    {
        *ip = *ip_port;
        ip++;
        ip_port++;
    }

    *ip = '\0';

	// don't care about port number
}

<commit_msg>removing extraneous file hashkey.c - it breaks the windows build. ===VersionHistory=== None<commit_after><|endoftext|>


<commit_before>#include <stdlib.h>

#include "condor_debug.h"
#include "condor_classad.h"
#pragma implementation "HashTable.h"
#include "HashTable.h"
#include "hashkey.h"
#include "sched.h"
#include "condor_attributes.h"

#include "netinet/in.h"

extern "C" char * sin_to_string(struct sockaddr_in *);

template class HashTable<HashKey, ClassAd *>;
extern void parseIpPort (char *, char *, int &);

void HashKey::sprint (char *s)
{
	if (port != 0)
		sprintf (s, "< %s , %s , %d >", name, ip_addr, port);
	else
		sprintf (s, "< %s >", name);
}

bool operator== (HashKey &lhs, HashKey &rhs)
{
    return (lhs.port == rhs.port                &&
			strcmp (lhs.name, rhs.name) == 0    &&
			strcmp (lhs.ip_addr, rhs.ip_addr) == 0);
}

ostream &operator<< (ostream &out, const HashKey &hk)
{
	out << "Hashkey: (" << hk.name << "," << hk.ip_addr << "," << hk.port;
	out << ")" << endl;
	return out;
}

int hashFunction (HashKey &key, int numBuckets)
{
    unsigned int bkt = 0;
    int i;

    for (i = 0; key.name[i]   ; bkt += key.name[i++]);
    for (i = 0; key.ip_addr[i]; bkt += key.ip_addr[i++]);
    bkt += key.port;

    bkt %= numBuckets;

    return bkt;
}

int hashOnName (HashKey &key, int numBuckets)
{
	unsigned int bkt = 0;
	int i;

	for (i = 0; key.name [i]; bkt += key.name[i++]);
	bkt %= numBuckets;

	return bkt;
}

// functions to make the hashkeys ...
// make hashkeys from the obtained ad
bool
makeStartdAdHashKey (HashKey &hk, ClassAd *ad, sockaddr_in *from)
{
	ExprTree *tree;
	char buffer [30];
	char buf2   [64];

	// get the name of the startd
	if (!(tree = ad->Lookup ("Name")))
	{
		// ... if name was not specified
		dprintf(D_FULLDEBUG,"Warning: No 'Name' attribute; trying 'Machine'\n");
		tree = ad->Lookup ("Machine");
	}

	if (tree)
	{
		strcpy (hk.name, ((String *)tree->RArg())->Value());
	}
	else
	{
		// neither Name nor Machine specified in ad
		dprintf (D_ALWAYS, "Error: Neither 'Name' nor 'Machine' specified\n");
		return false;
	}

	// get the IP and port of the startd
	tree = ad->Lookup (ATTR_STARTD_IP_ADDR);
	if (tree)
	{
		strcpy (buffer, ((String *)tree->RArg())->Value());
	}
	else
	{
		dprintf (D_FULLDEBUG,"Warning: No STARTD_IP_ADDR; inferring address\n");
		strcpy (buffer, sin_to_string (from));

		// since we have done the work ...
		sprintf (buf2, "%s = \"%s\"", ATTR_STARTD_IP_ADDR, buffer);
		ad->Insert(buf2);
	}

	parseIpPort (buffer, hk.ip_addr, hk.port);

	return true;
}

bool
makeScheddAdHashKey (HashKey &hk, ClassAd *ad, sockaddr_in *from)
{
	ExprTree *tree;
	char buffer [30];
	char buf2   [64];

	// get the name of the startd
	if (!(tree = ad->Lookup ("Name")))
	{
		dprintf(D_FULLDEBUG,"Warning: No 'Name' attribute; trying 'Machine'\n");
		// ... if name was not specified
		tree = ad->Lookup ("Machine");
	}

	if (tree)
	{
		strcpy (hk.name, ((String *)tree->RArg())->Value());
	}
	else
	{
		dprintf (D_ALWAYS, "Error: Neither 'Name' nor 'Machine' specified\n");
		// neither Name nor Machine specified
		return false;
	}

	// get the IP and port of the startd
	tree = ad->Lookup (ATTR_SCHEDD_IP_ADDR);
	if (tree)
	{
		strcpy (buffer, ((String *)tree->RArg())->Value());
	}
	else
	{
		dprintf(D_FULLDEBUG,"Warning: No SCHEDD_IP_ADDR; inferring address\n");
		strcpy (buffer, sin_to_string (from));

        // since we have done the work ...
        sprintf (buf2, "%s = \"%s\"", ATTR_SCHEDD_IP_ADDR, buffer);
        ad->Insert(buf2);
	}

	parseIpPort (buffer, hk.ip_addr, hk.port);

	return true;
}

bool
makeMasterAdHashKey (HashKey &hk, ClassAd *ad, sockaddr_in *from)
{
	ExprTree *tree;

	tree = ad->Lookup ("Machine");
	if (tree)
	{
		strcpy (hk.name, ((String *)tree->RArg())->Value ());
	}
	else
	{
		dprintf (D_ALWAYS, "Error: No 'Machine' attribute\n");
		return false;
	}

	// ip_addr and port are not necessary
	hk.ip_addr [0] = '\0';
	hk.port = 0;

	return true;
}

bool
makeCkptSrvrAdHashKey (HashKey &hk, ClassAd *ad, sockaddr_in *from)
{
	if (!ad->LookupString ("Machine", hk.name))
	{
		dprintf (D_ALWAYS, "Error:  No 'Machine' attribute\n");
		return false;
	}

	hk.ip_addr[0] = '\0';
	hk.port = 0;

	return true;
}

// utility function:  parse the string <aaa.bbb.ccc.ddd:pppp>
void
parseIpPort (char *ip_port_pair, char *ip_addr, int &port)
{
    char *ip_port = ip_port_pair + 1;
    char *ip = ip_addr;
    while (*ip_port != ':')
    {
        *ip = *ip_port;
        ip++;
        ip_port++;
    }

    *ip = '\0';
    ip_port++;
    port = (int) strtol (ip_port, (char **)NULL, 10);
}

<commit_msg>Undid previous change from using ATTR_*_IP_ADDR, because the rest of daemons don't support this yet.<commit_after>#include <stdlib.h>

#include "condor_debug.h"
#include "condor_classad.h"
#pragma implementation "HashTable.h"
#include "HashTable.h"
#include "hashkey.h"
#include "sched.h"
#include "condor_attributes.h"

#include "netinet/in.h"

extern "C" char * sin_to_string(struct sockaddr_in *);

template class HashTable<HashKey, ClassAd *>;
extern void parseIpPort (char *, char *, int &);

void HashKey::sprint (char *s)
{
	if (port != 0)
		sprintf (s, "< %s , %s , %d >", name, ip_addr, port);
	else
		sprintf (s, "< %s >", name);
}

bool operator== (HashKey &lhs, HashKey &rhs)
{
    return (lhs.port == rhs.port                &&
			strcmp (lhs.name, rhs.name) == 0    &&
			strcmp (lhs.ip_addr, rhs.ip_addr) == 0);
}

ostream &operator<< (ostream &out, const HashKey &hk)
{
	out << "Hashkey: (" << hk.name << "," << hk.ip_addr << "," << hk.port;
	out << ")" << endl;
	return out;
}

int hashFunction (HashKey &key, int numBuckets)
{
    unsigned int bkt = 0;
    int i;

    for (i = 0; key.name[i]   ; bkt += key.name[i++]);
    for (i = 0; key.ip_addr[i]; bkt += key.ip_addr[i++]);
    bkt += key.port;

    bkt %= numBuckets;

    return bkt;
}

int hashOnName (HashKey &key, int numBuckets)
{
	unsigned int bkt = 0;
	int i;

	for (i = 0; key.name [i]; bkt += key.name[i++]);
	bkt %= numBuckets;

	return bkt;
}

// functions to make the hashkeys ...
// make hashkeys from the obtained ad
bool
makeStartdAdHashKey (HashKey &hk, ClassAd *ad, sockaddr_in *from)
{
	ExprTree *tree;
	char buffer [30];
	char buf2   [64];

	// get the name of the startd
	if (!(tree = ad->Lookup ("Name")))
	{
		// ... if name was not specified
		dprintf(D_FULLDEBUG,"Warning: No 'Name' attribute; trying 'Machine'\n");
		tree = ad->Lookup ("Machine");
	}

	if (tree)
	{
		strcpy (hk.name, ((String *)tree->RArg())->Value());
	}
	else
	{
		// neither Name nor Machine specified in ad
		dprintf (D_ALWAYS, "Error: Neither 'Name' nor 'Machine' specified\n");
		return false;
	}

	// get the IP and port of the startd
	tree = ad->Lookup ("STARTD_IP_ADDR");
	if (tree)
	{
		strcpy (buffer, ((String *)tree->RArg())->Value());
	}
	else
	{
		dprintf (D_FULLDEBUG,"Warning: No STARTD_IP_ADDR; inferring address\n");
		strcpy (buffer, sin_to_string (from));

		// since we have done the work ...
		sprintf (buf2, "%s = \"%s\"", "STARTD_IP_ADDR", buffer);
		ad->Insert(buf2);
	}

	parseIpPort (buffer, hk.ip_addr, hk.port);

	return true;
}

bool
makeScheddAdHashKey (HashKey &hk, ClassAd *ad, sockaddr_in *from)
{
	ExprTree *tree;
	char buffer [30];
	char buf2   [64];

	// get the name of the startd
	if (!(tree = ad->Lookup ("Name")))
	{
		dprintf(D_FULLDEBUG,"Warning: No 'Name' attribute; trying 'Machine'\n");
		// ... if name was not specified
		tree = ad->Lookup ("Machine");
	}

	if (tree)
	{
		strcpy (hk.name, ((String *)tree->RArg())->Value());
	}
	else
	{
		dprintf (D_ALWAYS, "Error: Neither 'Name' nor 'Machine' specified\n");
		// neither Name nor Machine specified
		return false;
	}

	// get the IP and port of the startd
	tree = ad->Lookup ("SCHEDD_IP_ADDR");
	if (tree)
	{
		strcpy (buffer, ((String *)tree->RArg())->Value());
	}
	else
	{
		dprintf(D_FULLDEBUG,"Warning: No SCHEDD_IP_ADDR; inferring address\n");
		strcpy (buffer, sin_to_string (from));

        // since we have done the work ...
        sprintf (buf2, "%s = \"%s\"", "SCHEDD_IP_ADDR", buffer);
        ad->Insert(buf2);
	}

	parseIpPort (buffer, hk.ip_addr, hk.port);

	return true;
}

bool
makeMasterAdHashKey (HashKey &hk, ClassAd *ad, sockaddr_in *from)
{
	ExprTree *tree;

	tree = ad->Lookup ("Machine");
	if (tree)
	{
		strcpy (hk.name, ((String *)tree->RArg())->Value ());
	}
	else
	{
		dprintf (D_ALWAYS, "Error: No 'Machine' attribute\n");
		return false;
	}

	// ip_addr and port are not necessary
	hk.ip_addr [0] = '\0';
	hk.port = 0;

	return true;
}

bool
makeCkptSrvrAdHashKey (HashKey &hk, ClassAd *ad, sockaddr_in *from)
{
	if (!ad->LookupString ("Machine", hk.name))
	{
		dprintf (D_ALWAYS, "Error:  No 'Machine' attribute\n");
		return false;
	}

	hk.ip_addr[0] = '\0';
	hk.port = 0;

	return true;
}

// utility function:  parse the string <aaa.bbb.ccc.ddd:pppp>
void
parseIpPort (char *ip_port_pair, char *ip_addr, int &port)
{
    char *ip_port = ip_port_pair + 1;
    char *ip = ip_addr;
    while (*ip_port != ':')
    {
        *ip = *ip_port;
        ip++;
        ip_port++;
    }

    *ip = '\0';
    ip_port++;
    port = (int) strtol (ip_port, (char **)NULL, 10);
}

<|endoftext|>


<commit_before>// Copyright 2010-2012 Google
// 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 <math.h>
#include <string.h>
#include <algorithm>
#include "base/hash.h"
#include <string>
#include <utility>
#include <vector>

#include "base/commandlineflags.h"
#include "base/hash.h"
#include "base/int-type-indexed-vector.h"
#include "base/int-type.h"
#include "base/integral_types.h"
#include "base/logging.h"
#include "base/map-util.h"
#include "base/scoped_ptr.h"
#include "base/stl_util.h"
#include "base/stringprintf.h"
#include "constraint_solver/constraint_solver.h"
#include "constraint_solver/constraint_solveri.h"
#include "util/bitset.h"
#include "util/const_int_array.h"

#include "core/Solver.cc"

namespace operations_research {
class SatPropagator : public Constraint {
 public:
  SatPropagator(Solver* const solver)
  : Constraint(solver),
    num_bound_literals_(0) {}

  ~SatPropagator() {}

  bool Check(IntExpr* const expr) const {
    IntVar* expr_var = NULL;
    bool expr_negated = false;
    return solver()->IsBooleanVar(expr, &expr_var, &expr_negated);
  }

  bool Check(const std::vector<IntVar*>& vars) const {
    for (int i = 0; i < vars.size(); ++i) {
      if (!Check(vars[i])) {
        return false;
      }
    }
    return true;
  }

  Minisat::Lit Literal(IntExpr* const expr) {
    IntVar* expr_var = NULL;
    bool expr_negated = false;
    if (!solver()->IsBooleanVar(expr, &expr_var, &expr_negated)) {
      return Minisat::lit_Error;
    }
    VLOG(1) << "SAT: Parse " << expr->DebugString() << " to "
            << expr_var->DebugString() << "/" << expr_negated;
    if (ContainsKey(indices_, expr_var)) {
      return Minisat::mkLit(indices_[expr_var], !expr_negated);
    } else {
      const Minisat::Var var = minisat_.newVar(true, true);
      vars_.push_back(expr_var);
      indices_[expr_var] = var;
      Minisat::Lit lit = Minisat::mkLit(var, !expr_negated);
      VLOG(1) << "  - created var = " << Minisat::toInt(var)
              << ", lit = " << Minisat::toInt(lit);
      return lit;
    }
  }

  void VariableBound(int index) {
    if (num_bound_literals_.Value() < minisat_.decisionLevel()) {
      minisat_.cancelUntil(num_bound_literals_.Value());
    }
    VLOG(1) << "VariableBound: " << vars_[index]->DebugString();
    Minisat::Var var(index);
    Minisat::lbool internal_value = minisat_.value(var);
    VLOG(1) << "  - internal value = " << toInt(internal_value);
    const bool var_value = vars_[index]->Value() != 0;
    if (toInt(internal_value) != 2) {  // not undefined.
      const bool b_value = (toInt(internal_value) == 1);  // == l_True
      if (var_value != b_value) {
        solver()->Fail();
      } else {
        return;
      }
    }
    Minisat::Lit lit = Minisat::mkLit(var, var_value);
    VLOG(1) <<  "  - enqueue lit = " << Minisat::toInt(lit);
    if (!minisat_.propagateOneLiteral(lit)) {
      VLOG(1) << "  - failure detected";
      solver()->Fail();
    } else {
      const int level = minisat_.decisionLevel();
      num_bound_literals_.SetValue(solver(), level);
      for (int i = 0; i < minisat_.touched_variables_.size(); ++i) {
        const Minisat::Lit lit = minisat_.touched_variables_[i];
        const int var = Minisat::var(lit);
        const bool assigned_bool = Minisat::sign(lit);
        VLOG(1) << "  - var " << var << " was assigned to " << assigned_bool;
        vars_[var]->SetValue(assigned_bool);
      }
    }
  }

  virtual void Post() {
    for (int i = 0; i < vars_.size(); ++i) {
      Demon* const d = MakeConstraintDemon1(solver(),
                                            this,
                                            &SatPropagator::VariableBound,
                                            "VariableBound",
                                            indices_[vars_[i]]);
      vars_[i]->WhenDomain(d);
    }
  }

  virtual void InitialPropagate() {
    minisat_.initPropagator();
    for (int i = 0; i < vars_.size(); ++i) {
      IntVar* const var = vars_[i];
      if (var->Bound()) {
        VariableBound(i);
      }
    }
  }

  // Add a clause to the solver.
  bool AddClause (const std::vector<Minisat::Lit>& lits) {
    return minisat_.addClause(lits);
  }

  // Add the empty clause, making the solver contradictory.
  bool AddEmptyClause() {
    return minisat_.addEmptyClause();
  }

  // Add a unit clause to the solver.
  bool AddClause (Minisat::Lit p) {
    return minisat_.addClause(p);
  }

  // Add a binary clause to the solver.
  bool AddClause (Minisat::Lit p, Minisat:: Lit q) {
    return minisat_.addClause(p, q);
  }

  // Add a ternary clause to the solver.
  bool AddClause (Minisat::Lit p, Minisat::Lit q, Minisat::Lit r) {
    return minisat_.addClause(p, q, r);
  }

 private:
  Minisat::Solver minisat_;
  std::vector<IntVar*> vars_;
  hash_map<IntVar*, Minisat::Var> indices_;
  std::vector<Minisat::Lit> bound_literals_;
  NumericalRev<int> num_bound_literals_;
};

bool AddBoolEq(SatPropagator* const sat,
               IntExpr* const left,
               IntExpr* const right) {
  if (!sat->Check(left) || !sat->Check(right)) {
    return false;
  }
  Minisat::Lit left_lit = sat->Literal(left);
  Minisat::Lit right_lit = sat->Literal(right);
  sat->AddClause(~left_lit, right_lit);
  sat->AddClause(left_lit, ~right_lit);
  return true;
}

bool AddBoolLe(SatPropagator* const sat,
               IntExpr* const left,
               IntExpr* const right) {
  if (!sat->Check(left) || !sat->Check(right)) {
    return false;
  }
  Minisat::Lit left_lit = sat->Literal(left);
  Minisat::Lit right_lit = sat->Literal(right);
  sat->AddClause(~left_lit, right_lit);
  return true;
}

bool AddBoolNot(SatPropagator* const sat,
                IntExpr* const left,
                IntExpr* const right) {
  if (!sat->Check(left) || !sat->Check(right)) {
    return false;
  }
  Minisat::Lit left_lit = sat->Literal(left);
  Minisat::Lit right_lit = sat->Literal(right);
  sat->AddClause(~left_lit, ~right_lit);
  sat->AddClause(left_lit, right_lit);
  return true;
}

bool AddBoolOrArrayEqVar(SatPropagator* const sat,
                         const std::vector<IntVar*>& vars,
                         IntExpr* const target) {
  if (!sat->Check(vars) || !sat->Check(target)) {
    return false;
  }
  Minisat::Lit target_lit = sat->Literal(target);
  std::vector<Minisat::Lit> lits(vars.size() + 1);
  for (int i = 0; i < vars.size(); ++i) {
    lits[i] = sat->Literal(vars[i]);
  }
  lits[vars.size()] = ~target_lit;
  sat->AddClause(lits);
  for (int i = 0; i < vars.size(); ++i) {
    sat->AddClause(target_lit, ~lits[i]);
  }
  return true;
}

bool AddBoolAndArrayEqVar(SatPropagator* const sat,
                          const std::vector<IntVar*>& vars,
                          IntExpr* const target) {
  if (!sat->Check(vars) || !sat->Check(target)) {
    return false;
  }
  Minisat::Lit target_lit = sat->Literal(target);
  std::vector<Minisat::Lit> lits(vars.size() + 1);
  for (int i = 0; i < vars.size(); ++i) {
    lits[i] = ~sat->Literal(vars[i]);
  }
  lits[vars.size()] = target_lit;
  sat->AddClause(lits);
  for (int i = 0; i < vars.size(); ++i) {
    sat->AddClause(~target_lit, ~lits[i]);
  }
  return true;
}

bool AddBoolOrEqVar(SatPropagator* const sat,
                    IntExpr* const left,
                    IntExpr* const right,
                    IntExpr* const target) {
  if (!sat->Check(left) || !sat->Check(right) || !sat->Check(target)) {
    return false;
  }
  Minisat::Lit left_lit = sat->Literal(left);
  Minisat::Lit right_lit = sat->Literal(right);
  Minisat::Lit target_lit = sat->Literal(target);
  sat->AddClause(left_lit, right_lit, ~target_lit);
  sat->AddClause(~left_lit, target_lit);
  sat->AddClause(~right_lit, target_lit);
  return true;
}

bool AddBoolAndEqVar(SatPropagator* const sat,
                     IntExpr* const left,
                     IntExpr* const right,
                     IntExpr* const target) {
  if (!sat->Check(left) || !sat->Check(right) || !sat->Check(target)) {
    return false;
  }
  Minisat::Lit left_lit = sat->Literal(left);
  Minisat::Lit right_lit = sat->Literal(right);
  Minisat::Lit target_lit = sat->Literal(target);
  sat->AddClause(~left_lit, ~right_lit, target_lit);
  sat->AddClause(left_lit, ~target_lit);
  sat->AddClause(right_lit, ~target_lit);
  return true;
}

bool AddBoolIsEqVar(SatPropagator* const sat,
                    IntExpr* const left,
                    IntExpr* const right,
                    IntExpr* const target) {
  if (!sat->Check(left) || !sat->Check(right) || !sat->Check(target)) {
    return false;
  }
  Minisat::Lit left_lit = sat->Literal(left);
  Minisat::Lit right_lit = sat->Literal(right);
  Minisat::Lit target_lit = sat->Literal(target);
  sat->AddClause(~left_lit, right_lit, ~target_lit);
  sat->AddClause(left_lit, ~right_lit, ~target_lit);
  sat->AddClause(left_lit, right_lit, target_lit);
  sat->AddClause(~left_lit, ~right_lit, target_lit);
  return true;
}

bool AddBoolIsNEqVar(SatPropagator* const sat,
                     IntExpr* const left,
                     IntExpr* const right,
                     IntExpr* const target) {
  if (!sat->Check(left) || !sat->Check(right) || !sat->Check(target)) {
    return false;
  }
  Minisat::Lit left_lit = sat->Literal(left);
  Minisat::Lit right_lit = sat->Literal(right);
  Minisat::Lit target_lit = sat->Literal(target);
  sat->AddClause(~left_lit, right_lit, target_lit);
  sat->AddClause(left_lit, ~right_lit, target_lit);
  sat->AddClause(left_lit, right_lit, ~target_lit);
  sat->AddClause(~left_lit, ~right_lit, ~target_lit);
  return true;
}

bool AddBoolOrArrayEqualTrue(SatPropagator* const sat,
                             const std::vector<IntVar*>& vars) {
  if (!sat->Check(vars)) {
    return false;
  }
  std::vector<Minisat::Lit> lits(vars.size());
  for (int i = 0; i < vars.size(); ++i) {
    lits[i] = sat->Literal(vars[i]);
  }
  sat->AddClause(lits);
  return true;
}

bool AddBoolAndArrayEqualFalse(SatPropagator* const sat,
                               const std::vector<IntVar*>& vars) {
  if (!sat->Check(vars)) {
    return false;
  }
  std::vector<Minisat::Lit> lits(vars.size());
  for (int i = 0; i < vars.size(); ++i) {
    lits[i] = ~sat->Literal(vars[i]);
  }
  sat->AddClause(lits);
  return true;
}

SatPropagator* MakeSatPropagator(Solver* const solver) {
  return solver->RevAlloc(new SatPropagator(solver));
}
}  // namespace operations_research
<commit_msg>speed up minisat connection<commit_after>// Copyright 2010-2012 Google
// 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 <math.h>
#include <string.h>
#include <algorithm>
#include "base/hash.h"
#include <string>
#include <utility>
#include <vector>

#include "base/commandlineflags.h"
#include "base/hash.h"
#include "base/int-type-indexed-vector.h"
#include "base/int-type.h"
#include "base/integral_types.h"
#include "base/logging.h"
#include "base/map-util.h"
#include "base/scoped_ptr.h"
#include "base/stl_util.h"
#include "base/stringprintf.h"
#include "constraint_solver/constraint_solver.h"
#include "constraint_solver/constraint_solveri.h"
#include "util/bitset.h"
#include "util/const_int_array.h"

#include "core/Solver.cc"

namespace operations_research {
class SatPropagator : public Constraint {
 public:
  SatPropagator(Solver* const solver)
  : Constraint(solver),
    num_bound_literals_(0) {}

  ~SatPropagator() {}

  bool Check(IntExpr* const expr) const {
    IntVar* expr_var = NULL;
    bool expr_negated = false;
    return solver()->IsBooleanVar(expr, &expr_var, &expr_negated);
  }

  bool Check(const std::vector<IntVar*>& vars) const {
    for (int i = 0; i < vars.size(); ++i) {
      if (!Check(vars[i])) {
        return false;
      }
    }
    return true;
  }

  Minisat::Lit Literal(IntExpr* const expr) {
    IntVar* expr_var = NULL;
    bool expr_negated = false;
    if (!solver()->IsBooleanVar(expr, &expr_var, &expr_negated)) {
      return Minisat::lit_Error;
    }
    VLOG(1) << "SAT: Parse " << expr->DebugString() << " to "
            << expr_var->DebugString() << "/" << expr_negated;
    if (ContainsKey(indices_, expr_var)) {
      return Minisat::mkLit(indices_[expr_var], !expr_negated);
    } else {
      const Minisat::Var var = minisat_.newVar(true, true);
      vars_.push_back(expr_var);
      indices_[expr_var] = var;
      Minisat::Lit lit = Minisat::mkLit(var, !expr_negated);
      VLOG(1) << "  - created var = " << Minisat::toInt(var)
              << ", lit = " << Minisat::toInt(lit);
      return lit;
    }
  }

  void VariableBound(int index) {
    if (num_bound_literals_.Value() < minisat_.decisionLevel()) {
      minisat_.cancelUntil(num_bound_literals_.Value());
    }
    VLOG(1) << "VariableBound: " << vars_[index]->DebugString();
    Minisat::Var var(index);
    Minisat::lbool internal_value = minisat_.value(var);
    VLOG(1) << "  - internal value = " << toInt(internal_value);
    const bool var_value = vars_[index]->Value() != 0;
    if (toInt(internal_value) != 2) {  // not undefined.
      const bool b_value = (toInt(internal_value) == 1);  // == l_True
      if (var_value != b_value) {
        solver()->Fail();
      } else {
        return;
      }
    }
    Minisat::Lit lit = Minisat::mkLit(var, var_value);
    VLOG(1) <<  "  - enqueue lit = " << Minisat::toInt(lit);
    if (!minisat_.propagateOneLiteral(lit)) {
      VLOG(1) << "  - failure detected";
      solver()->Fail();
    } else {
      const int level = minisat_.decisionLevel();
      num_bound_literals_.SetValue(solver(), level);
      for (int i = 0; i < minisat_.touched_variables_.size(); ++i) {
        const Minisat::Lit lit = minisat_.touched_variables_[i];
        const int var = Minisat::var(lit);
        const bool assigned_bool = Minisat::sign(lit);
        VLOG(1) << "  - var " << var << " was assigned to " << assigned_bool;
        demons_[var]->inhibit(solver());
        vars_[var]->SetValue(assigned_bool);
      }
    }
  }

  virtual void Post() {
    demons_.resize(vars_.size());
    for (int i = 0; i < vars_.size(); ++i) {
      demons_[i] = MakeConstraintDemon1(solver(),
                                        this,
                                        &SatPropagator::VariableBound,
                                        "VariableBound",
                                        indices_[vars_[i]]);
      vars_[i]->WhenDomain(demons_[i]);
    }
  }

  virtual void InitialPropagate() {
    minisat_.initPropagator();
    for (int i = 0; i < vars_.size(); ++i) {
      IntVar* const var = vars_[i];
      if (var->Bound()) {
        VariableBound(i);
      }
    }
  }

  // Add a clause to the solver.
  bool AddClause (const std::vector<Minisat::Lit>& lits) {
    return minisat_.addClause(lits);
  }

  // Add the empty clause, making the solver contradictory.
  bool AddEmptyClause() {
    return minisat_.addEmptyClause();
  }

  // Add a unit clause to the solver.
  bool AddClause (Minisat::Lit p) {
    return minisat_.addClause(p);
  }

  // Add a binary clause to the solver.
  bool AddClause (Minisat::Lit p, Minisat:: Lit q) {
    return minisat_.addClause(p, q);
  }

  // Add a ternary clause to the solver.
  bool AddClause (Minisat::Lit p, Minisat::Lit q, Minisat::Lit r) {
    return minisat_.addClause(p, q, r);
  }

 private:
  Minisat::Solver minisat_;
  std::vector<IntVar*> vars_;
  hash_map<IntVar*, Minisat::Var> indices_;
  std::vector<Minisat::Lit> bound_literals_;
  NumericalRev<int> num_bound_literals_;
  std::vector<Demon*> demons_;
};

bool AddBoolEq(SatPropagator* const sat,
               IntExpr* const left,
               IntExpr* const right) {
  if (!sat->Check(left) || !sat->Check(right)) {
    return false;
  }
  Minisat::Lit left_lit = sat->Literal(left);
  Minisat::Lit right_lit = sat->Literal(right);
  sat->AddClause(~left_lit, right_lit);
  sat->AddClause(left_lit, ~right_lit);
  return true;
}

bool AddBoolLe(SatPropagator* const sat,
               IntExpr* const left,
               IntExpr* const right) {
  if (!sat->Check(left) || !sat->Check(right)) {
    return false;
  }
  Minisat::Lit left_lit = sat->Literal(left);
  Minisat::Lit right_lit = sat->Literal(right);
  sat->AddClause(~left_lit, right_lit);
  return true;
}

bool AddBoolNot(SatPropagator* const sat,
                IntExpr* const left,
                IntExpr* const right) {
  if (!sat->Check(left) || !sat->Check(right)) {
    return false;
  }
  Minisat::Lit left_lit = sat->Literal(left);
  Minisat::Lit right_lit = sat->Literal(right);
  sat->AddClause(~left_lit, ~right_lit);
  sat->AddClause(left_lit, right_lit);
  return true;
}

bool AddBoolOrArrayEqVar(SatPropagator* const sat,
                         const std::vector<IntVar*>& vars,
                         IntExpr* const target) {
  if (!sat->Check(vars) || !sat->Check(target)) {
    return false;
  }
  Minisat::Lit target_lit = sat->Literal(target);
  std::vector<Minisat::Lit> lits(vars.size() + 1);
  for (int i = 0; i < vars.size(); ++i) {
    lits[i] = sat->Literal(vars[i]);
  }
  lits[vars.size()] = ~target_lit;
  sat->AddClause(lits);
  for (int i = 0; i < vars.size(); ++i) {
    sat->AddClause(target_lit, ~lits[i]);
  }
  return true;
}

bool AddBoolAndArrayEqVar(SatPropagator* const sat,
                          const std::vector<IntVar*>& vars,
                          IntExpr* const target) {
  if (!sat->Check(vars) || !sat->Check(target)) {
    return false;
  }
  Minisat::Lit target_lit = sat->Literal(target);
  std::vector<Minisat::Lit> lits(vars.size() + 1);
  for (int i = 0; i < vars.size(); ++i) {
    lits[i] = ~sat->Literal(vars[i]);
  }
  lits[vars.size()] = target_lit;
  sat->AddClause(lits);
  for (int i = 0; i < vars.size(); ++i) {
    sat->AddClause(~target_lit, ~lits[i]);
  }
  return true;
}

bool AddBoolOrEqVar(SatPropagator* const sat,
                    IntExpr* const left,
                    IntExpr* const right,
                    IntExpr* const target) {
  if (!sat->Check(left) || !sat->Check(right) || !sat->Check(target)) {
    return false;
  }
  Minisat::Lit left_lit = sat->Literal(left);
  Minisat::Lit right_lit = sat->Literal(right);
  Minisat::Lit target_lit = sat->Literal(target);
  sat->AddClause(left_lit, right_lit, ~target_lit);
  sat->AddClause(~left_lit, target_lit);
  sat->AddClause(~right_lit, target_lit);
  return true;
}

bool AddBoolAndEqVar(SatPropagator* const sat,
                     IntExpr* const left,
                     IntExpr* const right,
                     IntExpr* const target) {
  if (!sat->Check(left) || !sat->Check(right) || !sat->Check(target)) {
    return false;
  }
  Minisat::Lit left_lit = sat->Literal(left);
  Minisat::Lit right_lit = sat->Literal(right);
  Minisat::Lit target_lit = sat->Literal(target);
  sat->AddClause(~left_lit, ~right_lit, target_lit);
  sat->AddClause(left_lit, ~target_lit);
  sat->AddClause(right_lit, ~target_lit);
  return true;
}

bool AddBoolIsEqVar(SatPropagator* const sat,
                    IntExpr* const left,
                    IntExpr* const right,
                    IntExpr* const target) {
  if (!sat->Check(left) || !sat->Check(right) || !sat->Check(target)) {
    return false;
  }
  Minisat::Lit left_lit = sat->Literal(left);
  Minisat::Lit right_lit = sat->Literal(right);
  Minisat::Lit target_lit = sat->Literal(target);
  sat->AddClause(~left_lit, right_lit, ~target_lit);
  sat->AddClause(left_lit, ~right_lit, ~target_lit);
  sat->AddClause(left_lit, right_lit, target_lit);
  sat->AddClause(~left_lit, ~right_lit, target_lit);
  return true;
}

bool AddBoolIsNEqVar(SatPropagator* const sat,
                     IntExpr* const left,
                     IntExpr* const right,
                     IntExpr* const target) {
  if (!sat->Check(left) || !sat->Check(right) || !sat->Check(target)) {
    return false;
  }
  Minisat::Lit left_lit = sat->Literal(left);
  Minisat::Lit right_lit = sat->Literal(right);
  Minisat::Lit target_lit = sat->Literal(target);
  sat->AddClause(~left_lit, right_lit, target_lit);
  sat->AddClause(left_lit, ~right_lit, target_lit);
  sat->AddClause(left_lit, right_lit, ~target_lit);
  sat->AddClause(~left_lit, ~right_lit, ~target_lit);
  return true;
}

bool AddBoolOrArrayEqualTrue(SatPropagator* const sat,
                             const std::vector<IntVar*>& vars) {
  if (!sat->Check(vars)) {
    return false;
  }
  std::vector<Minisat::Lit> lits(vars.size());
  for (int i = 0; i < vars.size(); ++i) {
    lits[i] = sat->Literal(vars[i]);
  }
  sat->AddClause(lits);
  return true;
}

bool AddBoolAndArrayEqualFalse(SatPropagator* const sat,
                               const std::vector<IntVar*>& vars) {
  if (!sat->Check(vars)) {
    return false;
  }
  std::vector<Minisat::Lit> lits(vars.size());
  for (int i = 0; i < vars.size(); ++i) {
    lits[i] = ~sat->Literal(vars[i]);
  }
  sat->AddClause(lits);
  return true;
}

SatPropagator* MakeSatPropagator(Solver* const solver) {
  return solver->RevAlloc(new SatPropagator(solver));
}
}  // namespace operations_research
<|endoftext|>