<commit_before>#include "readsTools.hpp"

#include <string>
#include <vector>
#include <iostream>

using namespace std;

//Static members/attributes;
const std::map<char,uint8_t> ReadsTools::nuc = {{'A',0},{'T',1},{'G',2},{'C',3},{'X',4}};

const std::vector< std::vector< int8_t > > ReadsTools::scoreMatrix =
	std::vector< std::vector< int8_t > > (5,
		std::vector<int8_t>(5,0)) = {
			//A T G C X(2nd id)
			{1,-1,-1,-1,-1}, //A (first id)
			{-1,1,-1,-1,-1}, //T (first id)
			{-1,-1,1,-1,-1}, //G (first id)
			{-1,-1,-1,1,-1}, //C (first id)
			{-1,-1,-1,-1,-1} //X (first id)
		};

	//function to get the best value in a matrix of int8_t (the scoreMatrix)
inline const int8_t bestValueInMatrix(vector< vector< int8_t> > matrix){
	if(!matrix.size() || !matrix[0].size()){
		cerr << "Error: matrix empty." << endl;
		return 0;
	}

	int8_t b = matrix[0][0];
	for(vector<vector<int8_t>>::const_iterator vi = matrix.cbegin(); vi != matrix.cend(); vi ++){
		for(vector<int8_t>::const_iterator vvi = vi->cbegin(); vvi != vi->cend(); vvi++){
			if(*vvi > b){b=*vvi;}
		}
	}
	return b;
}

const int8_t ReadsTools::bestScoreMatrix = bestValueInMatrix(scoreMatrix);
const int ReadsTools::gap_score = -1;

//Tool Public functions
//Function to get the score between 2 sequences (>0: normal couple, <0: seq2 is reversed-complement)
const int ReadsTools::scoreCmpReads(const std::string& read1, const string& read2){
	/* normal mapping */
	int best = scoreMatchingReads(read1,read2);

	/* read1 normal, read2 complementary (r2r) */
	string r2r = read2;
	const size_t r2size = read2.size();
	for(size_t i=0; i < r2size; i++){
		size_t r2id = r2size-1-i;
		switch(read2[i]){
			case 'A':
				r2r[r2id]='T';
				break;
			case 'T':
				r2r[r2id]='A';
				break;
			case 'G':
				r2r[r2id]='C';
				break;
			case 'C':
				r2r[r2id]='G';
				break;
			default:
				r2r[r2id]='A';
				break;
		}
	}
	int score = scoreMatchingReads(read1, r2r);

	if(best < score){best=score*(-1);}

	return best;
}

//Function to merge 2 sequences
const string ReadsTools::allignSeq(const string& seq1, const string& seq2){
	//Reminder: a needlemap has a size of seq1.size()+1 and seq1.size()+1
	//because the first line and first column must include an "empty" possibility
	struct Node {
		Node* previous = nullptr;
		size_t s1 = 0; //seq1 pos
		size_t s2 = 0; //seq2 pos
		int score=0;
	};
	vector< vector<Node> > needlemap (seq1.size()+1, vector<Node>(seq2.size()+1, Node()));

	/*
	cerr << "Merging following sequences" << endl;
	cerr << "Seq1:\n" << seq1 << endl;
	cerr << "Seq2:\n" << seq2 << endl;
	*/

	//Needlemap completion
		//first nuc (0,0)
		needlemap[0][0].score=scoreMatrix[nuc.at(seq1[0])][nuc.at(seq2[0])];
		//first line (we can begin anywere on the seq1 (reference) so
		//initial score is 0)
	for(size_t i=1; i < seq1.size()+1; i++){
		needlemap[i][0].score = 0;
		needlemap[i][0].previous = &needlemap[i-1][0];
		needlemap[i][0].s1=i-1;
	}
		//first column (we must match the beginning of the seq2)
	for(size_t i=1; i < seq2.size()+1; i++){
		needlemap[0][i].score = needlemap[0][i-1].score + gap_score;
		needlemap[0][i].previous = &needlemap[0][i-1];
		needlemap[0][i].s2=i-1;
	}

		//Do all other nodes (except last line and column)
	for(size_t i=1; i < seq1.size(); i++){
		for(size_t j=1; j < seq2.size(); j++){
				//Set position
			needlemap[i][j].s1=i-1;
			needlemap[i][j].s2=j-1;
				//(mis)match ?
			needlemap[i][j].score = needlemap[i-1][j-1].score +
				scoreMatrix[nuc.at(seq1[i-1])][nuc.at(seq2[j-1])];
			needlemap[i][j].previous = &needlemap[i-1][j-1];
				//seq1 gap ?
			int s = needlemap[i][j-1].score + gap_score;
			if(s > needlemap[i][j].score){
				needlemap[i][j].score = s;
				needlemap[i][j].previous = &needlemap[i][j-1];
			}
				//seq2 gap ?
			s = needlemap[i-1][j].score + gap_score;
			if(s > needlemap[i][j].score){
				needlemap[i][j].score = s;
				needlemap[i][j].previous = &needlemap[i-1][j];
			}
		}
	}

	//Last line and last column
	size_t n2 = seq2.size();
	for(size_t n1=1; n1 < seq1.size(); n1++){
		//Set pos
		needlemap[n1][n2].s1=n1-1;
		needlemap[n1][n2].s2=n2-1;

		//Match/mismatch ?
		needlemap[n1][n2].score = needlemap[n1-1][n2-1].score +
			scoreMatrix[nuc.at(seq1[n1-1])][nuc.at(seq2[n2-1])];
		needlemap[n1][n2].previous = &needlemap[n1-1][n2-1];

		//seq1 gap ?
		int s = needlemap[n1][n2-1].score+gap_score;
		if(s > needlemap[n1][n2].score){
			needlemap[n1][n2].score = s;
			needlemap[n1][n2].previous = &needlemap[n1][n2-1];
		}
		//seq2 gap ? (There is no gap_score as we can accept "gap" at the end )
		s = needlemap[n1-1][n2].score;
		if(s > needlemap[n1][n2].score){
			needlemap[n1][n2].score = s;
			needlemap[n1][n2].previous = &needlemap[n1-1][n2];
		}
	}
	size_t n1 = seq1.size();
	for(size_t n2=1; n2 < seq2.size(); n2++){
		//Set pos
		needlemap[n1][n2].s1=n1-1;
		needlemap[n1][n2].s2=n2-1;

		//Match/mismatch ?
		needlemap[n1][n2].score = needlemap[n1-1][n2-1].score +
			scoreMatrix[nuc.at(seq1[n1-1])][nuc.at(seq2[n2-1])];
		needlemap[n1][n2].previous = &needlemap[n1-1][n2-1];

		//seq1 gap ? (There is no gap_score as we can accept "gap" at the end)
		int s = needlemap[n1][n2-1].score;
		if(s > needlemap[n1][n2].score){
			needlemap[n1][n2].score = s;
			needlemap[n1][n2].previous = &needlemap[n1][n2-1];
		}
		//seq2 gap ?
		s = needlemap[n1-1][n2].score+gap_score;
		if(s > needlemap[n1][n2].score){
			needlemap[n1][n2].score = s;
			needlemap[n1][n2].previous = &needlemap[n1-1][n2];
		}
	}

	//Do last row
		//Set pos
	needlemap[n1][n2].s1=n1-1;
	needlemap[n1][n2].s2=n2-1;

		//match/mismatch
	needlemap[n1][n2].score = needlemap[n1-1][n2-1].score +
		scoreMatrix[nuc.at(seq1[n1-1])][nuc.at(seq2[n2-1])];
	needlemap[n1][n2].previous = &needlemap[n1-1][n2-1];

	//Gap (no gap_score as it is the end of reads)
	if(needlemap[n1][n2].score < needlemap[n1-1][n2].score){
		needlemap[n1][n2].score = needlemap[n1-1][n2].score;
		needlemap[n1][n2].previous = &needlemap[n1-1][n2];
	}
	if(needlemap[n1][n2].score < needlemap[n1][n2-1].score){
		needlemap[n1][n2].score = needlemap[n1][n2-1].score;
		needlemap[n1][n2].previous = &needlemap[n1][n2-1];
	}

	//Needlemap lecture (begin by the end : sequence is reversed)
	Node* n = &needlemap[n1][n2];
	if(n == nullptr || n->previous == nullptr){
		cerr << "Error in needlemap reading" << endl;
		return "error while creating the allignment";
	}
	Node* p = n->previous;
	string s = "";

		//Reconstruct all nucleotides
	while(p != nullptr){
		//Do the last nucleotide
		//If previous is s1-1 and s2-1 so it's a (mis)match
		//Else it is a gap
		if(p->s1 < n->s1 && p->s2 < n->s2){
			if(seq1[n->s1] == seq2[n->s2]){
				s += seq1[n->s1];
			}
			else { s += 'X';}
		}
			//seq1 gap
		else if (p->s1 == n->s1){
			s += seq2[n->s2];
		}
			//seq2 gap
		else {
			s += seq1[n->s1];
		}

		//Do previous
		n = p;
		p = n->previous;
	}

	//Return the consensus seq (reverse the needlemap result)
	return string(s.rbegin(), s.rend());

}

//Tool Private function
//Function to calculate the score between 2 sequences (no reverse-complement)
//It's based on needleman&wunsch using only 2 1D array of size of seq1 (and not
//a 2D array of size seq1*seq2. The 2 1D arrays are the compairason againt the actual
//seq1 nuc (seq1[n] <-> seq2) and the previous comparaison (seq1[n-1] <-> seq2)
const int ReadsTools::scoreMatchingReads(const string& read1, const string& read2){
	/*
	Calculing Comparaison score between the 2 read2s using
	needleman&wunsch algorithm without memoring the best path
	as we only need the score
	*/

	//Get the sequences length
	size_t len1 = read1.size();
	size_t len2 = read2.size();

	//Prepare the scoring arrays
	int* previous = new int[len2];
	int* current = new int[len2];
	int bestIN = 0; //bestIN is the best case of seq2 being completly inside seq1

	//Calculate the first line (seq2 againt seq1[0]
	//Note: we can't 'allow' a gap in seq2's "first nuc"
	previous[0] = ((read1[0]==read2[0])?1:-1);
	for(size_t j=1; j < len2; j++){ previous[j] = -j; }
	bestIN = previous[len2-1];

	//Complete the needle comparison
	for(size_t i=1; i < len1; i++){
		//Test the seq2's first nuc, a gap is allowed so it's just a (mis)match
		current[0] = ((read1[i]==read2[0])?1:-1);

		//Finish the line
		for(size_t j=1; j < len2; j++){
			//current[j] is the best of a match/mistach and both indels possibilities
			//Match/mismatch ?
			current[j] = previous[j-1] + ((read1[i]==read2[j])?1:-1);

			//indels ?
			current[j] = ((previous[j]-1 > current[j])?previous[j]-1:current[j]);
			current[j] = ((current[j-1]-1 > current[j])?current[j-1]-1:current[j]);
		}

		// Best of read2 being inside read1 ?
		bestIN = ((current[len2-1] > bestIN)?current[len2-1]:bestIN);

		//swap previous and current arrays
		int* swapbuf = previous;
		previous = current;
		current = swapbuf;
	}

	//get the best score
	for(size_t j=0; j<len2;j++){ bestIN = ((previous[j]>bestIN)?previous[j]:bestIN);}
	if(bestIN < 0){bestIN=0;} //security: we want a score >= 0
	int theomax = ((len1<len2)?len1:len2);

	//Clean memory
	delete[] previous;
	delete[] current;

	//Return best score (percent of bestIn based on theoric max (shorter reads size))
	return 100*bestIN/theomax;
}
<commit_msg>Correcting reads cmp in cpu. Work not over.<commit_after>#include "readsTools.hpp"

#include <string>
#include <vector>
#include <iostream>

using namespace std;

//Static members/attributes;
const std::map<char,uint8_t> ReadsTools::nuc = {{'A',0},{'T',1},{'G',2},{'C',3},{'X',4}};

const std::vector< std::vector< int8_t > > ReadsTools::scoreMatrix =
	std::vector< std::vector< int8_t > > (5,
		std::vector<int8_t>(5,0)) = {
			//A T G C X(2nd id)
			{1,-1,-1,-1,-1}, //A (first id)
			{-1,1,-1,-1,-1}, //T (first id)
			{-1,-1,1,-1,-1}, //G (first id)
			{-1,-1,-1,1,-1}, //C (first id)
			{-1,-1,-1,-1,-1} //X (first id)
		};

	//function to get the best value in a matrix of int8_t (the scoreMatrix)
inline const int8_t bestValueInMatrix(vector< vector< int8_t> > matrix){
	if(!matrix.size() || !matrix[0].size()){
		cerr << "Error: matrix empty." << endl;
		return 0;
	}

	int8_t b = matrix[0][0];
	for(vector<vector<int8_t>>::const_iterator vi = matrix.cbegin(); vi != matrix.cend(); vi ++){
		for(vector<int8_t>::const_iterator vvi = vi->cbegin(); vvi != vi->cend(); vvi++){
			if(*vvi > b){b=*vvi;}
		}
	}
	return b;
}

const int8_t ReadsTools::bestScoreMatrix = bestValueInMatrix(scoreMatrix);
const int ReadsTools::gap_score = -1;

//Tool Public functions
//Function to get the score between 2 sequences (>0: normal couple, <0: seq2 is reversed-complement)
const int ReadsTools::scoreCmpReads(const std::string& read1, const string& read2){
	/* normal mapping */
	int best = scoreMatchingReads(read1,read2);

	/* read1 normal, read2 complementary (r2r) */
	string r2r = read2;
	const size_t r2size = read2.size();
	for(size_t i=0; i < r2size; i++){
		size_t r2id = r2size-1-i;
		switch(read2[i]){
			case 'A':
				r2r[r2id]='T';
				break;
			case 'T':
				r2r[r2id]='A';
				break;
			case 'G':
				r2r[r2id]='C';
				break;
			case 'C':
				r2r[r2id]='G';
				break;
			default:
				r2r[r2id]='A';
				break;
		}
	}
	int score = scoreMatchingReads(read1, r2r);

	if(best < score){best=score*(-1);}

	return best;
}

//Function to merge 2 sequences
const string ReadsTools::allignSeq(const string& seq1, const string& seq2){
	//Reminder: a needlemap has a size of seq1.size()+1 and seq1.size()+1
	//because the first line and first column must include an "empty" possibility
	struct Node {
		Node* previous = nullptr;
		size_t s1 = 0; //seq1 pos
		size_t s2 = 0; //seq2 pos
		int score=0;
	};
	vector< vector<Node> > needlemap (seq1.size()+1, vector<Node>(seq2.size()+1, Node()));

	/*
	cerr << "Merging following sequences" << endl;
	cerr << "Seq1:\n" << seq1 << endl;
	cerr << "Seq2:\n" << seq2 << endl;
	*/

	//Needlemap completion
		//first nuc (0,0)
		needlemap[0][0].score=scoreMatrix[nuc.at(seq1[0])][nuc.at(seq2[0])];
		//first line (we can begin anywere on the seq1 (reference) so
		//initial score is 0)
	for(size_t i=1; i < seq1.size()+1; i++){
		needlemap[i][0].score = 0;
		needlemap[i][0].previous = &needlemap[i-1][0];
		needlemap[i][0].s1=i-1;
	}
		//first column (we must match the beginning of the seq2)
	for(size_t i=1; i < seq2.size()+1; i++){
		needlemap[0][i].score = needlemap[0][i-1].score + gap_score;
		needlemap[0][i].previous = &needlemap[0][i-1];
		needlemap[0][i].s2=i-1;
	}

		//Do all other nodes (except last line and column)
	for(size_t i=1; i < seq1.size(); i++){
		for(size_t j=1; j < seq2.size(); j++){
				//Set position
			needlemap[i][j].s1=i-1;
			needlemap[i][j].s2=j-1;
				//(mis)match ?
			needlemap[i][j].score = needlemap[i-1][j-1].score +
				scoreMatrix[nuc.at(seq1[i-1])][nuc.at(seq2[j-1])];
			needlemap[i][j].previous = &needlemap[i-1][j-1];
				//seq1 gap ?
			int s = needlemap[i][j-1].score + gap_score;
			if(s > needlemap[i][j].score){
				needlemap[i][j].score = s;
				needlemap[i][j].previous = &needlemap[i][j-1];
			}
				//seq2 gap ?
			s = needlemap[i-1][j].score + gap_score;
			if(s > needlemap[i][j].score){
				needlemap[i][j].score = s;
				needlemap[i][j].previous = &needlemap[i-1][j];
			}
		}
	}

	//Last line and last column
	size_t n2 = seq2.size();
	for(size_t n1=1; n1 < seq1.size(); n1++){
		//Set pos
		needlemap[n1][n2].s1=n1-1;
		needlemap[n1][n2].s2=n2-1;

		//Match/mismatch ?
		needlemap[n1][n2].score = needlemap[n1-1][n2-1].score +
			scoreMatrix[nuc.at(seq1[n1-1])][nuc.at(seq2[n2-1])];
		needlemap[n1][n2].previous = &needlemap[n1-1][n2-1];

		//seq1 gap ?
		int s = needlemap[n1][n2-1].score+gap_score;
		if(s > needlemap[n1][n2].score){
			needlemap[n1][n2].score = s;
			needlemap[n1][n2].previous = &needlemap[n1][n2-1];
		}
		//seq2 gap ? (There is no gap_score as we can accept "gap" at the end )
		s = needlemap[n1-1][n2].score;
		if(s > needlemap[n1][n2].score){
			needlemap[n1][n2].score = s;
			needlemap[n1][n2].previous = &needlemap[n1-1][n2];
		}
	}
	size_t n1 = seq1.size();
	for(size_t n2=1; n2 < seq2.size(); n2++){
		//Set pos
		needlemap[n1][n2].s1=n1-1;
		needlemap[n1][n2].s2=n2-1;

		//Match/mismatch ?
		needlemap[n1][n2].score = needlemap[n1-1][n2-1].score +
			scoreMatrix[nuc.at(seq1[n1-1])][nuc.at(seq2[n2-1])];
		needlemap[n1][n2].previous = &needlemap[n1-1][n2-1];

		//seq1 gap ? (There is no gap_score as we can accept "gap" at the end)
		int s = needlemap[n1][n2-1].score;
		if(s > needlemap[n1][n2].score){
			needlemap[n1][n2].score = s;
			needlemap[n1][n2].previous = &needlemap[n1][n2-1];
		}
		//seq2 gap ?
		s = needlemap[n1-1][n2].score+gap_score;
		if(s > needlemap[n1][n2].score){
			needlemap[n1][n2].score = s;
			needlemap[n1][n2].previous = &needlemap[n1-1][n2];
		}
	}

	//Do last row
		//Set pos
	needlemap[n1][n2].s1=n1-1;
	needlemap[n1][n2].s2=n2-1;

		//match/mismatch
	needlemap[n1][n2].score = needlemap[n1-1][n2-1].score +
		scoreMatrix[nuc.at(seq1[n1-1])][nuc.at(seq2[n2-1])];
	needlemap[n1][n2].previous = &needlemap[n1-1][n2-1];

	//Gap (no gap_score as it is the end of reads)
	if(needlemap[n1][n2].score < needlemap[n1-1][n2].score){
		needlemap[n1][n2].score = needlemap[n1-1][n2].score;
		needlemap[n1][n2].previous = &needlemap[n1-1][n2];
	}
	if(needlemap[n1][n2].score < needlemap[n1][n2-1].score){
		needlemap[n1][n2].score = needlemap[n1][n2-1].score;
		needlemap[n1][n2].previous = &needlemap[n1][n2-1];
	}

	//Needlemap lecture (begin by the end : sequence is reversed)
	Node* n = &needlemap[n1][n2];
	if(n == nullptr || n->previous == nullptr){
		cerr << "Error in needlemap reading" << endl;
		return "error while creating the allignment";
	}
	Node* p = n->previous;
	string s = "";

		//Reconstruct all nucleotides
	while(p != nullptr){
		//Do the last nucleotide
		//If previous is s1-1 and s2-1 so it's a (mis)match
		//Else it is a gap
		if(p->s1 < n->s1 && p->s2 < n->s2){
			if(seq1[n->s1] == seq2[n->s2]){
				s += seq1[n->s1];
			}
			else { s += 'X';}
		}
			//seq1 gap
		else if (p->s1 == n->s1){
			s += seq2[n->s2];
		}
			//seq2 gap
		else {
			s += seq1[n->s1];
		}

		//Do previous
		n = p;
		p = n->previous;
	}

	//Return the consensus seq (reverse the needlemap result)
	return string(s.rbegin(), s.rend());

}

//Tool Private function
//Function to calculate the score between 2 sequences (no reverse-complement)
//It's based on needleman&wunsch using only 2 1D array of size of seq1 (and not
//a 2D array of size seq1*seq2. The 2 1D arrays are the compairason againt the actual
//seq1 nuc (seq1[n] <-> seq2) and the previous comparaison (seq1[n-1] <-> seq2)
const int ReadsTools::scoreMatchingReads(const string& read1, const string& read2){
	/*
	Calculing Comparaison score between the 2 read2s using
	needleman&wunsch algorithm without memoring the best path
	as we only need the score
	*/

	//Get the sequences length
	size_t len1 = read1.size();
	size_t len2 = read2.size();

	//Prepare the scoring arrays
	int* previous = new int[len1];
	int* current = new int[len1];
	int bestIN = 0; //bestIN is the best case of seq2 being completly inside seq1

	//Calculate the first line (seq2[0] againt seq1)
	previous[0] = ((read1[0]==read2[0])?1:-1);
	for(size_t i=0; i < len1; i++){ previous[i] = ((read2[0]==read1[i])?1:-1);}
	bestIN = previous[len1-1];

	//Complete the needle comparison
	for(size_t j=1; j < len2; j++){
		//Test the seq1's first nuc:  is an indel as the first need to be seq2[0]
		current[0] = previous[0]-1;

		//Do others nucs of seq1
		for(size_t i=1; i < len1; i++){
			//current[j] is the best of a match/mistach and both indels possibilities
			//Match/mismatch ?
			current[i] = previous[i-1] + ((read1[i]==read2[j])?1:-1);

			//indels ?
			current[i] = previous[i]-1;
			current[i] = current[i-1]-1;
		}

		// Best of read2 being inside read1 ?
		bestIN = ((current[len1-1] > bestIN)?current[len1-1]:bestIN);

		//swap previous and current arrays
		int* swapbuf = previous;
		previous = current;
		current = swapbuf;
	}

	//get the best score
	for(size_t i=0; i<len1; i++){ bestIN = ((previous[i]>bestIN)?previous[i]:bestIN);}
	if(bestIN < 0){bestIN=0;} //security: we want a score >= 0
	int theomax = ((len1<len2)?len1:len2);

	//Clean memory
	delete[] previous;
	delete[] current;

	//Return best score (percent of bestIn based on theoric max (shorter reads size))
	return 100*bestIN/theomax;
}
<|endoftext|>


<commit_before>
#include "diff_solver.h"
#include "diff_system.h"
#include "dof_map.h"
#include "numeric_vector.h"
#include "unsteady_solver.h"

UnsteadySolver::UnsteadySolver (sys_type& s)
  : TimeSolver(s),
    reduce_deltat_on_diffsolver_failure(0),
    first_solve                  (true),
    old_local_nonlinear_solution (NumericVector<Number>::build())
{
}

UnsteadySolver::~UnsteadySolver ()
{
}

void UnsteadySolver::init ()
{
  TimeSolver::init();

  _system.add_vector("_old_nonlinear_solution");
}

void UnsteadySolver::solve ()
{
  if (first_solve)
    {
      advance_timestep();
      first_solve = false;
    }

  old_local_nonlinear_solution->init (_system.n_dofs());

  _system.get_vector("_old_nonlinear_solution").localize
    (*old_local_nonlinear_solution,
     _system.get_dof_map().get_send_list());

  unsigned int solve_result = _diff_solver->solve();

  // If we requested the UnsteadySolver to attempt reducing dt after a
  // failed DiffSolver solve, check the results of the solve now.
  if (reduce_deltat_on_diffsolver_failure)
    {
      bool backtracking_failed =
	solve_result & DiffSolver::DIVERGED_BACKTRACKING_FAILURE;

      bool max_iterations =
	solve_result & DiffSolver::DIVERGED_MAX_NONLINEAR_ITERATIONS;

      if (backtracking_failed || max_iterations)
	{
	  // Cut timestep in half
	  for (unsigned int nr=0; nr<reduce_deltat_on_diffsolver_failure; ++nr)
	    {
	      _system.deltat *= 0.5;
	      std::cout << "Newton backtracking failed.  Trying with smaller timestep, dt="
			<< _system.deltat << std::endl;

	      solve_result = _diff_solver->solve();

	      // Check solve results with reduced timestep
	      bool backtracking_failed =
		solve_result & DiffSolver::DIVERGED_BACKTRACKING_FAILURE;

	      bool max_iterations =
		solve_result & DiffSolver::DIVERGED_MAX_NONLINEAR_ITERATIONS;

	      if (!backtracking_failed && !max_iterations)
		{
		  if (!quiet)
		    std::cout << "Reduced dt solve succeeded." << std::endl;
		  return;
		}
	    }

	  // If we made it here, we still couldn't converge the solve after
	  // reducing deltat
	  std::cout << "DiffSolver::solve() did not succeed after "
		    << reduce_deltat_on_diffsolver_failure
		    << " attempts." << std::endl;
	  error();

  	} // end if (backtracking_failed || max_iterations)
    } // end if (reduce_deltat_on_diffsolver_failure)
}

void UnsteadySolver::advance_timestep ()
{
  NumericVector<Number> &old_nonlinear_solution =
  _system.get_vector("_old_nonlinear_solution");
  NumericVector<Number> &nonlinear_solution =
    *(_system.solution);

  old_nonlinear_solution = nonlinear_solution;

  if (!first_solve)
    _system.time += _system.deltat;
}

Number UnsteadySolver::old_nonlinear_solution(const unsigned int global_dof_number)
const
{
  assert (global_dof_number < _system.get_dof_map().n_dofs());
  assert (global_dof_number < old_local_nonlinear_solution->size());

  return (*old_local_nonlinear_solution)(global_dof_number);
}

Real UnsteadySolver::du(const SystemNorm &norm) const
{

  AutoPtr<NumericVector<Number> > solution_copy =
    _system.solution->clone();

  solution_copy->add(-1., _system.get_vector("_old_nonlinear_solution"));

  solution_copy->close();

  return _system.calculate_norm(solution_copy, norm);
}
<commit_msg>Minor bugfix<commit_after>
#include "diff_solver.h"
#include "diff_system.h"
#include "dof_map.h"
#include "numeric_vector.h"
#include "unsteady_solver.h"

UnsteadySolver::UnsteadySolver (sys_type& s)
  : TimeSolver(s),
    reduce_deltat_on_diffsolver_failure(0),
    first_solve                  (true),
    old_local_nonlinear_solution (NumericVector<Number>::build())
{
}

UnsteadySolver::~UnsteadySolver ()
{
}

void UnsteadySolver::init ()
{
  TimeSolver::init();

  _system.add_vector("_old_nonlinear_solution");
}

void UnsteadySolver::solve ()
{
  if (first_solve)
    {
      advance_timestep();
      first_solve = false;
    }

  old_local_nonlinear_solution->init (_system.n_dofs());

  _system.get_vector("_old_nonlinear_solution").localize
    (*old_local_nonlinear_solution,
     _system.get_dof_map().get_send_list());

  unsigned int solve_result = _diff_solver->solve();

  // If we requested the UnsteadySolver to attempt reducing dt after a
  // failed DiffSolver solve, check the results of the solve now.
  if (reduce_deltat_on_diffsolver_failure)
    {
      bool backtracking_failed =
	solve_result & DiffSolver::DIVERGED_BACKTRACKING_FAILURE;

      bool max_iterations =
	solve_result & DiffSolver::DIVERGED_MAX_NONLINEAR_ITERATIONS;

      if (backtracking_failed || max_iterations)
	{
	  // Cut timestep in half
	  for (unsigned int nr=0; nr<reduce_deltat_on_diffsolver_failure; ++nr)
	    {
	      _system.deltat *= 0.5;
	      std::cout << "Newton backtracking failed.  Trying with smaller timestep, dt="
			<< _system.deltat << std::endl;

	      solve_result = _diff_solver->solve();

	      // Check solve results with reduced timestep
	      bool backtracking_failed =
		solve_result & DiffSolver::DIVERGED_BACKTRACKING_FAILURE;

	      bool max_iterations =
		solve_result & DiffSolver::DIVERGED_MAX_NONLINEAR_ITERATIONS;

	      if (!backtracking_failed && !max_iterations)
		{
		  if (!quiet)
		    std::cout << "Reduced dt solve succeeded." << std::endl;
		  return;
		}
	    }

	  // If we made it here, we still couldn't converge the solve after
	  // reducing deltat
	  std::cout << "DiffSolver::solve() did not succeed after "
		    << reduce_deltat_on_diffsolver_failure
		    << " attempts." << std::endl;
	  error();

  	} // end if (backtracking_failed || max_iterations)
    } // end if (reduce_deltat_on_diffsolver_failure)
}

void UnsteadySolver::advance_timestep ()
{
  NumericVector<Number> &old_nonlinear_solution =
  _system.get_vector("_old_nonlinear_solution");
  NumericVector<Number> &nonlinear_solution =
    *(_system.solution);

  old_nonlinear_solution = nonlinear_solution;

  if (!first_solve)
    _system.time += _system.deltat;
}

Number UnsteadySolver::old_nonlinear_solution(const unsigned int global_dof_number)
const
{
  assert (global_dof_number < _system.get_dof_map().n_dofs());
  assert (global_dof_number < old_local_nonlinear_solution->size());

  return (*old_local_nonlinear_solution)(global_dof_number);
}

Real UnsteadySolver::du(const SystemNorm &norm) const
{

  AutoPtr<NumericVector<Number> > solution_copy =
    _system.solution->clone();

  solution_copy->add(-1., _system.get_vector("_old_nonlinear_solution"));

  solution_copy->close();

  return _system.calculate_norm(*solution_copy, norm);
}
<|endoftext|>


<commit_before>#include "transforms/DevirtFunctions.hh"
#include "llvm/Pass.h"
#include "llvm/Support/raw_ostream.h"

#include<set>
#include<algorithm>

using namespace llvm;

namespace previrt {
namespace transforms {

  static bool isIndirectCall(CallSite &CS) {
    Value *v = CS.getCalledValue ();
    if (!v) return false;

    v = v->stripPointerCasts ();
    return !isa<Function> (v);
  }

  static PointerType * getVoidPtrType(LLVMContext & C) {
    Type * Int8Type  = IntegerType::getInt8Ty(C);
    return PointerType::getUnqual(Int8Type);
  }

  static Value * castTo(Value * V, Type * Ty, std::string Name, Instruction * InsertPt) {
    // Don't bother creating a cast if it's already the correct type.
    if (V->getType() == Ty) return V;

    // If it's a constant, just create a constant expression.
    if (Constant * C = dyn_cast<Constant>(V))
    {
      Constant * CE = ConstantExpr::getZExtOrBitCast (C, Ty);
      return CE;
    }

    // Otherwise, insert a cast instruction.
    return CastInst::CreateZExtOrBitCast (V, Ty, Name, InsertPt);
  }

  Function* DevirtualizeFunctions::mkBounceFn(CallSite &CS, CallSiteResolver* CSR) {
    assert (isIndirectCall (CS) && "Not an indirect call");

    AliasSetId id = typeAliasId (CS);
    if (!CSR->useAliasing()) {
      // -- If we just use types then we can reuse the same bounce
      // -- function to avoid many duplicates.
      //
      // -- If we use Dsa we don't want to use the same bounce for the
      // -- same callee's type since the targets returned by Dsa can
      // -- be different from one callsite to another.
      auto it = m_bounceMap.find (id);
      if (it != m_bounceMap.end ()) return it->second;
    }

    // -- no direct calls in this alias set, nothing to construct
    if (!m_typeAliasSets.count(id)) return nullptr;

    // -- the final targets to build the bounce function
    AliasSet Targets;
    // -- all possible candidate targets whose type signatures matche
    AliasSet& TypesTargets = m_typeAliasSets [id];
    // -- targets provided by an external pointer analysis (optional)

    if (CSR->hasTargets(CS.getInstruction())) {
      // --- We filter out those targets whose signature do not match.
      AliasSet& AliasTargets = CSR->getTargets(CS.getInstruction());
      std::sort(TypesTargets.begin(), TypesTargets.end());
      std::sort(AliasTargets.begin(), AliasTargets.end());
      std::set_intersection(AliasTargets.begin(), AliasTargets.end(),
			    TypesTargets.begin(), TypesTargets.end(),
			    std::back_inserter(Targets));
    } else {
      // -- We did not have aliasing information so we just use types
      Targets = std::move(TypesTargets);
    }

    if (Targets.empty()) {
      // -- it's possible to be here if we had aliasing information
      // -- but it was not type consistent. If here, we won't able to
      // -- resolve the indirect call.
      return nullptr;
    }

    // Create a bounce function that has a function signature almost
    // identical to the function being called.  The only difference is
    // that it will have an additional pointer argument at the
    // beginning of its argument list that will be the function to
    // call.
    Value* ptr = CS.getCalledValue();
    SmallVector<Type*, 8> TP;
    TP.push_back (ptr->getType ());
    for (auto i = CS.arg_begin(), e = CS.arg_end (); i != e; ++i)
      TP.push_back ((*i)->getType());

    FunctionType* NewTy = FunctionType::get (CS.getType(), TP, false);
    Module * M = CS.getInstruction()->getParent()->getParent()->getParent();
    assert (M);
    Function* F = Function::Create (NewTy,
                                    GlobalValue::InternalLinkage,
                                    "seahorn.bounce",
                                    M);

    // Set the names of the arguments.  Also, record the arguments in a vector
    // for subsequence access.
    F->arg_begin()->setName("funcPtr");
    SmallVector<Value*, 8> fargs;
    auto ai = F->arg_begin();
    ++ai;
    for(auto ae = F->arg_end(); ai != ae; ++ai) {
      fargs.push_back(&*ai);
      ai->setName("arg");
    }

    // Create an entry basic block for the function.  All it should do is perform
    // some cast instructions and branch to the first comparison basic block.
    BasicBlock* entryBB = BasicBlock::Create (M->getContext(), "entry", F);

    // XXX: we sort Targets based on the name because otherwise the
    // order of the "case" statements in the switch can be different
    // with different OS or compiler. This has been a problem with
    // travis.
    std::sort(Targets.begin(), Targets.end(),
	      [](const Function *F1, const Function *F2) {
		if (F1->hasName() && F2->hasName()) {
		  return F1->getName() < F2->getName();
		} else {
		  return F1 < F2;
		}
	      });

    // For each function target, create a basic block that will call that
    // function directly.
    DenseMap<const Function*, BasicBlock*> targets;
    for (const Function *FL : Targets) {
      // Create the basic block for doing the direct call
      BasicBlock* BL = BasicBlock::Create (M->getContext(), FL->getName(), F);
      targets[FL] = BL;
      // Create the direct function call
      CallInst* directCall = CallInst::Create (const_cast<Function*>(FL),
                                               fargs, "", BL);
      // update call graph
      // if (m_cg) {
      //   auto fl_cg = m_cg->getOrInsertFunction (const_cast<Function*> (FL));
      //   auto cf_cg = m_cg->getOrInsertFunction (directCall->getCalledFunction ());
      //   fl_cg->addCalledFunction (CallSite (directCall), cf_cg);
      // }

      // Add the return instruction for the basic block
      if (CS.getType()->isVoidTy())
        ReturnInst::Create (M->getContext(), BL);
      else
        ReturnInst::Create (M->getContext(), directCall, BL);
    }

    BasicBlock * defaultBB = nullptr;
    if (m_allowIndirectCalls) {
      // Create a default basic block having the original indirect call
      defaultBB = BasicBlock::Create (M->getContext(), "default", F);
      if (CS.getType()->isVoidTy()) {
	ReturnInst::Create (M->getContext(), defaultBB);
      } else {
	CallInst *defaultRet = CallInst::Create(&*(F->arg_begin()), fargs, "", defaultBB);
	ReturnInst::Create (M->getContext(), defaultRet, defaultBB);
      }
    } else {
      // Create a failure basic block.  This basic block should simply be an
      // unreachable instruction.
      defaultBB = BasicBlock::Create (M->getContext(), "fail", F);
      new UnreachableInst (M->getContext(), defaultBB);
    }

    // Setup the entry basic block.  For now, just have it call the default
    // basic block.  We'll change the basic block to which it branches later.
    BranchInst * InsertPt = BranchInst::Create (defaultBB, entryBB);

    // Create basic blocks which will test the value of the incoming function
    // pointer and branch to the appropriate basic block to call the function.
    Type * VoidPtrType = getVoidPtrType (M->getContext());
    Value * FArg = castTo (&*(F->arg_begin()), VoidPtrType, "", InsertPt);
    BasicBlock * tailBB = defaultBB;
    for (const Function *FL : Targets)
    {

      // Cast the function pointer to an integer.  This can go in the entry
      // block.
      Value * TargetInt = castTo (const_cast<Function*>(FL),
                                  VoidPtrType,
                                  "",
                                  InsertPt);

      // Create a new basic block that compares the function pointer to the
      // function target.  If the function pointer matches, we'll branch to the
      // basic block performing the direct call for that function; otherwise,
      // we'll branch to the next function call target.
      BasicBlock* TB = targets [FL];
      BasicBlock* newB = BasicBlock::Create (M->getContext(),
                                             "test." + FL->getName(),
                                             F);
      CmpInst * setcc = CmpInst::Create (Instruction::ICmp,
                                         CmpInst::ICMP_EQ,
                                         TargetInt,
                                         FArg,
                                         "sc",
                                         newB);
      BranchInst::Create (TB, tailBB, setcc, newB);

      // Make this newly created basic block the next block that will be reached
      // when the next comparison will need to be done.
      tailBB = newB;
    }

    // Make the entry basic block branch to the first comparison basic block.
    InsertPt->setSuccessor(0, tailBB);

    // -- log the newly created function
    m_bounceMap.insert (std::make_pair (id, F));

    // Return the newly created bounce function.
    return F;
  }

  void DevirtualizeFunctions::mkDirectCall(CallSite CS, CallSiteResolver* CSR) {
    const Function *bounceFn = mkBounceFn(CS, CSR);
    // -- something failed
    if (!bounceFn) return;

    // Replace the original call with a call to the bounce function.
    if (CallInst* CI = dyn_cast<CallInst>(CS.getInstruction())) {
      // The last operand in the op list is the callee
      SmallVector<Value*, 8> Params;
      Params.reserve (std::distance (CI->op_begin(), CI->op_end()));
      Params.push_back (*(CI->op_end () - 1));
      Params.insert (Params.end (), CI->op_begin(), (CI->op_end() - 1));
      std::string name = CI->hasName() ? CI->getName().str() + ".dv" : "";
      CallInst* CN = CallInst::Create (const_cast<Function*>(bounceFn),
                                       Params,
                                       name,
                                       CI);

      // update call graph
      // if (m_cg) {
      //   m_cg->getOrInsertFunction (const_cast<Function*> (bounceFn));
      //   (*m_cg)[CI->getParent ()->getParent ()]->addCalledFunction
      //     (CallSite (CN), (*m_cg)[CN->getCalledFunction ()]);
      // }

      CN->setDebugLoc (CI->getDebugLoc ());
      CI->replaceAllUsesWith(CN);
      CI->eraseFromParent();
    }
    else if (InvokeInst* CI = dyn_cast<InvokeInst>(CS.getInstruction())) {
      SmallVector<Value*, 8> Params;
      Params.reserve (std::distance (CI->arg_operands().begin (),
                                     CI->arg_operands().end ()));
      // insert first the callee
      Params.push_back (CI->getCalledValue ());
      Params.insert (Params.end (),
                     CI->arg_operands().begin (),
                     CI->arg_operands().end());

      std::string name = CI->hasName() ? CI->getName().str() + ".dv" : "";
      InvokeInst* CN = InvokeInst::Create (const_cast<Function*>(bounceFn),
                                           CI->getNormalDest(),
                                           CI->getUnwindDest(),
                                           Params,
                                           name,
                                           CI);

      // update call graph
      // if (m_cg) {
      //   m_cg->getOrInsertFunction (const_cast<Function*> (bounceFn));
      //   (*m_cg)[CI->getParent ()->getParent ()]->addCalledFunction
      //     (CallSite (CN), (*m_cg)[CN->getCalledFunction ()]);
      // }

      CN->setDebugLoc (CI->getDebugLoc ());
      CI->replaceAllUsesWith(CN);
      CI->eraseFromParent();
    }
    return;
  }

  void DevirtualizeFunctions::visitCallSite (CallSite &CS) {
    // -- skip direct calls
    if (!isIndirectCall (CS)) return;

    // This is an indirect call site.  Put it in the worklist of call
    // sites to transforms.
    m_worklist.push_back (CS.getInstruction());
    return;
  }

  void DevirtualizeFunctions::visitCallInst(CallInst &CI) {
    // we cannot take the address of an inline asm
    if (CI.isInlineAsm ()) return;

    CallSite CS(&CI);
    visitCallSite(CS);
  }

  void DevirtualizeFunctions::visitInvokeInst(InvokeInst &II) {
    CallSite CS(&II);
    visitCallSite(CS);
  }

  DevirtualizeFunctions::AliasSetId DevirtualizeFunctions::typeAliasId (CallSite &CS) {
    assert (isIndirectCall (CS) && "Not an indirect call");
    PointerType *pTy = dyn_cast<PointerType> (CS.getCalledValue ()->getType ());
    assert (pTy && "Unexpected call not through a pointer");
    assert (isa<FunctionType> (pTy->getElementType ())
	    && "The type of called value is not a pointer to a function");
    return pTy;
  }

  /// returns an id of an alias set to which this function belongs
  DevirtualizeFunctions::AliasSetId DevirtualizeFunctions::typeAliasId(const Function &F) {
    return F.getFunctionType ()->getPointerTo ();
  }

  DevirtualizeFunctions::DevirtualizeFunctions(llvm::CallGraph* cg,
					       bool allowIndirectCalls)
    : /*m_cg(cg), */
      m_allowIndirectCalls(allowIndirectCalls)
  {}

  void DevirtualizeFunctions::computeTypeAliasSets(Module& M) {
    // -- Create type-based alias sets
    for (auto const &F: M) {
      // -- intrinsics are never called indirectly
      if (F.isIntrinsic ()) continue;

      // -- local functions whose address is not taken cannot be
      // -- resolved by a function pointer
      if (F.hasLocalLinkage () && !F.hasAddressTaken ()) continue;

      // -- skip calls to declarations, these are resolved implicitly
      // -- by calling through the function pointer argument in the
      // -- default case of bounce function

      // XXX: In OCCAM, it's common to take the address of an external
      // function if declared in another library.
      //
      //if (F.isDeclaration ()) continue;

      // -- skip seahorn and verifier specific intrinsics
      if (F.getName().startswith ("seahorn.")) continue;
      if (F.getName().startswith ("verifier.")) continue;
      // -- assume entry point is never called indirectly
      if (F.getName ().equals ("main")) continue;

      // -- add F to its corresponding alias set
      m_typeAliasSets[DevirtualizeFunctions::typeAliasId(F)].push_back(&F);
    }
  }

  bool DevirtualizeFunctions::resolveCallSites(Module & M, CallSiteResolver* CSR) {
    // -- Compute type alias sets if not computed already
    if (m_typeAliasSets.empty()) {
      computeTypeAliasSets(M);
    }

    // -- Visit all of the call instructions in this function and
    // -- record those that are indirect function calls.
    visit(M);

    // -- Now go through and transform all of the indirect calls that
    // -- we found that need transforming.
    bool Changed = !m_worklist.empty ();
    for (auto I : m_worklist) {
      CallSite CS(I);
      mkDirectCall(CS, CSR);
    }
    // -- Conservatively assume that we've changed one or more call
    // -- sites.
    return Changed;
  }

} // end namespace
} // end namespace
<commit_msg>Fix when the return of a call is optimized away<commit_after>#include "transforms/DevirtFunctions.hh"
#include "llvm/Pass.h"
#include "llvm/Support/raw_ostream.h"

#include<set>
#include<algorithm>

using namespace llvm;

namespace previrt {
namespace transforms {

  static bool isIndirectCall(CallSite &CS) {
    Value *v = CS.getCalledValue ();
    if (!v) return false;

    v = v->stripPointerCasts ();
    return !isa<Function> (v);
  }

  static PointerType * getVoidPtrType(LLVMContext & C) {
    Type * Int8Type  = IntegerType::getInt8Ty(C);
    return PointerType::getUnqual(Int8Type);
  }

  static Value * castTo(Value * V, Type * Ty, std::string Name, Instruction * InsertPt) {
    // Don't bother creating a cast if it's already the correct type.
    if (V->getType() == Ty) return V;

    // If it's a constant, just create a constant expression.
    if (Constant * C = dyn_cast<Constant>(V))
    {
      Constant * CE = ConstantExpr::getZExtOrBitCast (C, Ty);
      return CE;
    }

    // Otherwise, insert a cast instruction.
    return CastInst::CreateZExtOrBitCast (V, Ty, Name, InsertPt);
  }

  Function* DevirtualizeFunctions::mkBounceFn(CallSite &CS, CallSiteResolver* CSR) {
    assert (isIndirectCall (CS) && "Not an indirect call");

    AliasSetId id = typeAliasId (CS);
    if (!CSR->useAliasing()) {
      // -- If we just use types then we can reuse the same bounce
      // -- function to avoid many duplicates.
      //
      // -- If we use Dsa we don't want to use the same bounce for the
      // -- same callee's type since the targets returned by Dsa can
      // -- be different from one callsite to another.
      auto it = m_bounceMap.find (id);
      if (it != m_bounceMap.end ()) return it->second;
    }

    // -- no direct calls in this alias set, nothing to construct
    if (!m_typeAliasSets.count(id)) {
      llvm::errs() << "Devirt: no function defined in the current module matches type signature of "
		   << *CS.getInstruction() << "\n";
      return nullptr;
    }

    // -- the final targets to build the bounce function
    AliasSet Targets;
    // -- all possible candidate targets whose type signatures matche
    AliasSet& TypesTargets = m_typeAliasSets [id];
    // -- targets provided by an external pointer analysis (optional)

    if (CSR->hasTargets(CS.getInstruction())) {
      // --- We filter out those targets whose signature do not match.
      AliasSet& AliasTargets = CSR->getTargets(CS.getInstruction());
      std::sort(TypesTargets.begin(), TypesTargets.end());
      std::sort(AliasTargets.begin(), AliasTargets.end());
      std::set_intersection(AliasTargets.begin(), AliasTargets.end(),
			    TypesTargets.begin(), TypesTargets.end(),
			    std::back_inserter(Targets));
    } else {
      // -- We did not have aliasing information so we just use types
      Targets = std::move(TypesTargets);
    }

    if (Targets.empty()) {
      // -- it's possible to be here if we had aliasing information
      // -- but it was not type consistent. If here, we won't able to
      // -- resolve the indirect call.
      llvm::errs() << "Devirt: no callees after filtering out aliasing candidates with type information "
		   << *CS.getInstruction() << "\n";
      return nullptr;
    }

    // Create a bounce function that has a function signature almost
    // identical to the function being called.  The only difference is
    // that it will have an additional pointer argument at the
    // beginning of its argument list that will be the function to
    // call.
    Value* ptr = CS.getCalledValue();
    SmallVector<Type*, 8> TP;
    TP.push_back (ptr->getType ());
    for (auto i = CS.arg_begin(), e = CS.arg_end (); i != e; ++i)
      TP.push_back ((*i)->getType());

    FunctionType* NewTy = FunctionType::get (CS.getType(), TP, false);
    Module * M = CS.getInstruction()->getParent()->getParent()->getParent();
    assert (M);
    Function* F = Function::Create (NewTy,
                                    GlobalValue::InternalLinkage,
                                    "seahorn.bounce",
                                    M);

    // Set the names of the arguments.  Also, record the arguments in a vector
    // for subsequence access.
    F->arg_begin()->setName("funcPtr");
    SmallVector<Value*, 8> fargs;
    auto ai = F->arg_begin();
    ++ai;
    for(auto ae = F->arg_end(); ai != ae; ++ai) {
      fargs.push_back(&*ai);
      ai->setName("arg");
    }

    // Create an entry basic block for the function.  All it should do is perform
    // some cast instructions and branch to the first comparison basic block.
    BasicBlock* entryBB = BasicBlock::Create (M->getContext(), "entry", F);

    // XXX: we sort Targets based on the name because otherwise the
    // order of the "case" statements in the switch can be different
    // with different OS or compiler. This has been a problem with
    // travis.
    std::sort(Targets.begin(), Targets.end(),
	      [](const Function *F1, const Function *F2) {
		if (F1->hasName() && F2->hasName()) {
		  return F1->getName() < F2->getName();
		} else {
		  return F1 < F2;
		}
	      });

    // For each function target, create a basic block that will call that
    // function directly.
    DenseMap<const Function*, BasicBlock*> targets;
    for (const Function *FL : Targets) {
      // Create the basic block for doing the direct call
      BasicBlock* BL = BasicBlock::Create (M->getContext(), FL->getName(), F);
      targets[FL] = BL;
      // Create the direct function call
      CallInst* directCall = CallInst::Create (const_cast<Function*>(FL),
                                               fargs, "", BL);
      // update call graph
      // if (m_cg) {
      //   auto fl_cg = m_cg->getOrInsertFunction (const_cast<Function*> (FL));
      //   auto cf_cg = m_cg->getOrInsertFunction (directCall->getCalledFunction ());
      //   fl_cg->addCalledFunction (CallSite (directCall), cf_cg);
      // }

      // Add the return instruction for the basic block
      if (CS.getType()->isVoidTy())
        ReturnInst::Create (M->getContext(), BL);
      else
        ReturnInst::Create (M->getContext(), directCall, BL);
    }

    BasicBlock * defaultBB = nullptr;
    if (m_allowIndirectCalls) {
      // Create a default basic block having the original indirect call
      defaultBB = BasicBlock::Create (M->getContext(), "default", F);
      if (CS.getType()->isVoidTy()) {
	ReturnInst::Create (M->getContext(), defaultBB);
      } else {
	CallInst *defaultRet = CallInst::Create(&*(F->arg_begin()), fargs, "", defaultBB);
	ReturnInst::Create (M->getContext(), defaultRet, defaultBB);
      }
    } else {
      // Create a failure basic block.  This basic block should simply be an
      // unreachable instruction.
      defaultBB = BasicBlock::Create (M->getContext(), "fail", F);
      new UnreachableInst (M->getContext(), defaultBB);
    }

    // Setup the entry basic block.  For now, just have it call the default
    // basic block.  We'll change the basic block to which it branches later.
    BranchInst * InsertPt = BranchInst::Create (defaultBB, entryBB);

    // Create basic blocks which will test the value of the incoming function
    // pointer and branch to the appropriate basic block to call the function.
    Type * VoidPtrType = getVoidPtrType (M->getContext());
    Value * FArg = castTo (&*(F->arg_begin()), VoidPtrType, "", InsertPt);
    BasicBlock * tailBB = defaultBB;
    for (const Function *FL : Targets)
    {

      // Cast the function pointer to an integer.  This can go in the entry
      // block.
      Value * TargetInt = castTo (const_cast<Function*>(FL),
                                  VoidPtrType,
                                  "",
                                  InsertPt);

      // Create a new basic block that compares the function pointer to the
      // function target.  If the function pointer matches, we'll branch to the
      // basic block performing the direct call for that function; otherwise,
      // we'll branch to the next function call target.
      BasicBlock* TB = targets [FL];
      BasicBlock* newB = BasicBlock::Create (M->getContext(),
                                             "test." + FL->getName(),
                                             F);
      CmpInst * setcc = CmpInst::Create (Instruction::ICmp,
                                         CmpInst::ICMP_EQ,
                                         TargetInt,
                                         FArg,
                                         "sc",
                                         newB);
      BranchInst::Create (TB, tailBB, setcc, newB);

      // Make this newly created basic block the next block that will be reached
      // when the next comparison will need to be done.
      tailBB = newB;
    }

    // Make the entry basic block branch to the first comparison basic block.
    InsertPt->setSuccessor(0, tailBB);

    // -- log the newly created function
    m_bounceMap.insert (std::make_pair (id, F));

    // Return the newly created bounce function.
    return F;
  }

  void DevirtualizeFunctions::mkDirectCall(CallSite CS, CallSiteResolver* CSR) {
    const Function *bounceFn = mkBounceFn(CS, CSR);
    // -- something failed
    if (!bounceFn) return;

    // Replace the original call with a call to the bounce function.
    if (CallInst* CI = dyn_cast<CallInst>(CS.getInstruction())) {
      // The last operand in the op list is the callee
      SmallVector<Value*, 8> Params;
      Params.reserve (std::distance (CI->op_begin(), CI->op_end()));
      Params.push_back (*(CI->op_end () - 1));
      Params.insert (Params.end (), CI->op_begin(), (CI->op_end() - 1));
      std::string name = CI->hasName() ? CI->getName().str() + ".dv" : "";
      CallInst* CN = CallInst::Create (const_cast<Function*>(bounceFn),
                                       Params,
                                       name,
                                       CI);

      // update call graph
      // if (m_cg) {
      //   m_cg->getOrInsertFunction (const_cast<Function*> (bounceFn));
      //   (*m_cg)[CI->getParent ()->getParent ()]->addCalledFunction
      //     (CallSite (CN), (*m_cg)[CN->getCalledFunction ()]);
      // }

      CN->setDebugLoc (CI->getDebugLoc ());
      CI->replaceAllUsesWith(CN);
      CI->eraseFromParent();
    }
    else if (InvokeInst* CI = dyn_cast<InvokeInst>(CS.getInstruction())) {
      SmallVector<Value*, 8> Params;
      Params.reserve (std::distance (CI->arg_operands().begin (),
                                     CI->arg_operands().end ()));
      // insert first the callee
      Params.push_back (CI->getCalledValue ());
      Params.insert (Params.end (),
                     CI->arg_operands().begin (),
                     CI->arg_operands().end());

      std::string name = CI->hasName() ? CI->getName().str() + ".dv" : "";
      InvokeInst* CN = InvokeInst::Create (const_cast<Function*>(bounceFn),
                                           CI->getNormalDest(),
                                           CI->getUnwindDest(),
                                           Params,
                                           name,
                                           CI);

      // update call graph
      // if (m_cg) {
      //   m_cg->getOrInsertFunction (const_cast<Function*> (bounceFn));
      //   (*m_cg)[CI->getParent ()->getParent ()]->addCalledFunction
      //     (CallSite (CN), (*m_cg)[CN->getCalledFunction ()]);
      // }

      CN->setDebugLoc (CI->getDebugLoc ());
      CI->replaceAllUsesWith(CN);
      CI->eraseFromParent();
    }
    return;
  }

  void DevirtualizeFunctions::visitCallSite (CallSite &CS) {
    // -- skip direct calls
    if (!isIndirectCall (CS)) return;

    // This is an indirect call site.  Put it in the worklist of call
    // sites to transforms.
    m_worklist.push_back (CS.getInstruction());
    return;
  }

  void DevirtualizeFunctions::visitCallInst(CallInst &CI) {
    // we cannot take the address of an inline asm
    if (CI.isInlineAsm ()) return;

    CallSite CS(&CI);
    visitCallSite(CS);
  }

  void DevirtualizeFunctions::visitInvokeInst(InvokeInst &II) {
    CallSite CS(&II);
    visitCallSite(CS);
  }

  DevirtualizeFunctions::AliasSetId DevirtualizeFunctions::typeAliasId (CallSite &CS) {
    assert (isIndirectCall (CS) && "Not an indirect call");
    PointerType *pTy = nullptr;

    /*
      %390 = load void (i8*, i32*, i32*, i64, i32)*,
                        void (i8*, i32*, i32*, i64, i32)**
			bitcast (i64 (i8*, i32*, i32*, i64, i32)** @listdir to
                                 void (i8*, i32*, i32*, i64, i32)**)
      call void %390(i8* %385, i32* %1, i32* %2, i64 %139, i32 %26)
    */
    if (LoadInst* LI = dyn_cast<LoadInst>(CS.getCalledValue())) {
      if (Constant* C = dyn_cast<Constant>(LI->getPointerOperand())) {
	if (ConstantExpr* CE = dyn_cast<ConstantExpr>(C)) {
	  if (CE->getOpcode() == Instruction::BitCast) {
	    if (PointerType *ppTy = dyn_cast<PointerType>(CE->getOperand(0)->getType())) {
	      pTy = dyn_cast<PointerType>(ppTy->getElementType());
	      if (pTy) {
		assert (isa<FunctionType>(pTy->getElementType())
			&& "The type of called value is not a pointer to a function");
	      }
	    }
	  }
	}
      }
    }

    if (pTy) {
      return pTy;
    }

    pTy = dyn_cast<PointerType> (CS.getCalledValue()->getType ());
    assert (pTy && "Unexpected call not through a pointer");
    assert (isa<FunctionType> (pTy->getElementType ())
	    && "The type of called value is not a pointer to a function");
    return pTy;
  }

  /// returns an id of an alias set to which this function belongs
  DevirtualizeFunctions::AliasSetId DevirtualizeFunctions::typeAliasId(const Function &F) {
    return F.getFunctionType ()->getPointerTo ();
  }

  DevirtualizeFunctions::DevirtualizeFunctions(llvm::CallGraph* cg,
					       bool allowIndirectCalls)
    : /*m_cg(cg), */
      m_allowIndirectCalls(allowIndirectCalls)
  {}

  void DevirtualizeFunctions::computeTypeAliasSets(Module& M) {
    // -- Create type-based alias sets
    for (auto const &F: M) {
      // -- intrinsics are never called indirectly
      if (F.isIntrinsic ()) continue;

      // -- local functions whose address is not taken cannot be
      // -- resolved by a function pointer
      if (F.hasLocalLinkage () && !F.hasAddressTaken ()) continue;

      // -- skip calls to declarations, these are resolved implicitly
      // -- by calling through the function pointer argument in the
      // -- default case of bounce function

      // XXX: In OCCAM, it's common to take the address of an external
      // function if declared in another library.
      //
      //if (F.isDeclaration ()) continue;

      // -- skip seahorn and verifier specific intrinsics
      if (F.getName().startswith ("seahorn.")) continue;
      if (F.getName().startswith ("verifier.")) continue;
      // -- assume entry point is never called indirectly
      if (F.getName ().equals ("main")) continue;

      // -- add F to its corresponding alias set
      m_typeAliasSets[DevirtualizeFunctions::typeAliasId(F)].push_back(&F);
    }
  }

  bool DevirtualizeFunctions::resolveCallSites(Module & M, CallSiteResolver* CSR) {
    // -- Compute type alias sets if not computed already
    if (m_typeAliasSets.empty()) {
      computeTypeAliasSets(M);
    }

    // -- Visit all of the call instructions in this function and
    // -- record those that are indirect function calls.
    visit(M);

    // -- Now go through and transform all of the indirect calls that
    // -- we found that need transforming.
    bool Changed = !m_worklist.empty ();
    for (auto I : m_worklist) {
      CallSite CS(I);
      mkDirectCall(CS, CSR);
    }
    // -- Conservatively assume that we've changed one or more call
    // -- sites.
    return Changed;
  }

} // end namespace
} // end namespace
<|endoftext|>


<commit_before>// Copyright © 2015, German Neuroinformatics Node (G-Node)
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted under the terms of the BSD License. See
// LICENSE file in the root of the Project.
//
// Author: Christian Kellner <kellner@bio.lmu.de>

#ifndef NIX_VARIANT_H
#define NIX_VARIANT_H

#include <nix/DataType.hpp>
#include <nix/Platform.hpp>
#include <nix/None.hpp>

#include <string>
#include <cstdint>
#include <stdexcept>
#include <iostream>

namespace nix {
/**
 * @brief Class that can hold either a bool, double, (u)int(34|64) or a string.
 */
class NIXAPI Variant {
private:
    DataType dtype;

    union {
        bool v_bool;
        double v_double;
        uint32_t v_uint32;
        int32_t v_int32;
        uint64_t v_uint64;
        int64_t v_int64;
        char *v_string;
    };

public:
    Variant() : dtype(DataType::Nothing), v_bool(false) { }

    explicit Variant(char *value) : dtype(DataType::Nothing) {
        set(value);
    }

    explicit Variant(const char *value) : dtype(DataType::Nothing) {
        set(value);
    }

    template<typename T>
    explicit Variant(const T &value) : dtype(DataType::Nothing) {
        set(value);
    }

    template<size_t N>
    explicit Variant(const char (&value)[N]) : dtype(DataType::Nothing) {
        set(value, N);
    }

    Variant(const Variant &other) : Variant() {
        assign_variant_from(other);
    }

    Variant(Variant &&other) NOEXCEPT : Variant() {
        swap(other);
    }

    Variant &operator=(Variant other) {
        swap(other);
        return *this;
    }

    virtual ~Variant() {
        maybe_deallocte_string();
    }

    void set(none_t);
    void set(bool value);
    void set(int32_t value);
    void set(uint32_t value);
    void set(int64_t value);
    void set(uint64_t value);
    void set(double value);
    void set(const char *value, const size_t len);
    void set(const char *value);
    void set(const std::string &value);

    template<typename T>
    T get() const {
        T temp;
        get(temp);
        return temp;
    }

    void get(none_t &tag) const;
    void get(bool &out) const;
    void get(int32_t &value) const;
    void get(uint32_t &value) const;
    void get(int64_t &value) const;
    void get(uint64_t &value) const;
    void get(double &value) const;
    void get(std::string &value) const;

    DataType type() const {
        return dtype;
    }

    void swap(Variant &other);

    static bool supports_type(DataType dtype);

private:

    template<typename T>
    void swap_helper(Variant &other) {
        T temp = get<T>();
        assign_variant_from(other);
        other.set(temp);
    }

    void assign_variant_from(const Variant &other);

    void maybe_deallocte_string();

    inline void check_argument_type(DataType check) const {
        if (dtype != check) {
            throw std::invalid_argument("Incompatible DataType");
        }
    }
};

template<>
inline const char *Variant::get<const char *>() const {
    check_argument_type(DataType::String);
    return v_string;
}

template<>
inline const none_t Variant::get<>() const {
    return nix::none;
}

template<>
inline void Variant::swap_helper<none_t>(Variant &other) {
    assign_variant_from(other);
    other.set(nix::none);
}

NIXAPI std::ostream &operator<<(std::ostream &out, const Variant &value);
NIXAPI bool operator==(const Variant &a, const Variant &b);
inline bool operator!=(const Variant &a, const Variant &b) { return !(a == b); }
NIXAPI void swap(Variant &a, Variant &b);

} // nix::
#endif<commit_msg>Variant: move, assignment op: don't use swap<commit_after>// Copyright © 2015, German Neuroinformatics Node (G-Node)
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted under the terms of the BSD License. See
// LICENSE file in the root of the Project.
//
// Author: Christian Kellner <kellner@bio.lmu.de>

#ifndef NIX_VARIANT_H
#define NIX_VARIANT_H

#include <nix/DataType.hpp>
#include <nix/Platform.hpp>
#include <nix/None.hpp>

#include <string>
#include <cstdint>
#include <stdexcept>
#include <iostream>

namespace nix {
/**
 * @brief Class that can hold either a bool, double, (u)int(34|64) or a string.
 */
class NIXAPI Variant {
private:
    DataType dtype;

    union {
        bool v_bool;
        double v_double;
        uint32_t v_uint32;
        int32_t v_int32;
        uint64_t v_uint64;
        int64_t v_int64;
        char *v_string;
    };

public:
    Variant() : dtype(DataType::Nothing), v_bool(false) { }

    explicit Variant(char *value) : dtype(DataType::Nothing) {
        set(value);
    }

    explicit Variant(const char *value) : dtype(DataType::Nothing) {
        set(value);
    }

    template<typename T>
    explicit Variant(const T &value) : dtype(DataType::Nothing) {
        set(value);
    }

    template<size_t N>
    explicit Variant(const char (&value)[N]) : dtype(DataType::Nothing) {
        set(value, N);
    }

    Variant(const Variant &other) : Variant() {
        assign_variant_from(other);
    }

    Variant(Variant &&other) NOEXCEPT : Variant() {
        if (other.dtype == DataType::String) {
            v_string = other.v_string;
            dtype = DataType::String;
            other.dtype = DataType::Nothing;
            other.v_string = nullptr;
        } else {
            assign_variant_from(other);
        }
    }

    Variant &operator=(Variant other) {
        assign_variant_from(other);
        return *this;
    }

    virtual ~Variant() {
        maybe_deallocte_string();
    }

    void set(none_t);
    void set(bool value);
    void set(int32_t value);
    void set(uint32_t value);
    void set(int64_t value);
    void set(uint64_t value);
    void set(double value);
    void set(const char *value, const size_t len);
    void set(const char *value);
    void set(const std::string &value);

    template<typename T>
    T get() const {
        T temp;
        get(temp);
        return temp;
    }

    void get(none_t &tag) const;
    void get(bool &out) const;
    void get(int32_t &value) const;
    void get(uint32_t &value) const;
    void get(int64_t &value) const;
    void get(uint64_t &value) const;
    void get(double &value) const;
    void get(std::string &value) const;

    DataType type() const {
        return dtype;
    }

    void swap(Variant &other);

    static bool supports_type(DataType dtype);

private:

    template<typename T>
    void swap_helper(Variant &other) {
        T temp = get<T>();
        assign_variant_from(other);
        other.set(temp);
    }

    void assign_variant_from(const Variant &other);

    void maybe_deallocte_string();

    inline void check_argument_type(DataType check) const {
        if (dtype != check) {
            throw std::invalid_argument("Incompatible DataType");
        }
    }
};

template<>
inline const char *Variant::get<const char *>() const {
    check_argument_type(DataType::String);
    return v_string;
}

template<>
inline const none_t Variant::get<>() const {
    return nix::none;
}

template<>
inline void Variant::swap_helper<none_t>(Variant &other) {
    assign_variant_from(other);
    other.set(nix::none);
}

NIXAPI std::ostream &operator<<(std::ostream &out, const Variant &value);
NIXAPI bool operator==(const Variant &a, const Variant &b);
inline bool operator!=(const Variant &a, const Variant &b) { return !(a == b); }
NIXAPI void swap(Variant &a, Variant &b);

} // nix::
#endif<|endoftext|>


<commit_before>/******************************************************************************
 * $Id$
 *
 * Project:  libLAS - http://liblas.org - A BSD library for LAS format data.
 * Purpose:  LAS Schema implementation for C++ libLAS
 * Author:   Howard Butler, hobu.inc@gmail.com
 *
 ******************************************************************************
 * Copyright (c) 2010, Howard Butler
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following
 * conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in
 *       the documentation and/or other materials provided
 *       with the distribution.
 *     * Neither the name of the Martin Isenburg or Iowa Department
 *       of Natural Resources nor the names of its contributors may be
 *       used to endorse or promote products derived from this software
 *       without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 * OF SUCH DAMAGE.
 ****************************************************************************/

#ifndef PDAL_SCHEMA_HPP_INCLUDED
#define PDAL_SCHEMA_HPP_INCLUDED

#include <pdal/pdal.hpp>

#include <vector>
#include <map>

#include <pdal/Dimension.hpp>

// boost
#include <boost/cstdint.hpp>
#include <boost/any.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/foreach.hpp>
#include <boost/array.hpp>
#include <boost/optional.hpp>

#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_comparison.hpp>

namespace pdal
{

/// Schema definition
class PDAL_DLL Schema
{
public:
    Schema();
    Schema(Schema const& other);

    Schema& operator=(Schema const& rhs);

    bool operator==(const Schema& other) const;
    bool operator!=(const Schema& other) const;

    void appendDimension(Dimension const& dim);

    const std::vector<Dimension>& getDimensions() const;
    std::vector<Dimension>& getDimensions();

    bool hasDimension(const DimensionId::Id& id) const;
    //bool hasDimension(const Dimension& dim) const;

    Dimension& getDimension(const DimensionId::Id& id);
    const Dimension& getDimension(const DimensionId::Id& id) const;

    const Dimension& getDimension(std::size_t index) const;
    Dimension& getDimension(std::size_t index);

    int getDimensionIndex(const DimensionId::Id& id) const;
    int getDimensionIndex(const Dimension& dim) const;

    /// Fetch total byte size -- sum of all dimensions
    inline std::size_t getByteSize() const
    {
        return m_byteSize;
    }

    // returns a ptree reprsenting the Schema
    //
    // looks like this:
    //    dimension:
    //        [Dimension ptree]
    //    dimension:
    //        [Dimension ptree]
    //    ...
    //
    boost::property_tree::ptree toPTree() const;

    void dump() const;

    static Schema from_xml(std::string const& xml, std::string const& xsd);
    static Schema from_xml(std::string const& xml);
    static std::string to_xml(Schema const& schema);

private:
    void calculateSizes();

    std::vector<Dimension> m_dimensions;
    std::size_t m_byteSize;

    std::map<DimensionId::Id, std::size_t> m_dimensions_map;
};

PDAL_DLL std::ostream& operator<<(std::ostream& os, pdal::Schema const& d);

} // namespace liblas

#endif // PDAL_SCHEMA_HPP_INCLUDED
<commit_msg>no longer include tuple, not used<commit_after>/******************************************************************************
 * $Id$
 *
 * Project:  libLAS - http://liblas.org - A BSD library for LAS format data.
 * Purpose:  LAS Schema implementation for C++ libLAS
 * Author:   Howard Butler, hobu.inc@gmail.com
 *
 ******************************************************************************
 * Copyright (c) 2010, Howard Butler
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following
 * conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in
 *       the documentation and/or other materials provided
 *       with the distribution.
 *     * Neither the name of the Martin Isenburg or Iowa Department
 *       of Natural Resources nor the names of its contributors may be
 *       used to endorse or promote products derived from this software
 *       without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 * OF SUCH DAMAGE.
 ****************************************************************************/

#ifndef PDAL_SCHEMA_HPP_INCLUDED
#define PDAL_SCHEMA_HPP_INCLUDED

#include <pdal/pdal.hpp>

#include <vector>
#include <map>

#include <pdal/Dimension.hpp>

// boost
#include <boost/cstdint.hpp>
#include <boost/any.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/foreach.hpp>
#include <boost/array.hpp>
#include <boost/optional.hpp>

namespace pdal
{

/// Schema definition
class PDAL_DLL Schema
{
public:
    Schema();
    Schema(Schema const& other);

    Schema& operator=(Schema const& rhs);

    bool operator==(const Schema& other) const;
    bool operator!=(const Schema& other) const;

    void appendDimension(Dimension const& dim);

    const std::vector<Dimension>& getDimensions() const;
    std::vector<Dimension>& getDimensions();

    bool hasDimension(const DimensionId::Id& id) const;
    //bool hasDimension(const Dimension& dim) const;

    Dimension& getDimension(const DimensionId::Id& id);
    const Dimension& getDimension(const DimensionId::Id& id) const;

    const Dimension& getDimension(std::size_t index) const;
    Dimension& getDimension(std::size_t index);

    int getDimensionIndex(const DimensionId::Id& id) const;
    int getDimensionIndex(const Dimension& dim) const;

    /// Fetch total byte size -- sum of all dimensions
    inline std::size_t getByteSize() const
    {
        return m_byteSize;
    }

    // returns a ptree reprsenting the Schema
    //
    // looks like this:
    //    dimension:
    //        [Dimension ptree]
    //    dimension:
    //        [Dimension ptree]
    //    ...
    //
    boost::property_tree::ptree toPTree() const;

    void dump() const;

    static Schema from_xml(std::string const& xml, std::string const& xsd);
    static Schema from_xml(std::string const& xml);
    static std::string to_xml(Schema const& schema);

private:
    void calculateSizes();

    std::vector<Dimension> m_dimensions;
    std::size_t m_byteSize;

    std::map<DimensionId::Id, std::size_t> m_dimensions_map;
};

PDAL_DLL std::ostream& operator<<(std::ostream& os, pdal::Schema const& d);

} // namespace liblas

#endif // PDAL_SCHEMA_HPP_INCLUDED
<|endoftext|>


<commit_before>// Copyright © 2014 German Neuroinformatics Node (G-Node)
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted under the terms of the BSD License. See
// LICENSE file in the root of the Project.
//
// Author: Christian Kellner <kellner@bio.lmu.de>

#ifndef NIX_EXCEPTION_H
#define NIX_EXCEPTION_H

#include <stdexcept>
#include <sstream>

#include <nix/Platform.hpp>

namespace nix {

class OutOfBounds : public std::out_of_range {
public:
    OutOfBounds(const std::string &what_arg, size_t where) :
        out_of_range(what_arg), index(where) {
        std::stringstream sstream(what_arg);

        sstream << " [at index: " << where << "]";
        msg = sstream.str();
    }

    size_t where(void) const {
        return index;
    }

    const char *what() const NOEXCEPT {
        return msg.c_str();
    }

private:
    size_t index;
    std::string msg;
};

class UninitializedEntity : public std::exception {
public:
    UninitializedEntity() { }
    const char *what() const NOEXCEPT {
        return "The Entity being accessed is uninitialized.";
    }
};

class EmptyString: public std::exception {
public:
    EmptyString(const std::string &caller_arg):
    caller(caller_arg) { }

    const char *what() const NOEXCEPT {
        std::stringstream sstream("EmptyString: ");
        sstream << "Empty string given - not a valid value for " << caller;
        return sstream.str().c_str();
    }

private:
    std::string caller;
};

class MissingAttr: public std::exception {
public:
    MissingAttr(const std::string &attr_arg):
    attr(attr_arg) { }

    const char *what() const NOEXCEPT {
        std::stringstream sstream("MissingAttribute: ");
        sstream << "Obligatory attribute " << attr << " is not set!";
        return sstream.str().c_str();
    }

private:
    std::string attr;
};

class UnsortedTicks: public std::exception {
public:
    UnsortedTicks(const std::string &caller_arg):
    caller(caller_arg) { }

    const char *what() const NOEXCEPT {
        std::stringstream sstream("UnsortedTics: ");
        sstream << "Ticks are not given in a ascending order: " << caller;
        return sstream.str().c_str();
    }

private:
    std::string caller;
};

class InvalidUnit: public std::exception {
public:
    InvalidUnit(const std::string &what_arg, const std::string &caller_arg):
    what_msg(what_arg), caller(caller_arg) { }

    const char *what() const NOEXCEPT {
        std::stringstream sstream("InvalidUnit: ");
        sstream << what_msg << " evoked at: " << caller;
        return sstream.str().c_str();
    }

private:
    std::string what_msg;
    std::string caller;
};

class IncompatibleDimensions: public std::exception {
public:
    IncompatibleDimensions(const std::string &what_arg, const std::string &caller_arg):
    what_msg(what_arg), caller(caller_arg) { }

    const char *what() const NOEXCEPT {
        std::stringstream sstream("IncompatibleDimensions: ");
        sstream << what_msg << " evoked at: " << caller;
        return sstream.str().c_str();
    }

private:
    std::string what_msg;
    std::string caller;
};

class InvalidRankException : public std::runtime_error {
public:
    InvalidRankException(const std::string &message)
        : std::runtime_error(message) { }
};

}

#endif
<commit_msg>InvalidRankException: derive from out_of_range<commit_after>// Copyright © 2014 German Neuroinformatics Node (G-Node)
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted under the terms of the BSD License. See
// LICENSE file in the root of the Project.
//
// Author: Christian Kellner <kellner@bio.lmu.de>

#ifndef NIX_EXCEPTION_H
#define NIX_EXCEPTION_H

#include <stdexcept>
#include <sstream>

#include <nix/Platform.hpp>

namespace nix {

class OutOfBounds : public std::out_of_range {
public:
    OutOfBounds(const std::string &what_arg, size_t where) :
        out_of_range(what_arg), index(where) {
        std::stringstream sstream(what_arg);

        sstream << " [at index: " << where << "]";
        msg = sstream.str();
    }

    size_t where(void) const {
        return index;
    }

    const char *what() const NOEXCEPT {
        return msg.c_str();
    }

private:
    size_t index;
    std::string msg;
};

class UninitializedEntity : public std::exception {
public:
    UninitializedEntity() { }
    const char *what() const NOEXCEPT {
        return "The Entity being accessed is uninitialized.";
    }
};

class EmptyString: public std::exception {
public:
    EmptyString(const std::string &caller_arg):
    caller(caller_arg) { }

    const char *what() const NOEXCEPT {
        std::stringstream sstream("EmptyString: ");
        sstream << "Empty string given - not a valid value for " << caller;
        return sstream.str().c_str();
    }

private:
    std::string caller;
};

class MissingAttr: public std::exception {
public:
    MissingAttr(const std::string &attr_arg):
    attr(attr_arg) { }

    const char *what() const NOEXCEPT {
        std::stringstream sstream("MissingAttribute: ");
        sstream << "Obligatory attribute " << attr << " is not set!";
        return sstream.str().c_str();
    }

private:
    std::string attr;
};

class UnsortedTicks: public std::exception {
public:
    UnsortedTicks(const std::string &caller_arg):
    caller(caller_arg) { }

    const char *what() const NOEXCEPT {
        std::stringstream sstream("UnsortedTics: ");
        sstream << "Ticks are not given in a ascending order: " << caller;
        return sstream.str().c_str();
    }

private:
    std::string caller;
};

class InvalidUnit: public std::exception {
public:
    InvalidUnit(const std::string &what_arg, const std::string &caller_arg):
    what_msg(what_arg), caller(caller_arg) { }

    const char *what() const NOEXCEPT {
        std::stringstream sstream("InvalidUnit: ");
        sstream << what_msg << " evoked at: " << caller;
        return sstream.str().c_str();
    }

private:
    std::string what_msg;
    std::string caller;
};

class IncompatibleDimensions: public std::exception {
public:
    IncompatibleDimensions(const std::string &what_arg, const std::string &caller_arg):
    what_msg(what_arg), caller(caller_arg) { }

    const char *what() const NOEXCEPT {
        std::stringstream sstream("IncompatibleDimensions: ");
        sstream << what_msg << " evoked at: " << caller;
        return sstream.str().c_str();
    }

private:
    std::string what_msg;
    std::string caller;
};

class InvalidRankException : public std::out_of_range {
public:
    InvalidRankException(const std::string &message)
        : std::out_of_range(message) { }
};

}

#endif
<|endoftext|>


<commit_before>// TODO(zedzull): Make the screen size configurable through Lua
#define SCREEN_WIDTH 640
#define SCREEN_HEIGHT 480

int main() {
    glfwInit();

    glfwWindowHint(GLFW_RESIZABLE, false);

    GLFWwindow *window = glfwCreateWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "Zull", NULL, NULL);
    glfwMakeContextCurrent(window);
    glfwSwapInterval(1);

    const GLFWvidmode *video_mode = glfwGetVideoMode(glfwGetPrimaryMonitor());
    glfwSetWindowPos(window, (video_mode->width / 2) - (SCREEN_WIDTH / 2), (video_mode->height / 2) - (SCREEN_HEIGHT / 2));

    glfwSetKeyCallback(window, keyboard_callback);

    load_opengl_functions();

    graphics_init(SCREEN_WIDTH, SCREEN_HEIGHT);

    if (!script_init()) {
        return -1;
    }

    f64 delta_time = 1.0 / 60.0;

    f64 last_time = glfwGetTime();
    f64 unprocessed_time = 0.0;

    while (!glfwWindowShouldClose(window)) {
        f64 current_time = glfwGetTime();
        f64 elapsed_time = current_time - last_time;
        last_time = current_time;

        unprocessed_time += elapsed_time;

        while (unprocessed_time >= delta_time) {
            input_update();
            glfwPollEvents();

            if (input_was_key_pressed(KEY_ESCAPE)) {
                glfwSetWindowShouldClose(window, true);
            }

            script_update(delta_time);
            unprocessed_time -= delta_time;
        }

        graphics_begin_frame();

        script_draw();

        graphics_end_frame();

        glfwSwapBuffers(window);
    }

    script_shutdown();

    glfwTerminate();

    return 0;
}
<commit_msg>Updated script_init() function call to fit new signature.<commit_after>// TODO(zedzull): Make the screen size configurable through Lua
#define SCREEN_WIDTH 640
#define SCREEN_HEIGHT 480

int main() {
    glfwInit();

    glfwWindowHint(GLFW_RESIZABLE, false);

    GLFWwindow *window = glfwCreateWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "Zull", NULL, NULL);
    glfwMakeContextCurrent(window);
    glfwSwapInterval(1);

    const GLFWvidmode *video_mode = glfwGetVideoMode(glfwGetPrimaryMonitor());
    glfwSetWindowPos(window, (video_mode->width / 2) - (SCREEN_WIDTH / 2), (video_mode->height / 2) - (SCREEN_HEIGHT / 2));

    glfwSetKeyCallback(window, keyboard_callback);

    load_opengl_functions();

    graphics_init(SCREEN_WIDTH, SCREEN_HEIGHT);

    if (!script_init("game/main.lua")) {
        return -1;
    }

    f64 delta_time = 1.0 / 60.0;

    f64 last_time = glfwGetTime();
    f64 unprocessed_time = 0.0;

    while (!glfwWindowShouldClose(window)) {
        f64 current_time = glfwGetTime();
        f64 elapsed_time = current_time - last_time;
        last_time = current_time;

        unprocessed_time += elapsed_time;

        while (unprocessed_time >= delta_time) {
            input_update();
            glfwPollEvents();

            if (input_was_key_pressed(KEY_ESCAPE)) {
                glfwSetWindowShouldClose(window, true);
            }

            script_update(delta_time);
            unprocessed_time -= delta_time;
        }

        graphics_begin_frame();

        script_draw();

        graphics_end_frame();

        glfwSwapBuffers(window);
    }

    script_shutdown();

    glfwTerminate();

    return 0;
}
<|endoftext|>


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

#ifndef RPCZ_BASE_H
#define RPCZ_BASE_H

#include "google/protobuf/stubs/common.h"

namespace rpcz {
using google::protobuf::scoped_ptr;
using google::protobuf::uint64;
using google::protobuf::int64;

// A macro to disallow the copy constructor and operator= functions
// This should be used in the private: declarations for a class
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
  TypeName(const TypeName&);               \
    void operator=(const TypeName&)

// Deletes each pointer in the range [begin, end)
template<typename IteratorType>
void delete_container_pointers(const IteratorType& begin,
                             const IteratorType& end) {
  for (IteratorType i = begin; i != end; ++i) {
    delete *i;
  }
}

// For each item in the range [begin, end), delete item->first and item->second.
template<typename IteratorType>
void delete_container_pair_pointers(const IteratorType& begin,
                                 const IteratorType& end) {
  for (IteratorType i = begin; i != end; ++i) {
    delete i->first;
    delete i->second;
  }
}

// For each item in the range [begin, end), delete item->second.
template<typename IteratorType>
void delete_container_second_pointer(const IteratorType& begin,
                                  const IteratorType& end) {
  for (IteratorType i = begin; i != end; ++i) {
    delete i->second;
  }
}
}  // namespace rpcz
#endif
<commit_msg>Also need to #undef NO_ERROR here in order to build successfully on Windows<commit_after>// Copyright 2011 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: nadavs@google.com <Nadav Samet>

#ifndef RPCZ_BASE_H
#define RPCZ_BASE_H

#include "google/protobuf/stubs/common.h"

#ifdef WIN32
// winerror.h contains #define NO_ERROR 0
#undef NO_ERROR
#endif

namespace rpcz {
using google::protobuf::scoped_ptr;
using google::protobuf::uint64;
using google::protobuf::int64;

// A macro to disallow the copy constructor and operator= functions
// This should be used in the private: declarations for a class
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
  TypeName(const TypeName&);               \
    void operator=(const TypeName&)

// Deletes each pointer in the range [begin, end)
template<typename IteratorType>
void delete_container_pointers(const IteratorType& begin,
                             const IteratorType& end) {
  for (IteratorType i = begin; i != end; ++i) {
    delete *i;
  }
}

// For each item in the range [begin, end), delete item->first and item->second.
template<typename IteratorType>
void delete_container_pair_pointers(const IteratorType& begin,
                                 const IteratorType& end) {
  for (IteratorType i = begin; i != end; ++i) {
    delete i->first;
    delete i->second;
  }
}

// For each item in the range [begin, end), delete item->second.
template<typename IteratorType>
void delete_container_second_pointer(const IteratorType& begin,
                                  const IteratorType& end) {
  for (IteratorType i = begin; i != end; ++i) {
    delete i->second;
  }
}
}  // namespace rpcz
#endif
<|endoftext|>


<commit_before>#include "PDL.h"
#include "SDL.h"
#include "SDL_image.h"
#include "chipmunk/chipmunk.h"
#include <iostream>
#include <vector>

using namespace std;

const float FRAMES_PER_SECOND = 60.0;

const int SCREEN_WIDTH = 320;
const int SCREEN_HEIGHT = 480;
const int PADDING = 20;

const int GRAVITY = 600; // gravity strength

// making these global because I'm lazy
SDL_Surface *screen;
SDL_Surface *ball;

void updateShape(void*, void*);
void defineBorders(cpSpace*);

int main(int argc, char* argv[]) {
  bool in_loop = true;
  float xForce;
  float yForce;

  // create the file path to the ball image
  char* app_dir;
  PDL_GetCallingPath(app_dir, 256);
  string ball_path(app_dir);
  ball_path.append("assets/ball.gif");
  delete app_dir;

  // SDL setup
  SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK);
  screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, 32, 0);
  if (screen == NULL) return -1;
  SDL_Event event;
  SDL_Joystick *joystick = SDL_JoystickOpen(0);
  ball = IMG_Load(ball_path.c_str());

  // chipmunk setup
  cpSpace *space;
  cpBody *body;

  cpInitChipmunk();
  space = cpSpaceNew();
  space->iterations = 10;
  space->elasticIterations = 10;
  space->gravity = cpv(0, GRAVITY);

  defineBorders(space);

  // gameloop
  while (in_loop) {
    // get data from the accelerometer
    xForce = (float) SDL_JoystickGetAxis(joystick, 0) / 32768.0;
    yForce = (float) SDL_JoystickGetAxis(joystick, 1) / 32768.0;

    space->gravity = cpv(xForce * GRAVITY, yForce * GRAVITY);

    // capture the events and send the relevent tap events to the game scene
    while (SDL_PollEvent(&event)) {
      if (event.type == SDL_QUIT)
        in_loop = false;

      else if (event.type == SDL_MOUSEBUTTONDOWN) {
        if ((event.motion.x > PADDING && event.motion.x < SCREEN_WIDTH - PADDING) &&
            (event.motion.y > PADDING && event.motion.y < SCREEN_HEIGHT - PADDING)) {
          body = cpBodyNew(10.0f, INFINITY);
          body->p = cpv(event.motion.x, event.motion.y);
          cpSpaceAddBody(space, body);

          cpShape *shape = cpSpaceAddShape(space, cpCircleShapeNew(body, 20.0, cpvzero));
          shape->e = 0.3f;
          shape->u = 0.1f;
        }
      }
    }

    // clear the screen
    SDL_FillRect(SDL_GetVideoSurface(), NULL, 0);

    // recalculate the physics objects
    cpSpaceStep(space, 1.0f/FRAMES_PER_SECOND);
    cpSpaceHashEach(space->activeShapes, &updateShape, NULL);

    // update the display
    SDL_Flip(screen);
  }

  // shutdown Chipmunk
  cpSpaceFreeChildren(space);
  cpSpaceFree(space);

  // shutdown SDL
  SDL_FreeSurface(ball);
  PDL_Quit();
  SDL_Quit();

  return 0;
}

// update a shape's visual representation
void updateShape(void *ptr, void* unused) {
  cpShape *shape = (cpShape*)ptr;

  // make sure the shape is constructed correctly
  if(shape == NULL || shape->body == NULL) {
    return;
  }

  // Use a temporary rectangle to pass our x and y to the offsets when blitting
  SDL_Rect offset;
  offset.x = shape->body->p.x;
  offset.y = shape->body->p.y;

  SDL_BlitSurface(ball, NULL, screen, &offset);
}

// create borders around the screen
void defineBorders(cpSpace *space) {
  cpBody *body = cpBodyNew(INFINITY, INFINITY);
  float border_elasticity = 0.3f;
  float border_friction = 1.0f;

  // top border
  cpShape *border_top = cpSegmentShapeNew(body, cpv(-PADDING, -PADDING), cpv(SCREEN_WIDTH - PADDING, -PADDING), 1.0f);
  border_top->e = border_elasticity; border_top->u = border_friction;
  cpSpaceAddStaticShape(space, border_top);

  // right border
  cpShape *border_right = cpSegmentShapeNew(body, cpv(SCREEN_WIDTH - PADDING, -PADDING), cpv(SCREEN_WIDTH - PADDING, SCREEN_HEIGHT - PADDING), 1.0f);
  border_right->e = border_elasticity; border_right->u = border_friction;
  cpSpaceAddStaticShape(space, border_right);

  // bottom border
  cpShape *border_bottom = cpSegmentShapeNew(body, cpv(-PADDING, SCREEN_HEIGHT - PADDING), cpv(SCREEN_WIDTH - PADDING, SCREEN_HEIGHT - PADDING), 1.0f);
  border_bottom->e = border_elasticity; border_bottom->u = border_friction;
  cpSpaceAddStaticShape(space, border_bottom);

  // left border
  cpShape *border_left = cpSegmentShapeNew(body, cpv(-PADDING, -PADDING), cpv(-PADDING, SCREEN_HEIGHT - PADDING), 1.0f);
  border_left->e = border_elasticity; border_left->u = border_friction;
  cpSpaceAddStaticShape(space, border_left);
}<commit_msg>Modified the asset path<commit_after>#include "PDL.h"
#include "SDL.h"
#include "SDL_image.h"
#include "chipmunk/chipmunk.h"
#include <iostream>
#include <vector>

using namespace std;

const float FRAMES_PER_SECOND = 60.0;

const int SCREEN_WIDTH = 320;
const int SCREEN_HEIGHT = 480;
const int PADDING = 20;

const int GRAVITY = 600; // gravity strength

// making these global because I'm lazy
SDL_Surface *screen;
SDL_Surface *ball;

void updateShape(void*, void*);
void defineBorders(cpSpace*);

int main(int argc, char* argv[]) {
  bool in_loop = true;
  float xForce;
  float yForce;

  // create the file path to the ball image
  // Note: only get the PATH from PDL_GetCallingPath if on the device.  When building
  // from the desktop just hardcode the ball_path variable. PDL_GetCallingPath
  // only seems to work on the device.
  char app_dir[255];
  int ret = PDL_GetCallingPath(app_dir, 256);
  string ball_path(app_dir);
  ball_path.append("assets/ball.gif");

  // SDL setup
  SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK);
  screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, 32, 0);
  if (screen == NULL) return -1;
  SDL_Event event;
  SDL_Joystick *joystick = SDL_JoystickOpen(0);
  ball = IMG_Load(ball_path.c_str());

  // chipmunk setup
  cpSpace *space;
  cpBody *body;

  cpInitChipmunk();
  space = cpSpaceNew();
  space->iterations = 10;
  space->elasticIterations = 10;
  space->gravity = cpv(0, GRAVITY);

  defineBorders(space);

  // gameloop
  while (in_loop) {
    // get data from the accelerometer
    xForce = (float) SDL_JoystickGetAxis(joystick, 0) / 32768.0;
    yForce = (float) SDL_JoystickGetAxis(joystick, 1) / 32768.0;

    space->gravity = cpv(xForce * GRAVITY, yForce * GRAVITY);

    // capture the events and send the relevent tap events to the game scene
    while (SDL_PollEvent(&event)) {
      if (event.type == SDL_QUIT)
        in_loop = false;

      else if (event.type == SDL_MOUSEBUTTONDOWN) {
        if ((event.motion.x > PADDING && event.motion.x < SCREEN_WIDTH - PADDING) &&
            (event.motion.y > PADDING && event.motion.y < SCREEN_HEIGHT - PADDING)) {
          body = cpBodyNew(10.0f, INFINITY);
          body->p = cpv(event.motion.x, event.motion.y);
          cpSpaceAddBody(space, body);

          cpShape *shape = cpSpaceAddShape(space, cpCircleShapeNew(body, 20.0, cpvzero));
          shape->e = 0.3f;
          shape->u = 0.1f;
        }
      }
    }

    // clear the screen
    SDL_FillRect(SDL_GetVideoSurface(), NULL, 0);

    // recalculate the physics objects
    cpSpaceStep(space, 1.0f/FRAMES_PER_SECOND);
    cpSpaceHashEach(space->activeShapes, &updateShape, NULL);

    // update the display
    SDL_Flip(screen);
  }

  // shutdown Chipmunk
  cpSpaceFreeChildren(space);
  cpSpaceFree(space);

  // shutdown SDL
  SDL_FreeSurface(ball);
  PDL_Quit();
  SDL_Quit();

  return 0;
}

// update a shape's visual representation
void updateShape(void *ptr, void* unused) {
  cpShape *shape = (cpShape*)ptr;

  // make sure the shape is constructed correctly
  if(shape == NULL || shape->body == NULL) {
    return;
  }

  // Use a temporary rectangle to pass our x and y to the offsets when blitting
  SDL_Rect offset;
  offset.x = shape->body->p.x;
  offset.y = shape->body->p.y;

  SDL_BlitSurface(ball, NULL, screen, &offset);
}

// create borders around the screen
void defineBorders(cpSpace *space) {
  cpBody *body = cpBodyNew(INFINITY, INFINITY);
  float border_elasticity = 0.3f;
  float border_friction = 1.0f;

  // top border
  cpShape *border_top = cpSegmentShapeNew(body, cpv(-PADDING, -PADDING), cpv(SCREEN_WIDTH - PADDING, -PADDING), 1.0f);
  border_top->e = border_elasticity; border_top->u = border_friction;
  cpSpaceAddStaticShape(space, border_top);

  // right border
  cpShape *border_right = cpSegmentShapeNew(body, cpv(SCREEN_WIDTH - PADDING, -PADDING), cpv(SCREEN_WIDTH - PADDING, SCREEN_HEIGHT - PADDING), 1.0f);
  border_right->e = border_elasticity; border_right->u = border_friction;
  cpSpaceAddStaticShape(space, border_right);

  // bottom border
  cpShape *border_bottom = cpSegmentShapeNew(body, cpv(-PADDING, SCREEN_HEIGHT - PADDING), cpv(SCREEN_WIDTH - PADDING, SCREEN_HEIGHT - PADDING), 1.0f);
  border_bottom->e = border_elasticity; border_bottom->u = border_friction;
  cpSpaceAddStaticShape(space, border_bottom);

  // left border
  cpShape *border_left = cpSegmentShapeNew(body, cpv(-PADDING, -PADDING), cpv(-PADDING, SCREEN_HEIGHT - PADDING), 1.0f);
  border_left->e = border_elasticity; border_left->u = border_friction;
  cpSpaceAddStaticShape(space, border_left);
}<|endoftext|>