<commit_before>/*
 * gameMgr.cpp
 *
 *  Created on: Mar 11, 2017
 *      Author: sushil
 */

#include <gameMgr.h>
#include <engine.h>
#include <OgreMeshManager.h>

GameMgr::GameMgr(Engine *engine): Mgr(engine), entitySceneNodes(){
	floor = Ogre::Plane(Ogre::Vector3::UNIT_Y, 0);
    ceiling = new Ogre::MovablePlane("ceiling");
    ceiling->d = 0;
    ceiling->normal = -1 * Ogre::Vector3::UNIT_Y;
    gameplayTime = 0;
    entityCount = 0;
}

GameMgr::~GameMgr(){

}

void GameMgr::init(){

}

void GameMgr::loadLevel(){
	this->loadLevel("level001.txt");

}

void GameMgr::stop(){

}

void GameMgr::tick(float dt){
	//engine->gfxMgr->ogreAnimationState->addTime(dt);
	if(engine->theState == STATE::GAMEPLAY)
	{
		gameplayTime += dt;
		std::cout << "Gameplay time: " << gameplayTime << std::endl;
	}
}

void GameMgr::createGround(int width, int heigth, std::string &material)
{
	// Create Plane //////////////////////////////////////////////////////////////////////////////////////////
	Ogre::MeshManager::getSingleton().createPlane(
	    "ground",
	    Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
	    floor,
		width, heigth, 20, 20,
	    true,
	    1, 5, 5,
	    Ogre::Vector3::UNIT_Z);
	//////////////////////////////////////////////////////////////////////////////////////////////////////////

	// Create Ground Entity //////////////////////////////////////////////////////////////////////////////////
	Ogre::Entity* groundEntity = engine->gfxMgr->ogreSceneManager->createEntity("ground");
	engine->gfxMgr->ogreSceneManager->getRootSceneNode()->createChildSceneNode()->attachObject(groundEntity);
	groundEntity->setCastShadows(false);
	groundEntity->setMaterialName(material);
	//////////////////////////////////////////////////////////////////////////////////////////////////////////

	// Create Separated Water Ground ////////////////////////////////////////////////////////////////////////
	Ogre::Entity* groundEntity2 = engine->gfxMgr->ogreSceneManager->createEntity("ground");
	engine->gfxMgr->ogreSceneManager->getRootSceneNode()->createChildSceneNode()->attachObject(groundEntity2);
	groundEntity2->setCastShadows(false);
	groundEntity2->setMaterialName("Examples/WaterStream");
	//////////////////////////////////////////////////////////////////////////////////////////////////////////
}

void GameMgr::createCeiling()
{
	Ogre::MovablePlane plane(-Ogre::Vector3::UNIT_Y, 100);

	// Create Ceiling ///////////////////////////////////////////////////////////////////////////////////////
	Ogre::MeshManager::getSingleton().createPlane(
	    "ceiling",
	    Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
		plane,
		4000, 3400, 20, 20,
	    true,
	    1, 5, 5,
	    Ogre::Vector3::UNIT_Z);
	//////////////////////////////////////////////////////////////////////////////////////////////////////////

	// Create Ceiling Entity //////////////////////////////////////////////////////////////////////////////////
	Ogre::Entity* ceiling = engine->gfxMgr->ogreSceneManager->createEntity("ceiling");
	engine->gfxMgr->ogreSceneManager->getRootSceneNode()->createChildSceneNode()->attachObject(ceiling);
	ceiling->setCastShadows(false);
	ceiling->setMaterialName("Examples/Rockwall");
}

void GameMgr::createSky(){

	engine->gfxMgr->ogreSceneManager->setSkyBox(true, "Examples/SpaceSkyBox");

}

void GameMgr::loadLevel(std::string levelFilename)
{
	// Load the environment, objects, and characters
	this->loadEnvironment(levelFilename);
	this->setupEnvironment();
	this->setupSounds();
	this->loadObjects();
	this->loadCharacters();
}

void GameMgr::loadEnvironment(std::string levelFilename)
{
	// Variables
	std::ifstream fin;
	int x, z;
	float x_offset, y_offset, z_offset;
	float scale, orientation;
	std::string groundMaterial, objectMesh, characterMesh;
	std::string buffer, buff;
	char objectChar;
	std::map<std::string, readFromFile*> objects;

	// Open File
	fin.open(levelFilename);

	// Check for bad file
	if(!fin.is_open())
	{
		std::cerr << "ERROR, FILE CANNOT BE OPENED" << std::endl;
		return;
	}

	// First block is world dimensions and material name
	fin >> x >> z;
	fin >> groundMaterial;

	// TESTING FILE READ ////////////////////////////////////////////
	std::cerr << "Ground Dimensions: " << x << " x " << z << std::endl;
	std::cerr << "Ground Material: " << groundMaterial << std::endl;
	/////////////////////////////////////////////////////////////////

	// Create floor mesh with read in dimensions
	createGround( x*100, z*100, groundMaterial);

	// Create Ceiling
	createCeiling(); //DEBUG THIS LATER

	// Setup the grid
	this->grid = new Grid( engine->gfxMgr->ogreSceneManager, x, z, engine);

	// Second block reads in location of you and enemies
	// Check for Objects line
	fin >> buffer;

	if( buffer != "Objects" )
	{
		std::cerr << "FILE NOT FORMATTED CORRECTLY" << std::endl;
	}

	// Read Objects and positions
	readFromFile* readEnt = new readFromFile();

	fin >> buff; // read single char

	fin >> readEnt->mesh;
	fin >> x_offset >> y_offset >> z_offset;
	fin >> readEnt->entityOrientation >> readEnt->entityScale;

	// Set entity info
	readEnt->positionOffset = Ogre::Vector3(x_offset, y_offset, z_offset);
	readEnt->entity = false;
	objects[buff] = readEnt;

	readEnt = new readFromFile(); // read in next if any

	// Testing Second Box Readin ///////////////////////////////////
	std::cerr << "Objects" << std::endl;
	std::cerr << objectChar << " " << objectMesh << std::endl;
	std::cerr << "Located at: " << x_offset << ", " << y_offset << ", " << z_offset << std::endl;
	std::cerr << "Scaled at: " << orientation << " " << scale << std::endl;
	///////////////////////////////////////////////////////////////

	// Check for Characters line /////////////////////////////////////////////////////////////////
	fin >> buffer;

	if( buffer != "Characters" )
	{
		std::cerr << "FILE NOT FORMATTED CORRECTLY" << std::endl;
	}

	// Read in Characters

	fin >> buff; // read next char

	fin >> readEnt->mesh;
	fin >> x_offset >> y_offset >> z_offset;
	fin >> readEnt->entityOrientation >> readEnt->entityScale;

	// set entity info
	readEnt->positionOffset = Ogre::Vector3(x_offset, y_offset, z_offset);
	readEnt->entity = true;
	objects[buff] = readEnt;

	// read next if any
	readEnt = new readFromFile();

	// Testing Third Box Readin ///////////////////////////////////
	std::cerr << "Characters" << std::endl;
	std::cerr << objectChar << " " << characterMesh << std::endl;
	std::cerr << "Located at: " << x_offset << ", " << y_offset << ", " << z_offset << std::endl;
	std::cerr << "Scaled at: " << orientation << " " << scale << std::endl;
	///////////////////////////////////////////////////////////////

	// Read the World Placement //////////////////////////////////////////////////////////////////
	char c;

	// Start to see if world is in file
	fin >> buffer;

	if( buffer != "World" )
	{
		std::cerr << "FILE NOT FORMATTED CORRECTLY" << std::endl;
	}

	// Pre Conditions for World setup
	Ogre::Vector3 wallPosition;
	wallPosition = Ogre::Vector3(-1850, 50, 1200);

	Ogre::Vector3 archPosition;
	archPosition = Ogre::Vector3(0, 0, 0);

	Ogre::Vector3 enemyPosition;
	enemyPosition = Ogre::Vector3(-1200, 0, 1000);

	// Loop through map dimensions
	for( int row = 0; row < ROW_SIZE - 3; row++ )
	{
		for( int col = 0; col < COL_SIZE - 3; col++ )
		{
			fin >> c;

			Ogre::Vector3 gridPositionInWorld = this->grid->getPosition(row, col);

			// Check for walls (Not player or enemy nodes)
			if( c == 'W' )
			{

				// Grab the "objects" config stuff from the object map that Hadi built
				readFromFile * objectEntData = objects["D"]; // Currently not used lmao

				GridParams * gridParam =  this->grid->getGrid(row, col);
				if(gridParam) gridParam->notWalkable();

				engine->entityMgr->CreateEntity(EntityType::WALL, gridPositionInWorld, 0);

				objectEntData = NULL;
				gridParam = NULL;
			}

			// Check for Arch
			else if( c == 'A' )
			{
//				std::cerr << "Spawning Arch" << std::endl;
//				engine->entityMgr->CreateEntity(EntityType::ARCH, archPosition, 0);
//				archPosition.x += 50;

			}

			// See no evil
			else if( c == 'C' )
			{
				engine->entityMgr->CreateEntity(EntityType::SEENO, gridPositionInWorld, 0);
			}

			else if(c == 'S')
			{
				engine->entityMgr->CreateEntity(EntityType::SPEAKNO, gridPositionInWorld, 0);
			}
			else if(c == 'H')
			{
				engine->entityMgr->CreateEntity(EntityType::HEARNO, gridPositionInWorld, 0);
			}
		}
	}

	// Create the Entities

	// Create Skybox for the hell of it
	createSky();
//	delete readEnt;
}

void GameMgr::setupEnvironment()
{
	//We know graphicsMgr is ready and initialized
	engine->gfxMgr->ogreSceneManager->setAmbientLight(Ogre::ColourValue(0.3, 0.3, 0.3));
	Ogre::Light* light = engine->gfxMgr->ogreSceneManager->createLight("MainLight");
	light->setType(Ogre::Light::LT_POINT);
	light->setPosition(100.0, 800.0, 100.0);
	light->setDiffuseColour(Ogre::ColourValue::White);
	light->setSpecularColour(Ogre::ColourValue::White);
}

/*
 *
 * Basic Setup for pre-alpha testing
 * Will be more complex in later phases
 *
 */
void GameMgr::setupSounds()
{
	// Load Song from file
	engine->soundMgr->load_song("Layer 1", "/home/hrumjahn/git/Cries/resources/ss.wav");
	//load_sound(std::string soundName, std::string filePath);

	//play_sound(std::string soundName);
	engine->soundMgr->play_song("Layer 1", true);

	// Play song (.wav)
}

void GameMgr::loadObjects()
{
	// Create Entity
	Ogre::Entity *splash = engine->gfxMgr->ogreSceneManager->createEntity("Splash.mesh");

	// Create scene node for this entity
	engine->gfxMgr->splashNode = engine->gfxMgr->ogreSceneManager->getRootSceneNode()->createChildSceneNode();
	engine->gfxMgr->splashNode->attachObject(splash);
	splash->setMaterialName("Material");
	engine->gfxMgr->splashNode->setScale(10.f, 10.0f, 10.0f);
	engine->gfxMgr->splashNode->setPosition( 0.0f, 400, -3500);
	engine->gfxMgr->splashNode->roll(Ogre::Degree(-360));
	engine->gfxMgr->splashNode->pitch(Ogre::Degree(90));
}

void GameMgr::loadCharacters()
{
	//Creating the entities
//	engine->entityMgr->CreateEntity(EntityType::HEARNO, Ogre::Vector3(0, 10, -1000), 0);
//	engine->entityMgr->CreateEntity(EntityType::SEENO, Ogre::Vector3(500, 0, -500), Ogre::Math::HALF_PI / 2);
//	engine->entityMgr->CreateEntity(EntityType::SPEAKNO, Ogre::Vector3(-500, 20, -500), Ogre::Math::HALF_PI / -2);
/*
	// Set Animation States
	//engine->gfxMgr->ogreAnimationState = splash->getAnimationState("Test");
	engine->gfxMgr->ogreAnimationState->setWeight(1);
	engine->gfxMgr->ogreAnimationState->setLoop(true);
	engine->gfxMgr->ogreAnimationState->setEnabled(true);
*/

}

std::string GameMgr:: getNewName()
{

	return std::string("object_" + std::to_string(entityCount++));
}

<commit_msg>Created a ceiling<commit_after>/*
 * gameMgr.cpp
 *
 *  Created on: Mar 11, 2017
 *      Author: sushil
 */

#include <gameMgr.h>
#include <engine.h>
#include <OgreMeshManager.h>

GameMgr::GameMgr(Engine *engine): Mgr(engine), entitySceneNodes(){
	floor = Ogre::Plane(Ogre::Vector3::UNIT_Y, 0);
    ceiling = new Ogre::MovablePlane("ceiling");
    ceiling->d = 0;
    ceiling->normal = -1 * Ogre::Vector3::UNIT_Y;
    gameplayTime = 0;
    entityCount = 0;
}

GameMgr::~GameMgr(){

}

void GameMgr::init(){

}

void GameMgr::loadLevel(){
	this->loadLevel("level001.txt");

}

void GameMgr::stop(){

}

void GameMgr::tick(float dt){
	//engine->gfxMgr->ogreAnimationState->addTime(dt);
	if(engine->theState == STATE::GAMEPLAY)
	{
		gameplayTime += dt;
		std::cout << "Gameplay time: " << gameplayTime << std::endl;
	}
}

void GameMgr::createGround(int width, int heigth, std::string &material)
{
	// Create Plane //////////////////////////////////////////////////////////////////////////////////////////
	Ogre::MeshManager::getSingleton().createPlane(
	    "ground",
	    Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
	    floor,
		width, heigth, 20, 20,
	    true,
	    1, 5, 5,
	    Ogre::Vector3::UNIT_Z);
	//////////////////////////////////////////////////////////////////////////////////////////////////////////

	// Create Ground Entity //////////////////////////////////////////////////////////////////////////////////
	Ogre::Entity* groundEntity = engine->gfxMgr->ogreSceneManager->createEntity("ground");
	engine->gfxMgr->ogreSceneManager->getRootSceneNode()->createChildSceneNode()->attachObject(groundEntity);
	groundEntity->setCastShadows(false);
	groundEntity->setMaterialName(material);
	//////////////////////////////////////////////////////////////////////////////////////////////////////////

	// Create Separated Water Ground ////////////////////////////////////////////////////////////////////////
	Ogre::Entity* groundEntity2 = engine->gfxMgr->ogreSceneManager->createEntity("ground");
	engine->gfxMgr->ogreSceneManager->getRootSceneNode()->createChildSceneNode()->attachObject(groundEntity2);
	groundEntity2->setCastShadows(false);
	groundEntity2->setMaterialName("Examples/WaterStream");
	//////////////////////////////////////////////////////////////////////////////////////////////////////////
}

void GameMgr::createCeiling()
{
	Ogre::Plane plane(-Ogre::Vector3::UNIT_Y, -100);

	// Create Ceiling ///////////////////////////////////////////////////////////////////////////////////////
	Ogre::MeshManager::getSingleton().createPlane(
	    "ceiling",
	    Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
		plane,
		4000, 3400, 20, 20,
	    true,
	    1, 5, 5,
	    Ogre::Vector3::UNIT_Z);
	//////////////////////////////////////////////////////////////////////////////////////////////////////////

	// Create Ceiling Entity //////////////////////////////////////////////////////////////////////////////////
	Ogre::Entity* ceiling = engine->gfxMgr->ogreSceneManager->createEntity("ceiling");
	engine->gfxMgr->ogreSceneManager->getRootSceneNode()->createChildSceneNode()->attachObject(ceiling);
	ceiling->setCastShadows(false);
	ceiling->setMaterialName("Examples/Rockwall");
}

void GameMgr::createSky(){

	engine->gfxMgr->ogreSceneManager->setSkyBox(true, "Examples/SpaceSkyBox");

}

void GameMgr::loadLevel(std::string levelFilename)
{
	// Load the environment, objects, and characters
	this->loadEnvironment(levelFilename);
	this->setupEnvironment();
	this->setupSounds();
	this->loadObjects();
	this->loadCharacters();
}

void GameMgr::loadEnvironment(std::string levelFilename)
{
	// Variables
	std::ifstream fin;
	int x, z;
	float x_offset, y_offset, z_offset;
	float scale, orientation;
	std::string groundMaterial, objectMesh, characterMesh;
	std::string buffer, buff;
	char objectChar;
	std::map<std::string, readFromFile*> objects;

	// Open File
	fin.open(levelFilename);

	// Check for bad file
	if(!fin.is_open())
	{
		std::cerr << "ERROR, FILE CANNOT BE OPENED" << std::endl;
		return;
	}

	// First block is world dimensions and material name
	fin >> x >> z;
	fin >> groundMaterial;

	// TESTING FILE READ ////////////////////////////////////////////
	std::cerr << "Ground Dimensions: " << x << " x " << z << std::endl;
	std::cerr << "Ground Material: " << groundMaterial << std::endl;
	/////////////////////////////////////////////////////////////////

	// Create floor mesh with read in dimensions
	createGround( x*100, z*100, groundMaterial);

	// Create Ceiling
	createCeiling(); //DEBUG THIS LATER

	// Setup the grid
	this->grid = new Grid( engine->gfxMgr->ogreSceneManager, x, z, engine);

	// Second block reads in location of you and enemies
	// Check for Objects line
	fin >> buffer;

	if( buffer != "Objects" )
	{
		std::cerr << "FILE NOT FORMATTED CORRECTLY" << std::endl;
	}

	// Read Objects and positions
	readFromFile* readEnt = new readFromFile();

	fin >> buff; // read single char

	fin >> readEnt->mesh;
	fin >> x_offset >> y_offset >> z_offset;
	fin >> readEnt->entityOrientation >> readEnt->entityScale;

	// Set entity info
	readEnt->positionOffset = Ogre::Vector3(x_offset, y_offset, z_offset);
	readEnt->entity = false;
	objects[buff] = readEnt;

	readEnt = new readFromFile(); // read in next if any

	// Testing Second Box Readin ///////////////////////////////////
	std::cerr << "Objects" << std::endl;
	std::cerr << objectChar << " " << objectMesh << std::endl;
	std::cerr << "Located at: " << x_offset << ", " << y_offset << ", " << z_offset << std::endl;
	std::cerr << "Scaled at: " << orientation << " " << scale << std::endl;
	///////////////////////////////////////////////////////////////

	// Check for Characters line /////////////////////////////////////////////////////////////////
	fin >> buffer;

	if( buffer != "Characters" )
	{
		std::cerr << "FILE NOT FORMATTED CORRECTLY" << std::endl;
	}

	// Read in Characters

	fin >> buff; // read next char

	fin >> readEnt->mesh;
	fin >> x_offset >> y_offset >> z_offset;
	fin >> readEnt->entityOrientation >> readEnt->entityScale;

	// set entity info
	readEnt->positionOffset = Ogre::Vector3(x_offset, y_offset, z_offset);
	readEnt->entity = true;
	objects[buff] = readEnt;

	// read next if any
	readEnt = new readFromFile();

	// Testing Third Box Readin ///////////////////////////////////
	std::cerr << "Characters" << std::endl;
	std::cerr << objectChar << " " << characterMesh << std::endl;
	std::cerr << "Located at: " << x_offset << ", " << y_offset << ", " << z_offset << std::endl;
	std::cerr << "Scaled at: " << orientation << " " << scale << std::endl;
	///////////////////////////////////////////////////////////////

	// Read the World Placement //////////////////////////////////////////////////////////////////
	char c;

	// Start to see if world is in file
	fin >> buffer;

	if( buffer != "World" )
	{
		std::cerr << "FILE NOT FORMATTED CORRECTLY" << std::endl;
	}

	// Pre Conditions for World setup
	Ogre::Vector3 wallPosition;
	wallPosition = Ogre::Vector3(-1850, 50, 1200);

	Ogre::Vector3 archPosition;
	archPosition = Ogre::Vector3(0, 0, 0);

	Ogre::Vector3 enemyPosition;
	enemyPosition = Ogre::Vector3(-1200, 0, 1000);

	// Loop through map dimensions
	for( int row = 0; row < ROW_SIZE - 3; row++ )
	{
		for( int col = 0; col < COL_SIZE - 3; col++ )
		{
			fin >> c;

			Ogre::Vector3 gridPositionInWorld = this->grid->getPosition(row, col);

			// Check for walls (Not player or enemy nodes)
			if( c == 'W' )
			{

				// Grab the "objects" config stuff from the object map that Hadi built
				readFromFile * objectEntData = objects["D"]; // Currently not used lmao

				GridParams * gridParam =  this->grid->getGrid(row, col);
				if(gridParam) gridParam->notWalkable();

				engine->entityMgr->CreateEntity(EntityType::WALL, gridPositionInWorld, 0);

				objectEntData = NULL;
				gridParam = NULL;
			}

			// Check for Arch
			else if( c == 'A' )
			{
//				std::cerr << "Spawning Arch" << std::endl;
//				engine->entityMgr->CreateEntity(EntityType::ARCH, archPosition, 0);
//				archPosition.x += 50;

			}

			// See no evil
			else if( c == 'C' )
			{
				engine->entityMgr->CreateEntity(EntityType::SEENO, gridPositionInWorld, 0);
			}

			else if(c == 'S')
			{
				engine->entityMgr->CreateEntity(EntityType::SPEAKNO, gridPositionInWorld, 0);
			}
			else if(c == 'H')
			{
				engine->entityMgr->CreateEntity(EntityType::HEARNO, gridPositionInWorld, 0);
			}
		}
	}

	// Create the Entities

	// Create Skybox for the hell of it
	createSky();
//	delete readEnt;
}

void GameMgr::setupEnvironment()
{
	//We know graphicsMgr is ready and initialized
	engine->gfxMgr->ogreSceneManager->setAmbientLight(Ogre::ColourValue(0.3, 0.3, 0.3));
	Ogre::Light* light = engine->gfxMgr->ogreSceneManager->createLight("MainLight");
	light->setType(Ogre::Light::LT_POINT);
	light->setPosition(100.0, 800.0, 100.0);
	light->setDiffuseColour(Ogre::ColourValue::White);
	light->setSpecularColour(Ogre::ColourValue::White);
}

/*
 *
 * Basic Setup for pre-alpha testing
 * Will be more complex in later phases
 *
 */
void GameMgr::setupSounds()
{
	// Load Song from file
	engine->soundMgr->load_song("Layer 1", "/home/hrumjahn/git/Cries/resources/ss.wav");
	//load_sound(std::string soundName, std::string filePath);

	//play_sound(std::string soundName);
	engine->soundMgr->play_song("Layer 1", true);

	// Play song (.wav)
}

void GameMgr::loadObjects()
{
	// Create Entity
	Ogre::Entity *splash = engine->gfxMgr->ogreSceneManager->createEntity("Splash.mesh");

	// Create scene node for this entity
	engine->gfxMgr->splashNode = engine->gfxMgr->ogreSceneManager->getRootSceneNode()->createChildSceneNode();
	engine->gfxMgr->splashNode->attachObject(splash);
	splash->setMaterialName("Material");
	engine->gfxMgr->splashNode->setScale(10.f, 10.0f, 10.0f);
	engine->gfxMgr->splashNode->setPosition( 0.0f, 400, -3500);
	engine->gfxMgr->splashNode->roll(Ogre::Degree(-360));
	engine->gfxMgr->splashNode->pitch(Ogre::Degree(90));
}

void GameMgr::loadCharacters()
{
	//Creating the entities
//	engine->entityMgr->CreateEntity(EntityType::HEARNO, Ogre::Vector3(0, 10, -1000), 0);
//	engine->entityMgr->CreateEntity(EntityType::SEENO, Ogre::Vector3(500, 0, -500), Ogre::Math::HALF_PI / 2);
//	engine->entityMgr->CreateEntity(EntityType::SPEAKNO, Ogre::Vector3(-500, 20, -500), Ogre::Math::HALF_PI / -2);
/*
	// Set Animation States
	//engine->gfxMgr->ogreAnimationState = splash->getAnimationState("Test");
	engine->gfxMgr->ogreAnimationState->setWeight(1);
	engine->gfxMgr->ogreAnimationState->setLoop(true);
	engine->gfxMgr->ogreAnimationState->setEnabled(true);
*/

}

std::string GameMgr:: getNewName()
{

	return std::string("object_" + std::to_string(entityCount++));
}

<|endoftext|>


<commit_before>#include <string>
#include <vector>

namespace gen {

bool is_integer(const std::string &s);

/*
 * Hostname, ipv4, or ipv6.
 * Returns an empty string on success,
 * non-empty on failure.
 */
std::string valid_addr(const std::string &addr);

/* Split a string into count(c) parts, return all tokens in an array. */
typedef std::vector<std::string> tokens_t;
tokens_t split_string(const std::string &str, const std::string &c);

}
<commit_msg>Add newline at EOF<commit_after>#include <string>
#include <vector>

namespace gen {

bool is_integer(const std::string &s);

/*
 * Hostname, ipv4, or ipv6.
 * Returns an empty string on success,
 * non-empty on failure.
 */
std::string valid_addr(const std::string &addr);

/* Split a string into count(c) parts, return all tokens in an array. */
typedef std::vector<std::string> tokens_t;
tokens_t split_string(const std::string &str, const std::string &c);

}

<|endoftext|>


<commit_before>// Simple keogram composition program using OpenCV
// Copyright 2018 Jarno Paananen <jarno.paananen@gmail.com>
// Based on a script by Thomas Jacquin
// Rotation added by Agustin Nunez @agnunez
// SPDX-License-Identifier: MIT

#include <getopt.h>
#include <glob.h>
#include <stdio.h>
#include <sys/stat.h>
#include <cstdlib>
#include <iostream>
#include <string>
#include <vector>

#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/opencv.hpp>

#define KNRM "\x1B[0m"
#define KRED "\x1B[31m"
#define KGRN "\x1B[32m"
#define KYEL "\x1B[33m"
#define KBLU "\x1B[34m"
#define KMAG "\x1B[35m"
#define KCYN "\x1B[36m"
#define KWHT "\x1B[37m"

//-------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------
int loglevel = 0;

void usage_and_exit(int x) {
  std::cout
      << "Usage:\tkeogram -d <imagedir> -e <ext> -o <outputfile> [<other_args>]"
      << std::endl;
  if (x)
    std::cout
        << KRED
        << "Source directory, image extension, and output file are required"
        << std::endl;

  std::cout << KNRM << std::endl;
  std::cout << "Arguments:" << std::endl;
  std::cout << "-d | --directory <str> : directory from which to load images "
               "(required)"
            << std::endl;
  std::cout << "-e | --extension <str> : image extension to process (required)"
            << std::endl;
  std::cout << "-o | --output-file <str> : name of output file (required)"
            << std::endl;
  std::cout << "-r | --rotate <float> : number of degrees to rotate image, "
               "counterclockwise (0)"
            << std::endl;
  std::cout << "-s | --image-size <int>x<int> : only process images of a given "
               "size, eg. 1280x960"
            << std::endl;
  std::cout << "-h | --help : display this help message" << std::endl;
  std::cout << "-v | --verbose : Increase logging verbosity" << std::endl;
  std::cout << "-n | --no-label : Disable hour labels" << std::endl;
  std::cout
      << "-C | --font-color <str> : label font color, in HTML format (0000ff)"
      << std::endl;
  std::cout << "-L | --font-line <int> : font line thickness (3)" << std::endl;
  std::cout << "-N | --font-name <str> : font name (simplex)" << std::endl;
  std::cout << "-S | --font-side <float> : font size (2.0)" << std::endl;
  std::cout << "-T | --font-type <int> : font line type (1)" << std::endl;

  std::cout << KNRM << std::endl;
  std::cout
      << "Font name is one of these OpenCV font names:\n\tSimplex, Plain, "
         "Duplex, Complex, Triplex, ComplexSmall, ScriptSimplex, ScriptComplex"
      << std::endl;
  std::cout << "Font Type is an OpenCV line type: 0=antialias, 1=8-connected, "
               "2=4-connected"
            << std::endl;
  std::cout << KNRM << std::endl;
  std::cout << "    ex: keogram --directory ../images/current/ --extension jpg "
               "--output-file keogram.jpg --font-size 2"
            << std::endl;
  std::cout << "    ex: keogram -d . -e png -o /home/pi/allsky/keogram.jpg -n"
            << KNRM << std::endl;
  exit(x);
}

int get_font_by_name(char* s) {
  // case insensitively check the user-specified font, and use something
  // sensible in case of erroneous input
  if (strcasecmp(s, "plain") == 0)
    return cv::FONT_HERSHEY_PLAIN;
  if (strcasecmp(s, "duplex") == 0)
    return cv::FONT_HERSHEY_DUPLEX;
  if (strcasecmp(s, "complex") == 0)
    return cv::FONT_HERSHEY_COMPLEX;
  if (strcasecmp(s, "complexsmall") == 0)
    return cv::FONT_HERSHEY_COMPLEX_SMALL;
  if (strcasecmp(s, "triplex") == 0)
    return cv::FONT_HERSHEY_TRIPLEX;
  if (strcasecmp(s, "scriptsimplex") == 0)
    return cv::FONT_HERSHEY_SCRIPT_SIMPLEX;
  if (strcasecmp(s, "scriptcomplex") == 0)
    return cv::FONT_HERSHEY_SCRIPT_COMPLEX;
  if (strcasecmp(s, "simplex"))  // yes, this is intentional
    std::cout << KRED << "Unknown font '" << s << "', using SIMPLEX " << KNRM
              << std::endl;
  return cv::FONT_HERSHEY_SIMPLEX;
}

int main(int argc, char* argv[]) {
  int c;
  bool labelsEnabled = true;
  int fontFace = cv::FONT_HERSHEY_SCRIPT_SIMPLEX;
  double fontScale = 2;
  int fontType = cv::LINE_8;
  int thickness = 3;
  unsigned char fontColor[3] = {255, 0, 0};
  double angle = 0;
  std::string directory, extension, outputfile;
  int width = 0, height = 0;

  while (1) {  // getopt loop
    int option_index = 0;
    static struct option long_options[] = {
        {"directory", required_argument, 0, 'd'},
        {"image-size", required_argument, 0, 's'},
        {"extension", required_argument, 0, 'e'},
        {"output", required_argument, 0, 'o'},
        {"font-color", required_argument, 0, 'C'},
        {"font-line", required_argument, 0, 'L'},
        {"font-name", required_argument, 0, 'N'},
        {"font-size", required_argument, 0, 'S'},
        {"font-type", required_argument, 0, 'T'},
        {"rotate", required_argument, 0, 'r'},
        {"no-label", no_argument, 0, 'n'},
        {"verbose", no_argument, 0, 'v'},
        {"help", no_argument, 0, 'h'},
        {0, 0, 0, 0}};

    c = getopt_long(argc, argv, "d:e:o:r:s:C:L:N:S:T:nvh", long_options,
                    &option_index);
    if (c == -1)
      break;
    switch (c) {  // option switch
      int tmp;
      case 'h':
        usage_and_exit(0);
        // NOTREACHED
      case 'd':
        directory = optarg;
        break;
      case 'e':
        extension = optarg;
        break;
      case 'o':
        outputfile = optarg;
        break;
      case 'n':
        labelsEnabled = false;
        break;
      case 'r':
        angle = atof(optarg);
        break;
      case 's':
        sscanf(optarg, "%dx%d", &width, &height);
        // 122.8Mpx should be enough for anybody.
        if (height < 0 || height > 9600 || width < 0 || width > 12800)
          height = width = 0;
        break;
      case 'v':
        loglevel++;
        break;
      case 'C':
        if (optarg[0] == '#')  // skip '#' if input is like '#coffee'
          optarg++;
        sscanf(optarg, "%06x", &tmp);
        fontColor[0] = (tmp >> 16) & 0xff;
        fontColor[1] = (tmp >> 8) & 0xff;
        fontColor[2] = tmp & 0xff;
        break;
      case 'L':
        thickness = atoi(optarg);
        break;
      case 'N':
        fontFace = get_font_by_name(optarg);
        break;
      case 'S':
        fontScale = atof(optarg);
        break;
      case 'T':
        tmp = atoi(optarg);
        if (tmp == 2)
          fontType = cv::LINE_4;
        else if (tmp == 0)
          fontType = cv::LINE_AA;
        else
          fontType = cv::LINE_8;
        break;
      default:
        break;
    }  // option switch
  }    // getopt loop

  if (directory.empty() || extension.empty() || outputfile.empty())
    usage_and_exit(3);

  glob_t files;
  std::string wildcard = directory + "/*." + extension;
  glob(wildcard.c_str(), 0, NULL, &files);
  if (files.gl_pathc == 0) {
    globfree(&files);
    std::cout << "No images found, exiting." << std::endl;
    return 0;
  }

  cv::Mat accumulated;

  int prevHour = -1;
  int nchan = 0;

  for (size_t f = 0; f < files.gl_pathc; f++) {
    cv::Mat imagesrc = cv::imread(files.gl_pathv[f], cv::IMREAD_UNCHANGED);
    if (!imagesrc.data) {
      std::cout << "Error reading file " << basename(files.gl_pathv[f])
                << std::endl;
      continue;
    }

    if (loglevel)
      std::cout << "[" << f + 1 << "/" << files.gl_pathc << "] "
                << basename(files.gl_pathv[f]) << std::endl;

    if (height && width &&
        (imagesrc.cols != width || imagesrc.rows != height)) {
      fprintf(stderr, "%s size %dx%d != %dx%d\n", files.gl_pathv[f],
              imagesrc.cols, imagesrc.cols, width, height);
      continue;
    }
    if (nchan == 0)
      nchan = imagesrc.channels();

    if (imagesrc.channels() != nchan)
      continue;

    cv::Point2f center((imagesrc.cols - 1) / 2.0, (imagesrc.rows - 1) / 2.0);
    cv::Mat rot = cv::getRotationMatrix2D(center, angle, 1.0);
    cv::Rect2f bbox =
        cv::RotatedRect(cv::Point2f(), imagesrc.size(), angle).boundingRect2f();
    rot.at<double>(0, 2) += bbox.width / 2.0 - imagesrc.cols / 2.0;
    rot.at<double>(1, 2) += bbox.height / 2.0 - imagesrc.rows / 2.0;
    cv::Mat imagedst;
    cv::warpAffine(imagesrc, imagedst, rot, bbox.size());
    if (accumulated.empty()) {
      accumulated.create(imagedst.rows, files.gl_pathc, imagesrc.type());
    }

    // Copy middle column to destination
    imagedst.col(imagedst.cols / 2).copyTo(accumulated.col(f));

    if (labelsEnabled) {
      struct stat s;
      stat(files.gl_pathv[f], &s);

      struct tm* t = localtime(&s.st_mtime);
      if (t->tm_hour != prevHour) {
        if (prevHour != -1) {
          // Draw a dashed line and label for hour
          cv::LineIterator it(accumulated, cv::Point(f, 0),
                              cv::Point(f, accumulated.rows));
          for (int i = 0; i < it.count; i++, ++it) {
            // 4 pixel dashed line
            if (i & 4) {
              uchar* p = *it;
              for (int c = 0; c < it.elemSize; c++) {
                *p = ~(*p);
                p++;
              }
            }
          }

          // Draw text label to the left of the dash
          char hour[3];
          snprintf(hour, 3, "%02d", t->tm_hour);
          std::string text(hour);
          int baseline = 0;
          cv::Size textSize =
              cv::getTextSize(text, fontFace, fontScale, thickness, &baseline);

          if (f - textSize.width >= 0) {
            cv::putText(accumulated, text,
                        cv::Point(f - textSize.width,
                                  accumulated.rows - textSize.height),
                        fontFace, fontScale,
                        cv::Scalar(fontColor[0], fontColor[1], fontColor[2]),
                        thickness, fontType);
          }
        }
        prevHour = t->tm_hour;
      }
    }
  }
  globfree(&files);

  std::vector<int> compression_params;
  compression_params.push_back(cv::IMWRITE_PNG_COMPRESSION);
  compression_params.push_back(9);
  compression_params.push_back(cv::IMWRITE_JPEG_QUALITY);
  compression_params.push_back(95);

  cv::imwrite(outputfile, accumulated, compression_params);
}
<commit_msg>more improvements<commit_after>// Simple keogram composition program using OpenCV
// Copyright 2018 Jarno Paananen <jarno.paananen@gmail.com>
// Based on a script by Thomas Jacquin
// Rotation added by Agustin Nunez @agnunez
// SPDX-License-Identifier: MIT

#include <getopt.h>
#include <glob.h>
#include <stdio.h>
#include <sys/stat.h>
#include <cstdlib>
#include <iostream>
#include <string>
#include <vector>

#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/opencv.hpp>

#define KNRM "\x1B[0m"
#define KRED "\x1B[31m"
#define KGRN "\x1B[32m"
#define KYEL "\x1B[33m"
#define KBLU "\x1B[34m"
#define KMAG "\x1B[35m"
#define KCYN "\x1B[36m"
#define KWHT "\x1B[37m"

//-------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------
int loglevel = 0;

void usage_and_exit(int x) {
  std::cout
      << "Usage:\tkeogram -d <imagedir> -e <ext> -o <outputfile> [<other_args>]"
      << std::endl;
  if (x)
    std::cout
        << KRED
        << "Source directory, image extension, and output file are required"
        << std::endl;

  std::cout << KNRM << std::endl;
  std::cout << "Arguments:" << std::endl;
  std::cout << "-d | --directory <str> : directory from which to load images "
               "(required)"
            << std::endl;
  std::cout << "-e | --extension <str> : image extension to process (required)"
            << std::endl;
  std::cout << "-o | --output-file <str> : name of output file (required)"
            << std::endl;
  std::cout << "-r | --rotate <float> : number of degrees to rotate image, "
               "counterclockwise (0)"
            << std::endl;
  std::cout << "-s | --image-size <int>x<int> : only process images of a given "
               "size, eg. 1280x960"
            << std::endl;
  std::cout << "-h | --help : display this help message" << std::endl;
  std::cout << "-v | --verbose : Increase logging verbosity" << std::endl;
  std::cout << "-n | --no-label : Disable hour labels" << std::endl;
  std::cout
      << "-C | --font-color <str> : label font color, in HTML format (0000ff)"
      << std::endl;
  std::cout << "-L | --font-line <int> : font line thickness (3)" << std::endl;
  std::cout << "-N | --font-name <str> : font name (simplex)" << std::endl;
  std::cout << "-S | --font-side <float> : font size (2.0)" << std::endl;
  std::cout << "-T | --font-type <int> : font line type (1)" << std::endl;

  std::cout << KNRM << std::endl;
  std::cout
      << "Font name is one of these OpenCV font names:\n\tSimplex, Plain, "
         "Duplex, Complex, Triplex, ComplexSmall, ScriptSimplex, ScriptComplex"
      << std::endl;
  std::cout << "Font Type is an OpenCV line type: 0=antialias, 1=8-connected, "
               "2=4-connected"
            << std::endl;
  std::cout << KNRM << std::endl;
  std::cout << "    ex: keogram --directory ../images/current/ --extension jpg "
               "--output-file keogram.jpg --font-size 2"
            << std::endl;
  std::cout << "    ex: keogram -d . -e png -o /home/pi/allsky/keogram.jpg -n"
            << KNRM << std::endl;
  exit(x);
}

int get_font_by_name(char* s) {
  // case insensitively check the user-specified font, and use something
  // sensible in case of erroneous input
  if (strcasecmp(s, "plain") == 0)
    return cv::FONT_HERSHEY_PLAIN;
  if (strcasecmp(s, "duplex") == 0)
    return cv::FONT_HERSHEY_DUPLEX;
  if (strcasecmp(s, "complex") == 0)
    return cv::FONT_HERSHEY_COMPLEX;
  if (strcasecmp(s, "complexsmall") == 0)
    return cv::FONT_HERSHEY_COMPLEX_SMALL;
  if (strcasecmp(s, "triplex") == 0)
    return cv::FONT_HERSHEY_TRIPLEX;
  if (strcasecmp(s, "scriptsimplex") == 0)
    return cv::FONT_HERSHEY_SCRIPT_SIMPLEX;
  if (strcasecmp(s, "scriptcomplex") == 0)
    return cv::FONT_HERSHEY_SCRIPT_COMPLEX;
  if (strcasecmp(s, "simplex"))  // yes, this is intentional
    std::cout << KRED << "Unknown font '" << s << "', using SIMPLEX " << KNRM
              << std::endl;
  return cv::FONT_HERSHEY_SIMPLEX;
}

int main(int argc, char* argv[]) {
  int c;
  bool labelsEnabled = true, parse_filename = false;
  int fontFace = cv::FONT_HERSHEY_SCRIPT_SIMPLEX;
  double fontScale = 2;
  int fontType = cv::LINE_8;
  int thickness = 3;
  unsigned char fontColor[3] = {255, 0, 0};
  double angle = 0;
  std::string directory, extension, outputfile;
  int width = 0, height = 0;

  while (1) {  // getopt loop
    int option_index = 0;
    static struct option long_options[] = {
        {"directory", required_argument, 0, 'd'},
        {"image-size", required_argument, 0, 's'},
        {"extension", required_argument, 0, 'e'},
        {"output", required_argument, 0, 'o'},
        {"font-color", required_argument, 0, 'C'},
        {"font-line", required_argument, 0, 'L'},
        {"font-name", required_argument, 0, 'N'},
        {"font-size", required_argument, 0, 'S'},
        {"font-type", required_argument, 0, 'T'},
        {"rotate", required_argument, 0, 'r'},
        {"parse-filename", no_argument, 0, 'p'},
        {"no-label", no_argument, 0, 'n'},
        {"verbose", no_argument, 0, 'v'},
        {"help", no_argument, 0, 'h'},
        {0, 0, 0, 0}};

    c = getopt_long(argc, argv, "d:e:o:r:s:C:L:N:S:T:npvh", long_options,
                    &option_index);
    if (c == -1)
      break;
    switch (c) {  // option switch
      int tmp;
      case 'h':
        usage_and_exit(0);
        // NOTREACHED
      case 'd':
        directory = optarg;
        break;
      case 'e':
        extension = optarg;
        break;
      case 'o':
        outputfile = optarg;
        break;
      case 'p':
        parse_filename = true;
        break;
      case 'n':
        labelsEnabled = false;
        break;
      case 'r':
        angle = atof(optarg);
        break;
      case 's':
        sscanf(optarg, "%dx%d", &width, &height);
        // 122.8Mpx should be enough for anybody.
        if (height < 0 || height > 9600 || width < 0 || width > 12800)
          height = width = 0;
        break;
      case 'v':
        loglevel++;
        break;
      case 'C':
        if (strchr(optarg, ' ')) {
          int r, g, b;
          sscanf(optarg, "%d %d %d", &b, &g, &r);
          fontColor[0] = b & 0xff;
          fontColor[1] = g & 0xff;
          fontColor[2] = r & 0xff;
          break;
        }
        if (optarg[0] == '#')  // skip '#' if input is like '#coffee'
          optarg++;
        sscanf(optarg, "%06x", &tmp);
        fontColor[0] = tmp & 0xff;
        fontColor[1] = (tmp >> 8) & 0xff;
        fontColor[2] = (tmp >> 16) & 0xff;
        break;
      case 'L':
        thickness = atoi(optarg);
        break;
      case 'N':
        fontFace = get_font_by_name(optarg);
        break;
      case 'S':
        fontScale = atof(optarg);
        break;
      case 'T':
        tmp = atoi(optarg);
        if (tmp == 2)
          fontType = cv::LINE_4;
        else if (tmp == 0)
          fontType = cv::LINE_AA;
        else
          fontType = cv::LINE_8;
        break;
      default:
        break;
    }  // option switch
  }    // getopt loop

  if (directory.empty() || extension.empty() || outputfile.empty())
    usage_and_exit(3);

  glob_t files;
  std::string wildcard = directory + "/*." + extension;
  glob(wildcard.c_str(), 0, NULL, &files);
  if (files.gl_pathc == 0) {
    globfree(&files);
    std::cout << "No images found, exiting." << std::endl;
    return 0;
  }

  cv::Mat accumulated;

  int prevHour = -1;
  int nchan = 0;

  for (size_t f = 0; f < files.gl_pathc; f++) {
    cv::Mat imagesrc = cv::imread(files.gl_pathv[f], cv::IMREAD_UNCHANGED);
    if (!imagesrc.data) {
      std::cout << "Error reading file " << basename(files.gl_pathv[f])
                << std::endl;
      continue;
    }

    if (loglevel)
      std::cout << "[" << f + 1 << "/" << files.gl_pathc << "] "
                << basename(files.gl_pathv[f]) << std::endl;

    if (height && width &&
        (imagesrc.cols != width || imagesrc.rows != height)) {
      fprintf(stderr, "%s size %dx%d != %dx%d\n", files.gl_pathv[f],
              imagesrc.cols, imagesrc.cols, width, height);
      continue;
    }
    if (nchan == 0)
      nchan = imagesrc.channels();

    if (imagesrc.channels() != nchan)
      continue;

    cv::Point2f center((imagesrc.cols - 1) / 2.0, (imagesrc.rows - 1) / 2.0);
    cv::Mat rot = cv::getRotationMatrix2D(center, angle, 1.0);
    cv::Rect2f bbox =
        cv::RotatedRect(cv::Point2f(), imagesrc.size(), angle).boundingRect2f();
    rot.at<double>(0, 2) += bbox.width / 2.0 - imagesrc.cols / 2.0;
    rot.at<double>(1, 2) += bbox.height / 2.0 - imagesrc.rows / 2.0;
    cv::Mat imagedst;
    cv::warpAffine(imagesrc, imagedst, rot, bbox.size());
    if (accumulated.empty()) {
      accumulated.create(imagedst.rows, files.gl_pathc, imagesrc.type());
    }

    // Copy middle column to destination
    imagedst.col(imagedst.cols / 2).copyTo(accumulated.col(f));

    if (labelsEnabled) {
      struct tm ft;  // the time of the file, by any means necessary
      if (parse_filename) {
        // engage your safety squints!
        char* s;
        s = strrchr(files.gl_pathv[f], '-');
        s++;
        sscanf(s, "%04d%02d%02d%02d%02d%02d.%*s", &ft.tm_year, &ft.tm_mon,
               &ft.tm_mday, &ft.tm_hour, &ft.tm_min, &ft.tm_sec);
      } else {
        // sometimes you can believe the file time on disk
        struct stat s;
        stat(files.gl_pathv[f], &s);
        struct tm* t = localtime(&s.st_mtime);
        ft.tm_hour = t->tm_hour;
      }

      if (ft.tm_hour != prevHour) {
        if (prevHour != -1) {
          // Draw a dashed line and label for hour
          cv::LineIterator it(accumulated, cv::Point(f, 0),
                              cv::Point(f, accumulated.rows));
          for (int i = 0; i < it.count; i++, ++it) {
            // 4 pixel dashed line
            if (i & 4) {
              uchar* p = *it;
              for (int c = 0; c < it.elemSize; c++) {
                *p = ~(*p);
                p++;
              }
            }
          }

          // Draw text label to the left of the dash
          char hour[3];
          snprintf(hour, 3, "%02d", ft.tm_hour);
          std::string text(hour);
          int baseline = 0;
          cv::Size textSize =
              cv::getTextSize(text, fontFace, fontScale, thickness, &baseline);

          if (f - textSize.width >= 0) {
            cv::putText(accumulated, text,
                        cv::Point(f - textSize.width,
                                  accumulated.rows - textSize.height),
                        fontFace, fontScale,
                        cv::Scalar(fontColor[0], fontColor[1], fontColor[2]),
                        thickness, fontType);
          }
        }
        prevHour = ft.tm_hour;
      }
    }
  }
  globfree(&files);

  std::vector<int> compression_params;
  compression_params.push_back(cv::IMWRITE_PNG_COMPRESSION);
  compression_params.push_back(9);
  compression_params.push_back(cv::IMWRITE_JPEG_QUALITY);
  compression_params.push_back(95);

  cv::imwrite(outputfile, accumulated, compression_params);
}
<|endoftext|>


<commit_before>// Chemfiles, a modern library for chemistry file reading and writing
// Copyright (C) Guillaume Fraux and contributors -- BSD license

#include <iostream>
#include "chemfiles/warnings.hpp"
#include "chemfiles/Configuration.hpp"
#include "chemfiles/generic.hpp"

static chemfiles::warning_callback CALLBACK = [](std::string message){
    std::cerr << "[chemfiles] " << message << std::endl;
};

void chemfiles::set_warning_callback(warning_callback callback) {
    CALLBACK = callback;
}

void chemfiles::warning(std::string message) {
    CALLBACK(std::move(message));
}

void chemfiles::add_configuration(const std::string& path) {
    Configuration::add_configuration(path);
}
<commit_msg>Ensure thread safety for warning callback code<commit_after>// Chemfiles, a modern library for chemistry file reading and writing
// Copyright (C) Guillaume Fraux and contributors -- BSD license

#include <iostream>

#include "chemfiles/warnings.hpp"
#include "chemfiles/Configuration.hpp"
#include "chemfiles/generic.hpp"
#include "chemfiles/mutex.hpp"

using namespace chemfiles;

static mutex<warning_callback> CALLBACK = {[](std::string message){
    std::cerr << "[chemfiles] " << message << std::endl;
}};

void chemfiles::set_warning_callback(warning_callback callback) {
    auto guard = CALLBACK.lock();
    *guard = callback;
}

void chemfiles::warning(std::string message) {
    auto guard = CALLBACK.lock();
    (*guard)(std::move(message));
}

void chemfiles::add_configuration(const std::string& path) {
    Configuration::add_configuration(path);
}
<|endoftext|>


<commit_before>#include "Schema.hpp"
#include <sstream>

static std::string translateType(const DataType& type) {
  std::ostringstream stream;
  if(type.typeTag == DataTypeTag::Integer) {
    stream << "Integer";
  } else if(type.typeTag == DataTypeTag::Numeric) {
    stream << "Numeric<" << (int) type.attributes.numeric.integerPlaces
           << "," << (int) type.attributes.numeric.decimalPlaces << ">";
  } else if(type.typeTag == DataTypeTag::Char) {
    stream << "Char<" << (int) type.attributes.charLen << ">";
  } else if(type.typeTag == DataTypeTag::VarChar) {
    stream << "Varchar<" << (int) type.attributes.charLen << ">";
  } else if(type.typeTag == DataTypeTag::Date) {
    stream << "Date";
  } else if(type.typeTag == DataTypeTag::Timestamp) {
    stream << "Timestamp";
  }
  return stream.str();
}

template<typename T, typename Callable>
static void generateList(std::ostream& out, const std::vector<T>& elements, Callable cb, std::string seperator = ", ") {
  auto first = true;
  for(const auto& elem : elements) {
    if(!first) out << seperator;
    cb(out, elem);
    first = false;
  }
}

void Schema::generateCppCode(std::ostream& out) {
  out <<
    "#ifndef H_Schema\n"
    "#define H_Schema\n"
    "#include <vector>\n"
    "#include <map>\n"
    "#include <unordered_map>\n"
    "#include \"schema/Types.hpp\"\n";
  for(auto& table : tables) {
    out << "//--------------------------------------------------\n"
           "struct " << table.name << "_t {\n";
    // actual columns
    for(auto& column : table.columns) {
      out << "  std::vector<" << translateType(column.type) << "> col_" << column.name << ";\n";
    }
    // primary key index
    if(!table.primaryKey.empty()) {
      if(table.primaryKeyPrefixIndexable) {
        out << "  std::map<std::tuple<";
      } else {
        out << "  std::unordered_map<std::tuple<";
      }
      generateList(out, table.primaryKey, [&](auto& out, auto& col){
               out << translateType(table.columns[col].type);
          });
      out << ">, size_t> primary_key_idx;\n";
    }
    // additional idcs
    for(auto& idx : table.indices) {
      if(idx.prefixIndexable) {
        out << "  std::map<std::tuple<";
      } else {
        out << "  std::unordered_map<std::tuple<";
      }
      generateList(out, idx.columns, [&](auto& out, auto& col){
               out << translateType(table.columns[col].type);
          });
      out << ">, size_t> idx_" << idx.name << ";\n";
    }
    // insert
    out << "  void insert_tuple(";
    generateList(out, table.columns, [&](auto& out, auto& column){
            out << translateType(column.type) << " " << column.name;
        });
    out << ") {\n";
    for(auto& column : table.columns) {
      out << "    this->col_" << column.name << ".push_back(" << column.name << ");\n";
    }
    auto generateIndexInsert = [&](const std::string& idxName, const std::vector<unsigned>& idxCols){
      out << "    this->" << idxName << ".insert(std::make_pair(std::make_tuple(";
      generateList(out, idxCols, [&](auto& out, auto& col){
              out << table.columns[col].name;
          });
      out << "), this->col_" << table.columns[0].name << ".size()))\n";
    };
    if(!table.primaryKey.empty()) {
      generateIndexInsert("primary_key_idx", table.primaryKey);
    }
    for(auto& idx : table.indices) {
      generateIndexInsert("idx_" + idx.name, idx.columns);
    }
    out << "  }\n";
    // delete
    out << "  void delete_tuple(size_t tid) {\n";
    auto generateIndexDelete = [&](const std::string& idxName, const std::vector<unsigned>& idxCols){
      out << "    this->" << idxName << ".erase(std::make_tuple(";
      generateList(out, idxCols, [&](auto& out, auto& col){
              out << "this->col_" << table.columns[col].name << "[tid]";
          });
      out << "));\n";
      out << "    this->" << idxName << "[std::make_tuple(";
      generateList(out, idxCols, [&](auto& out, auto& col){
              out << "this->col_" << table.columns[col].name << ".back()";
          });
      out << ")] = tid;\n";
    };
    if(!table.primaryKey.empty()) {
      generateIndexDelete("primary_key_idx", table.primaryKey);
    }
    for(auto& idx : table.indices) {
      generateIndexDelete("idx_" + idx.name, idx.columns);
    }
    for(auto& column : table.columns) {
      out << "    this->col_" << column.name << "[tid] = this->col_" << column.name << ".back();\n";
      out << "    this->col_" << column.name << ".pop_back();\n";
    }
    out << "  }\n";
    //TODO: parse
    out << "}\n";
  }
  out << "//--------------------------------------------------\n"
         "#endif";
}
<commit_msg>schema: generate "loadFromTbl" function<commit_after>#include "Schema.hpp"
#include <sstream>

static std::string translateType(const DataType& type) {
  std::ostringstream stream;
  if(type.typeTag == DataTypeTag::Integer) {
    stream << "Integer";
  } else if(type.typeTag == DataTypeTag::Numeric) {
    stream << "Numeric<" << (int) type.attributes.numeric.integerPlaces
           << "," << (int) type.attributes.numeric.decimalPlaces << ">";
  } else if(type.typeTag == DataTypeTag::Char) {
    stream << "Char<" << (int) type.attributes.charLen << ">";
  } else if(type.typeTag == DataTypeTag::VarChar) {
    stream << "Varchar<" << (int) type.attributes.charLen << ">";
  } else if(type.typeTag == DataTypeTag::Date) {
    stream << "Date";
  } else if(type.typeTag == DataTypeTag::Timestamp) {
    stream << "Timestamp";
  }
  return stream.str();
}

template<typename T, typename Callable>
static void generateList(std::ostream& out, const std::vector<T>& elements, Callable cb, std::string seperator = ", ") {
  auto first = true;
  for(const auto& elem : elements) {
    if(!first) out << seperator;
    cb(out, elem);
    first = false;
  }
}

void Schema::generateCppCode(std::ostream& out) {
  out <<
    "#ifndef H_Schema\n"
    "#define H_Schema\n"
    "#include <vector>\n"
    "#include <map>\n"
    "#include <unordered_map>\n"
    "#include <istream>\n"
    "#include \"schema/Types.hpp\"\n";
  for(auto& table : tables) {
    out << "//--------------------------------------------------\n"
           "struct " << table.name << "_t {\n";
    // actual columns
    for(auto& column : table.columns) {
      out << "  std::vector<" << translateType(column.type) << "> col_" << column.name << ";\n";
    }
    // primary key index
    if(!table.primaryKey.empty()) {
      if(table.primaryKeyPrefixIndexable) {
        out << "  std::map<std::tuple<";
      } else {
        out << "  std::unordered_map<std::tuple<";
      }
      generateList(out, table.primaryKey, [&](auto& out, auto& col){
               out << translateType(table.columns[col].type);
          });
      out << ">, size_t> primary_key_idx;\n";
    }
    // additional idcs
    for(auto& idx : table.indices) {
      if(idx.prefixIndexable) {
        out << "  std::map<std::tuple<";
      } else {
        out << "  std::unordered_map<std::tuple<";
      }
      generateList(out, idx.columns, [&](auto& out, auto& col){
               out << translateType(table.columns[col].type);
          });
      out << ">, size_t> idx_" << idx.name << ";\n";
    }
    // insert
    out << "  void insert_tuple(";
    generateList(out, table.columns, [&](auto& out, auto& column){
            out << translateType(column.type) << " " << column.name;
        });
    out << ") {\n";
    for(auto& column : table.columns) {
      out << "    this->col_" << column.name << ".push_back(" << column.name << ");\n";
    }
    auto generateIndexInsert = [&](const std::string& idxName, const std::vector<unsigned>& idxCols){
      out << "    this->" << idxName << ".insert(std::make_pair(std::make_tuple(";
      generateList(out, idxCols, [&](auto& out, auto& col){
              out << table.columns[col].name;
          });
      out << "), this->col_" << table.columns[0].name << ".size()))\n";
    };
    if(!table.primaryKey.empty()) {
      generateIndexInsert("primary_key_idx", table.primaryKey);
    }
    for(auto& idx : table.indices) {
      generateIndexInsert("idx_" + idx.name, idx.columns);
    }
    out << "  }\n";
    // delete
    out << "  void delete_tuple(size_t tid) {\n";
    auto generateIndexDelete = [&](const std::string& idxName, const std::vector<unsigned>& idxCols){
      out << "    this->" << idxName << ".erase(std::make_tuple(";
      generateList(out, idxCols, [&](auto& out, auto& col){
              out << "this->col_" << table.columns[col].name << "[tid]";
          });
      out << "));\n";
      out << "    this->" << idxName << "[std::make_tuple(";
      generateList(out, idxCols, [&](auto& out, auto& col){
              out << "this->col_" << table.columns[col].name << ".back()";
          });
      out << ")] = tid;\n";
    };
    if(!table.primaryKey.empty()) {
      generateIndexDelete("primary_key_idx", table.primaryKey);
    }
    for(auto& idx : table.indices) {
      generateIndexDelete("idx_" + idx.name, idx.columns);
    }
    for(auto& column : table.columns) {
      out << "    this->col_" << column.name << "[tid] = this->col_" << column.name << ".back();\n";
      out << "    this->col_" << column.name << ".pop_back();\n";
    }
    out << "  }\n";
    // loadFromTbl
    out << "  void loadFromTbl(std::istream& in) {\n"
        << "    std::string buffer;\n"
        << "    char nextChar;\n"
        << "    while(in.good()) {\n";
    bool first = true;
    for(auto& col : table.columns) {
      if(!first) out << "      if(nextChar == '\\n') throw \"unexpected end of line\";\n";
      first = false;
      out << "      buffer.clear();\n"
             "      nextChar = in.peek();\n"
             "      while(nextChar != '|' && nextChar != '\\n') { buffer.push_back(nextChar); nextChar = in.get(); }\n"
             "      this->col_" << col.name << ".push_back(" << translateType(col.type) << "::castString(buffer.c_str(), buffer.size()));\n";
    }
    out << "      if(nextChar != '\\n') throw \"expected end of line\";\n";
    out << "    }\n"
           "    auto table_size = this->col_" << table.columns[0].name << ".size();\n";
    if(!table.primaryKey.empty()) {
      out << "    this->primary_key_idx.reserve(table_size);\n";
    }
    for(auto& idx : table.indices) {
      out << "    this->idx_" << idx.name << ".reserve(table_size);\n";
    }
    out << "    for(size_t i = 0; i < table_size; i++) {\n";
    auto generateIndexBulkLoad = [&](const std::string& idxName, const std::vector<unsigned>& idxCols){
      out << "      this->" << idxName << ".insert(std::make_pair(std::make_tuple(";
      generateList(out, idxCols, [&](auto& out, auto& col){
              out << "this->col_" << table.columns[col].name << "[i]";
          });
      out << "), i))\n";
    };
    if(!table.primaryKey.empty()) {
      generateIndexBulkLoad("primary_key_idx", table.primaryKey);
    }
    for(auto& idx : table.indices) {
      generateIndexBulkLoad("idx_" + idx.name, idx.columns);
    }
    out << "    }\n"
           "  }\n";
    //finish struct
    out << "}\n";
  }
  out << "//--------------------------------------------------\n"
         "#endif";
}
<|endoftext|>


<commit_before>//===- GlobalsModRef.cpp - Simple Mod/Ref Analysis for Globals ------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This simple pass provides alias and mod/ref information for global values
// that do not have their address taken.  For this simple (but very common)
// case, we can provide pretty accurate and useful information.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "globalsmodref"
#include "llvm/Analysis/Passes.h"
#include "llvm/Module.h"
#include "llvm/Pass.h"
#include "llvm/Instructions.h"
#include "llvm/Constants.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/CallGraph.h"
#include "Support/Debug.h"
#include "Support/Statistic.h"
#include "Support/SCCIterator.h"
#include <set>
using namespace llvm;

namespace {
  Statistic<>
  NumNonAddrTakenGlobalVars("globalsmodref-aa",
                            "Number of global vars without address taken");
  Statistic<>
  NumNonAddrTakenFunctions("globalsmodref-aa",
                           "Number of functions without address taken");

  class GlobalsModRef : public Pass, public AliasAnalysis {
    /// ModRefFns - One instance of this record is kept for each global without
    /// its address taken.
    struct ModRefFns {
      /// RefFns/ModFns - Sets of functions that and write globals.
      std::set<Function*> RefFns, ModFns;
    };

    /// NonAddressTakenGlobals - A map of globals that do not have their
    /// addresses taken to their record.
    std::map<GlobalValue*, ModRefFns> NonAddressTakenGlobals;

    /// FunctionInfo - For each function, keep track of what globals are
    /// modified or read.
    std::map<std::pair<Function*, GlobalValue*>, unsigned> FunctionInfo;

  public:
    bool run(Module &M) {
      InitializeAliasAnalysis(this);                 // set up super class
      AnalyzeGlobals(M);                          // find non-addr taken globals
      AnalyzeCallGraph(getAnalysis<CallGraph>(), M); // Propagate on CG
      return false;
    }

    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AliasAnalysis::getAnalysisUsage(AU);
      AU.addRequired<CallGraph>();
      AU.setPreservesAll();                         // Does not transform code
    }

    //------------------------------------------------
    // Implement the AliasAnalysis API
    //
    AliasResult alias(const Value *V1, unsigned V1Size,
                      const Value *V2, unsigned V2Size);
    ModRefResult getModRefInfo(CallSite CS, Value *P, unsigned Size);
    bool hasNoModRefInfoForCalls() const { return false; }

    virtual void deleteValue(Value *V);
    virtual void copyValue(Value *From, Value *To);

  private:
    void AnalyzeGlobals(Module &M);
    void AnalyzeCallGraph(CallGraph &CG, Module &M);
    bool AnalyzeUsesOfGlobal(Value *V, std::vector<Function*> &Readers,
                             std::vector<Function*> &Writers);
  };

  RegisterOpt<GlobalsModRef> X("globalsmodref-aa",
                               "Simple mod/ref analysis for globals");
  RegisterAnalysisGroup<AliasAnalysis, GlobalsModRef> Y;
}

Pass *llvm::createGlobalsModRefPass() { return new GlobalsModRef(); }

/// AnalyzeGlobalUses - Scan through the users of all of the internal
/// GlobalValue's in the program.  If none of them have their "Address taken"
/// (really, their address passed to something nontrivial), record this fact,
/// and record the functions that they are used directly in.
void GlobalsModRef::AnalyzeGlobals(Module &M) {
  std::vector<Function*> Readers, Writers;
  for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
    if (I->hasInternalLinkage()) {
      if (!AnalyzeUsesOfGlobal(I, Readers, Writers)) {
        // Remember that we are tracking this global, and the mod/ref fns
        ModRefFns &E = NonAddressTakenGlobals[I];
        E.RefFns.insert(Readers.begin(), Readers.end());
        E.ModFns.insert(Writers.begin(), Writers.end());
        ++NumNonAddrTakenFunctions;
      }
      Readers.clear(); Writers.clear();
    }

  for (Module::giterator I = M.gbegin(), E = M.gend(); I != E; ++I)
    // FIXME: it is kinda dumb to track aliasing properties for constant
    // globals, it will never be particularly useful anyways, 'cause they can
    // never be modified (and the optimizer knows this already)!
    if (I->hasInternalLinkage()) {
      if (!AnalyzeUsesOfGlobal(I, Readers, Writers)) {
        // Remember that we are tracking this global, and the mod/ref fns
        ModRefFns &E = NonAddressTakenGlobals[I];
        E.RefFns.insert(Readers.begin(), Readers.end());
        E.ModFns.insert(Writers.begin(), Writers.end());
        ++NumNonAddrTakenGlobalVars;
      }
      Readers.clear(); Writers.clear();
    }
}

/// AnalyzeUsesOfGlobal - Look at all of the users of the specified global value
/// derived pointer.  If this is used by anything complex (i.e., the address
/// escapes), return true.  Also, while we are at it, keep track of those
/// functions that read and write to the value.
bool GlobalsModRef::AnalyzeUsesOfGlobal(Value *V,
                                        std::vector<Function*> &Readers,
                                        std::vector<Function*> &Writers) {
  //if (!isa<PointerType>(V->getType())) return true;

  for (Value::use_iterator UI = V->use_begin(), E = V->use_end(); UI != E; ++UI)
    if (LoadInst *LI = dyn_cast<LoadInst>(*UI)) {
      Readers.push_back(LI->getParent()->getParent());
    } else if (StoreInst *SI = dyn_cast<StoreInst>(*UI)) {
      if (V == SI->getOperand(0)) return true;  // Storing the pointer
      Writers.push_back(SI->getParent()->getParent());
    } else if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(*UI)) {
      if (AnalyzeUsesOfGlobal(GEP, Readers, Writers)) return true;
    } else if (CallInst *CI = dyn_cast<CallInst>(*UI)) {
      // Make sure that this is just the function being called, not that it is
      // passing into the function.
      for (unsigned i = 1, e = CI->getNumOperands(); i != e; ++i)
        if (CI->getOperand(i) == V) return true;
    } else if (CallInst *CI = dyn_cast<CallInst>(*UI)) {
      // Make sure that this is just the function being called, not that it is
      // passing into the function.
      for (unsigned i = 1, e = CI->getNumOperands(); i != e; ++i)
        if (CI->getOperand(i) == V) return true;
    } else if (InvokeInst *II = dyn_cast<InvokeInst>(*UI)) {
      // Make sure that this is just the function being called, not that it is
      // passing into the function.
      for (unsigned i = 3, e = II->getNumOperands(); i != e; ++i)
        if (II->getOperand(i) == V) return true;
    } else if (ConstantExpr *CE = dyn_cast<ConstantExpr>(*UI)) {
      if (CE->getOpcode() == Instruction::GetElementPtr ||
          CE->getOpcode() == Instruction::Cast) {
        if (AnalyzeUsesOfGlobal(CE, Readers, Writers))
          return true;
      } else {
        return true;
      }
    } else if (GlobalValue *GV = dyn_cast<GlobalValue>(*UI)) {
      if (AnalyzeUsesOfGlobal(GV, Readers, Writers)) return true;
    } else {
      return true;
    }
  return false;
}

/// AnalyzeCallGraph - At this point, we know the functions where globals are
/// immediately stored to and read from.  Propagate this information up the call
/// graph to all callers.
void GlobalsModRef::AnalyzeCallGraph(CallGraph &CG, Module &M) {
  if (NonAddressTakenGlobals.empty()) return;  // Don't bother, nothing to do.

  // Invert the NonAddressTakenGlobals map into the FunctionInfo map.
  for (std::map<GlobalValue*, ModRefFns>::iterator I =
         NonAddressTakenGlobals.begin(), E = NonAddressTakenGlobals.end();
       I != E; ++I) {
    GlobalValue *GV = I->first;
    ModRefFns &MRInfo = I->second;
    for (std::set<Function*>::iterator I = MRInfo.RefFns.begin(),
           E = MRInfo.RefFns.begin(); I != E; ++I)
      FunctionInfo[std::make_pair(*I, GV)] |= Ref;
    MRInfo.RefFns.clear();
    for (std::set<Function*>::iterator I = MRInfo.ModFns.begin(),
           E = MRInfo.ModFns.begin(); I != E; ++I)
      FunctionInfo[std::make_pair(*I, GV)] |= Mod;
    MRInfo.ModFns.clear();
  }

  // We do a bottom-up SCC traversal of the call graph.  In other words, we
  // visit all callees before callers (leaf-first).
  for (scc_iterator<CallGraph*> I = scc_begin(&CG), E = scc_end(&CG);
       I != E; ++I) {
    std::map<GlobalValue*, unsigned> ModRefProperties;
    const std::vector<CallGraphNode *> &SCC = *I;

    // Collect the mod/ref properties due to called functions.
    for (unsigned i = 0, e = SCC.size(); i != e; ++i)
      for (CallGraphNode::iterator CI = SCC[i]->begin(), E = SCC[i]->end();
           CI != E; ++CI) {
        if (Function *Callee = (*CI)->getFunction()) {
          // Otherwise, combine the callee properties into our accumulated set.
          std::map<std::pair<Function*, GlobalValue*>, unsigned>::iterator
            CI = FunctionInfo.lower_bound(std::make_pair(Callee,
                                                         (GlobalValue*)0));
          for (;CI != FunctionInfo.end() && CI->first.first == Callee; ++CI)
            ModRefProperties[CI->first.second] |= CI->second;
        } else {
          // For now assume that external functions could mod/ref anything,
          // since they could call into an escaping function that mod/refs an
          // internal.  FIXME: We need better tracking!
          for (std::map<GlobalValue*, ModRefFns>::iterator GI =
                 NonAddressTakenGlobals.begin(),
                 E = NonAddressTakenGlobals.end(); GI != E; ++GI)
            ModRefProperties[GI->first] = ModRef;
          goto Out;
        }
      }
  Out:
    // Set all functions in the CFG to have these properties.  FIXME: it would
    // be better to use union find to only store these properties once,
    // PARTICULARLY if it's the universal set.
    for (unsigned i = 0, e = SCC.size(); i != e; ++i)
      if (Function *F = SCC[i]->getFunction()) {
        for (std::map<GlobalValue*, unsigned>::iterator I =
               ModRefProperties.begin(), E = ModRefProperties.end();
             I != E; ++I)
          FunctionInfo[std::make_pair(F, I->first)] = I->second;
      }
  }
}

/// getUnderlyingObject - This traverses the use chain to figure out what object
/// the specified value points to.  If the value points to, or is derived from,
/// a global object, return it.
static const GlobalValue *getUnderlyingObject(const Value *V) {
  //if (!isa<PointerType>(V->getType())) return 0;

  // If we are at some type of object... return it.
  if (const GlobalValue *GV = dyn_cast<GlobalValue>(V)) return GV;

  // Traverse through different addressing mechanisms...
  if (const Instruction *I = dyn_cast<Instruction>(V)) {
    if (isa<CastInst>(I) || isa<GetElementPtrInst>(I))
      return getUnderlyingObject(I->getOperand(0));
  } else if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(V)) {
    if (CE->getOpcode() == Instruction::Cast ||
        CE->getOpcode() == Instruction::GetElementPtr)
      return getUnderlyingObject(CE->getOperand(0));
  }
  return 0;
}

/// alias - If one of the pointers is to a global that we are tracking, and the
/// other is some random pointer, we know there cannot be an alias, because the
/// address of the global isn't taken.
AliasAnalysis::AliasResult
GlobalsModRef::alias(const Value *V1, unsigned V1Size,
                     const Value *V2, unsigned V2Size) {
  GlobalValue *GV1 = const_cast<GlobalValue*>(getUnderlyingObject(V1));
  GlobalValue *GV2 = const_cast<GlobalValue*>(getUnderlyingObject(V2));

  // If the global's address is taken, pretend we don't know it's a pointer to
  // the global.
  if (GV1 && !NonAddressTakenGlobals.count(GV1)) GV1 = 0;
  if (GV2 && !NonAddressTakenGlobals.count(GV2)) GV2 = 0;

  if ((GV1 || GV2) && GV1 != GV2)
    return NoAlias;

  return AliasAnalysis::alias(V1, V1Size, V2, V2Size);
}

AliasAnalysis::ModRefResult
GlobalsModRef::getModRefInfo(CallSite CS, Value *P, unsigned Size) {
  unsigned Known = ModRef;

  // If we are asking for mod/ref info of a direct call with a pointer to a
  // global, return information if we have it.
  if (GlobalValue *GV = const_cast<GlobalValue*>(getUnderlyingObject(P)))
    if (GV->hasInternalLinkage())
      if (Function *F = CS.getCalledFunction()) {
        std::map<std::pair<Function*, GlobalValue*>, unsigned>::iterator
          it = FunctionInfo.find(std::make_pair(F, GV));
        if (it != FunctionInfo.end())
          Known = it->second;
      }

  if (Known == NoModRef)
    return NoModRef; // No need to query other mod/ref analyses
  return ModRefResult(Known & AliasAnalysis::getModRefInfo(CS, P, Size));
}

//===----------------------------------------------------------------------===//
// Methods to update the analysis as a result of the client transformation.
//
void GlobalsModRef::deleteValue(Value *V) {
  if (GlobalValue *GV = dyn_cast<GlobalValue>(V)) {
    std::map<GlobalValue*, ModRefFns>::iterator I =
      NonAddressTakenGlobals.find(GV);
    if (I != NonAddressTakenGlobals.end())
      NonAddressTakenGlobals.erase(I);
  }
}

void GlobalsModRef::copyValue(Value *From, Value *To) {
  if (GlobalValue *FromGV = dyn_cast<GlobalValue>(From))
    if (GlobalValue *ToGV = dyn_cast<GlobalValue>(To)) {
      std::map<GlobalValue*, ModRefFns>::iterator I =
        NonAddressTakenGlobals.find(FromGV);
      if (I != NonAddressTakenGlobals.end())
        NonAddressTakenGlobals[ToGV] = I->second;
    }
}
<commit_msg>Complete rewrite of this pass to be faster, use less memory, be easier to understand, and more accurate to boot!  This implements GlobalModRef/purecse.ll over the previous impl.<commit_after>//===- GlobalsModRef.cpp - Simple Mod/Ref Analysis for Globals ------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This simple pass provides alias and mod/ref information for global values
// that do not have their address taken, and keeps track of whether functions
// read or write memory (are "pure").  For this simple (but very common) case,
// we can provide pretty accurate and useful information.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "globalsmodref-aa"
#include "llvm/Analysis/Passes.h"
#include "llvm/Module.h"
#include "llvm/Pass.h"
#include "llvm/Instructions.h"
#include "llvm/Constants.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/CallGraph.h"
#include "llvm/Support/InstIterator.h"
#include "Support/CommandLine.h"
#include "Support/Debug.h"
#include "Support/Statistic.h"
#include "Support/SCCIterator.h"
#include <set>
using namespace llvm;

namespace {
  Statistic<>
  NumNonAddrTakenGlobalVars("globalsmodref-aa",
                            "Number of global vars without address taken");
  Statistic<>
  NumNonAddrTakenFunctions("globalsmodref-aa",
                           "Number of functions without address taken");
  Statistic<>
  NumNoMemFunctions("globalsmodref-aa",
                    "Number of functions that do not access memory");
  Statistic<>
  NumReadMemFunctions("globalsmodref-aa",
                      "Number of functions that only read memory");

  /// FunctionRecord - One instance of this structure is stored for every
  /// function in the program.  Later, the entries for these functions are
  /// removed if the function is found to call an external function (in which
  /// case we know nothing about it.
  struct FunctionRecord {
    /// GlobalInfo - Maintain mod/ref info for all of the globals without
    /// addresses taken that are read or written (transitively) by this
    /// function.
    std::map<GlobalValue*, unsigned> GlobalInfo;

    unsigned getInfoForGlobal(GlobalValue *GV) const {
      std::map<GlobalValue*, unsigned>::const_iterator I = GlobalInfo.find(GV);
      if (I != GlobalInfo.end())
        return I->second;
      return 0;
    }

    /// FunctionEffect - Capture whether or not this function reads or writes to
    /// ANY memory.  If not, we can do a lot of aggressive analysis on it.
    unsigned FunctionEffect;
  };

  /// GlobalsModRef - The actual analysis pass.
  class GlobalsModRef : public Pass, public AliasAnalysis {
    /// NonAddressTakenGlobals - The globals that do not have their addresses
    /// taken.
    std::set<GlobalValue*> NonAddressTakenGlobals;

    /// FunctionInfo - For each function, keep track of what globals are
    /// modified or read.
    std::map<Function*, FunctionRecord> FunctionInfo;

  public:
    bool run(Module &M) {
      InitializeAliasAnalysis(this);                 // set up super class
      AnalyzeGlobals(M);                          // find non-addr taken globals
      AnalyzeCallGraph(getAnalysis<CallGraph>(), M); // Propagate on CG
      return false;
    }

    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AliasAnalysis::getAnalysisUsage(AU);
      AU.addRequired<CallGraph>();
      AU.setPreservesAll();                         // Does not transform code
    }

    //------------------------------------------------
    // Implement the AliasAnalysis API
    //
    AliasResult alias(const Value *V1, unsigned V1Size,
                      const Value *V2, unsigned V2Size);
    ModRefResult getModRefInfo(CallSite CS, Value *P, unsigned Size);
    bool hasNoModRefInfoForCalls() const { return false; }

    bool doesNotAccessMemory(Function *F) {
      if (FunctionRecord *FR = getFunctionInfo(F))
        if (FR->FunctionEffect == 0)
          return true;
      return AliasAnalysis::doesNotAccessMemory(F);
    }
    bool onlyReadsMemory(Function *F) {
      if (FunctionRecord *FR = getFunctionInfo(F))
        if ((FR->FunctionEffect & Mod) == 0)
          return true;
      return AliasAnalysis::onlyReadsMemory(F);
    }

    virtual void deleteValue(Value *V);
    virtual void copyValue(Value *From, Value *To);

  private:
    /// getFunctionInfo - Return the function info for the function, or null if
    /// the function calls an external function (in which case we don't have
    /// anything useful to say about it).
    FunctionRecord *getFunctionInfo(Function *F) {
      std::map<Function*, FunctionRecord>::iterator I = FunctionInfo.find(F);
      if (I != FunctionInfo.end())
        return &I->second;
      return 0;
    }

    void AnalyzeGlobals(Module &M);
    void AnalyzeCallGraph(CallGraph &CG, Module &M);
    void AnalyzeSCC(std::vector<CallGraphNode *> &SCC);
    bool AnalyzeUsesOfGlobal(Value *V, std::vector<Function*> &Readers,
                             std::vector<Function*> &Writers);
  };

  RegisterOpt<GlobalsModRef> X("globalsmodref-aa",
                               "Simple mod/ref analysis for globals");
  RegisterAnalysisGroup<AliasAnalysis, GlobalsModRef> Y;
}

Pass *llvm::createGlobalsModRefPass() { return new GlobalsModRef(); }

/// AnalyzeGlobalUses - Scan through the users of all of the internal
/// GlobalValue's in the program.  If none of them have their "Address taken"
/// (really, their address passed to something nontrivial), record this fact,
/// and record the functions that they are used directly in.
void GlobalsModRef::AnalyzeGlobals(Module &M) {
  std::vector<Function*> Readers, Writers;
  for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
    if (I->hasInternalLinkage()) {
      if (!AnalyzeUsesOfGlobal(I, Readers, Writers)) {
        // Remember that we are tracking this global.
        NonAddressTakenGlobals.insert(I);
        ++NumNonAddrTakenFunctions;
      }
      Readers.clear(); Writers.clear();
    }

  for (Module::giterator I = M.gbegin(), E = M.gend(); I != E; ++I)
    if (I->hasInternalLinkage()) {
      if (!AnalyzeUsesOfGlobal(I, Readers, Writers)) {
        // Remember that we are tracking this global, and the mod/ref fns
        NonAddressTakenGlobals.insert(I);
        for (unsigned i = 0, e = Readers.size(); i != e; ++i)
          FunctionInfo[Readers[i]].GlobalInfo[I] |= Ref;

        if (!I->isConstant())  // No need to keep track of writers to constants
          for (unsigned i = 0, e = Writers.size(); i != e; ++i)
            FunctionInfo[Writers[i]].GlobalInfo[I] |= Mod;
        ++NumNonAddrTakenGlobalVars;
      }
      Readers.clear(); Writers.clear();
    }
}

/// AnalyzeUsesOfGlobal - Look at all of the users of the specified global value
/// derived pointer.  If this is used by anything complex (i.e., the address
/// escapes), return true.  Also, while we are at it, keep track of those
/// functions that read and write to the value.
bool GlobalsModRef::AnalyzeUsesOfGlobal(Value *V,
                                        std::vector<Function*> &Readers,
                                        std::vector<Function*> &Writers) {
  if (!isa<PointerType>(V->getType())) return true;

  for (Value::use_iterator UI = V->use_begin(), E = V->use_end(); UI != E; ++UI)
    if (LoadInst *LI = dyn_cast<LoadInst>(*UI)) {
      Readers.push_back(LI->getParent()->getParent());
    } else if (StoreInst *SI = dyn_cast<StoreInst>(*UI)) {
      if (V == SI->getOperand(0)) return true;  // Storing the pointer
      Writers.push_back(SI->getParent()->getParent());
    } else if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(*UI)) {
      if (AnalyzeUsesOfGlobal(GEP, Readers, Writers)) return true;
    } else if (CallInst *CI = dyn_cast<CallInst>(*UI)) {
      // Make sure that this is just the function being called, not that it is
      // passing into the function.
      for (unsigned i = 1, e = CI->getNumOperands(); i != e; ++i)
        if (CI->getOperand(i) == V) return true;
    } else if (CallInst *CI = dyn_cast<CallInst>(*UI)) {
      // Make sure that this is just the function being called, not that it is
      // passing into the function.
      for (unsigned i = 1, e = CI->getNumOperands(); i != e; ++i)
        if (CI->getOperand(i) == V) return true;
    } else if (InvokeInst *II = dyn_cast<InvokeInst>(*UI)) {
      // Make sure that this is just the function being called, not that it is
      // passing into the function.
      for (unsigned i = 3, e = II->getNumOperands(); i != e; ++i)
        if (II->getOperand(i) == V) return true;
    } else if (ConstantExpr *CE = dyn_cast<ConstantExpr>(*UI)) {
      if (CE->getOpcode() == Instruction::GetElementPtr ||
          CE->getOpcode() == Instruction::Cast) {
        if (AnalyzeUsesOfGlobal(CE, Readers, Writers))
          return true;
      } else {
        return true;
      }
    } else if (GlobalValue *GV = dyn_cast<GlobalValue>(*UI)) {
      if (AnalyzeUsesOfGlobal(GV, Readers, Writers)) return true;
    } else {
      return true;
    }
  return false;
}

/// AnalyzeCallGraph - At this point, we know the functions where globals are
/// immediately stored to and read from.  Propagate this information up the call
/// graph to all callers and compute the mod/ref info for all memory for each
/// function.
void GlobalsModRef::AnalyzeCallGraph(CallGraph &CG, Module &M) {
  DEBUG(std::cerr << "GlobalsModRef: Analyze Call Graph\n");

  // We do a bottom-up SCC traversal of the call graph.  In other words, we
  // visit all callees before callers (leaf-first).
  for (scc_iterator<CallGraph*> I = scc_begin(&CG), E = scc_end(&CG); I!=E; ++I)
    // Do not call AnalyzeSCC on the external function node.
    if ((*I).size() != 1 || (*I)[0]->getFunction())
      AnalyzeSCC(*I);
}

void GlobalsModRef::AnalyzeSCC(std::vector<CallGraphNode *> &SCC) {
  assert(!SCC.empty() && "SCC with no functions?");
  FunctionRecord &FR = FunctionInfo[SCC[0]->getFunction()];

  bool CallsExternal = false;
  unsigned FunctionEffect = 0;

  // Collect the mod/ref properties due to called functions.  We only compute
  // one mod-ref set
  for (unsigned i = 0, e = SCC.size(); i != e && !CallsExternal; ++i)
    for (CallGraphNode::iterator CI = SCC[i]->begin(), E = SCC[i]->end();
         CI != E; ++CI)
      if (Function *Callee = (*CI)->getFunction()) {
        if (FunctionRecord *CalleeFR = getFunctionInfo(Callee)) {
          // Propagate function effect up.
          FunctionEffect |= CalleeFR->FunctionEffect;

          // Incorporate callee's effects on globals into our info.
          for (std::map<GlobalValue*, unsigned>::iterator GI =
                 CalleeFR->GlobalInfo.begin(), E = CalleeFR->GlobalInfo.end();
               GI != E; ++GI)
            FR.GlobalInfo[GI->first] |= GI->second;

        } else {
          CallsExternal = true;
          break;
        }
      } else {
        CallsExternal = true;
        break;
      }

  // If this SCC calls an external function, we can't say anything about it, so
  // remove all SCC functions from the FunctionInfo map.
  if (CallsExternal) {
    for (unsigned i = 0, e = SCC.size(); i != e; ++i)
      FunctionInfo.erase(SCC[i]->getFunction());
    return;
  }

  // Otherwise, unless we already know that this function mod/refs memory, scan
  // the function bodies to see if there are any explicit loads or stores.
  if (FunctionEffect != ModRef) {
    for (unsigned i = 0, e = SCC.size(); i != e && FunctionEffect != ModRef;++i)
      for (inst_iterator II = inst_begin(SCC[i]->getFunction()),
             E = inst_end(SCC[i]->getFunction());
           II != E && FunctionEffect != ModRef; ++II)
        if (isa<LoadInst>(*II))
          FunctionEffect |= Ref;
        else if (isa<StoreInst>(*II))
          FunctionEffect |= Mod;
  }

  if ((FunctionEffect & Mod) == 0)
    ++NumReadMemFunctions;
  if (FunctionEffect == 0)
    ++NumNoMemFunctions;
  FR.FunctionEffect = FunctionEffect;

  // Finally, now that we know the full effect on this SCC, clone the
  // information to each function in the SCC.
  for (unsigned i = 1, e = SCC.size(); i != e; ++i)
    FunctionInfo[SCC[i]->getFunction()] = FR;
}

/// getUnderlyingObject - This traverses the use chain to figure out what object
/// the specified value points to.  If the value points to, or is derived from,
/// a global object, return it.
static const GlobalValue *getUnderlyingObject(const Value *V) {
  if (!isa<PointerType>(V->getType())) return 0;

  // If we are at some type of object... return it.
  if (const GlobalValue *GV = dyn_cast<GlobalValue>(V)) return GV;

  // Traverse through different addressing mechanisms...
  if (const Instruction *I = dyn_cast<Instruction>(V)) {
    if (isa<CastInst>(I) || isa<GetElementPtrInst>(I))
      return getUnderlyingObject(I->getOperand(0));
  } else if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(V)) {
    if (CE->getOpcode() == Instruction::Cast ||
        CE->getOpcode() == Instruction::GetElementPtr)
      return getUnderlyingObject(CE->getOperand(0));
  }
  return 0;
}

/// alias - If one of the pointers is to a global that we are tracking, and the
/// other is some random pointer, we know there cannot be an alias, because the
/// address of the global isn't taken.
AliasAnalysis::AliasResult
GlobalsModRef::alias(const Value *V1, unsigned V1Size,
                     const Value *V2, unsigned V2Size) {
  GlobalValue *GV1 = const_cast<GlobalValue*>(getUnderlyingObject(V1));
  GlobalValue *GV2 = const_cast<GlobalValue*>(getUnderlyingObject(V2));

  // If the global's address is taken, pretend we don't know it's a pointer to
  // the global.
  if (GV1 && !NonAddressTakenGlobals.count(GV1)) GV1 = 0;
  if (GV2 && !NonAddressTakenGlobals.count(GV2)) GV2 = 0;

  if ((GV1 || GV2) && GV1 != GV2)
    return NoAlias;

  return AliasAnalysis::alias(V1, V1Size, V2, V2Size);
}

AliasAnalysis::ModRefResult
GlobalsModRef::getModRefInfo(CallSite CS, Value *P, unsigned Size) {
  unsigned Known = ModRef;

  // If we are asking for mod/ref info of a direct call with a pointer to a
  // global we are tracking, return information if we have it.
  if (GlobalValue *GV = const_cast<GlobalValue*>(getUnderlyingObject(P)))
    if (GV->hasInternalLinkage())
      if (Function *F = CS.getCalledFunction())
        if (NonAddressTakenGlobals.count(GV))
          if (FunctionRecord *FR = getFunctionInfo(F))
            Known = FR->getInfoForGlobal(GV);

  if (Known == NoModRef)
    return NoModRef; // No need to query other mod/ref analyses
  return ModRefResult(Known & AliasAnalysis::getModRefInfo(CS, P, Size));
}

//===----------------------------------------------------------------------===//
// Methods to update the analysis as a result of the client transformation.
//
void GlobalsModRef::deleteValue(Value *V) {
  if (GlobalValue *GV = dyn_cast<GlobalValue>(V))
    NonAddressTakenGlobals.erase(GV);
}

void GlobalsModRef::copyValue(Value *From, Value *To) {
}
<|endoftext|>