<commit_before>#include <iostream>
#include <sstream>
#include <string>
#include <fstream>
#include <vector>
#include <map>
#include <cstdio>

#include <sys/stat.h>

#include <boost/filesystem.hpp>

#include "Sequence.hpp"
#include "Parser.hpp"
#include "Experiment.hpp"

#include "demultiplexing.hpp"

using namespace std;
namespace fs=boost::filesystem;

void printHelp () {
	cout << "./dtd -r1 r1_filename -r2 r2_filename \
-o oligos_filename -e experiments [-d output_directory]" << endl;
	cout << "Command line description:" << endl;
	cout << "\t\e[1m-r1\e[0m: The FASTQ file containing all the reads R1 from \
a paired end amplicon sequencing." << endl;
	cout << "\t\e[1m-r2\e[0m: The FASTQ file containing all the reads R2 from \
a paired end amplicon sequencing." << endl;
	cout << "\t\e[1m-p or -primers\e[0m: The FASTA file containing all the tag-primer pairs. The \
header line must contain the name of the sequence using the convention \
<primer_name>-<tag_name>. For example F1-C. The primer can contain the '-' \
character but nor the tag name." << endl;
	// cout << "\t\e[1m-t or -tag-size\e[0m: The size of the tags in bp." << endl;
	cout << "\t\e[1m-l or -libraries\e[0m: The csv file containing the tags for the libraries and samples. \
The csv must have at least 4 columns named run, sample, forward and reverse. \
These columns corresponds respectively to the run name, the sample name, the forward \
taged primer name of the experiment and the reverse." << endl;
	cout << "\t\e[1m-d or -directory\e[0m: The directory where all the output FASTQ by \
by experiment will be created. By default this is the current directory." << endl;
	cout << "\t\e[1m-m or -mistag\e[0m: Two files named mistag_R1.fastq and \
mistag_R2.fastq will be created with non assigned read pairs. The primer names will be \
added to the end of the read headers." << endl;
	cout << "\t\e[1m-t or -trim\e[0m: Trim the primers from the sequence." << endl;
	cout << "\t\e[1m-rl or -restrict-library\e[0m: Restrict the demultiplexing to only one library." << endl;
}

map<string, Experiment> parse_experiments(string exp_filename, string out_dir, string restriction);
map<string, Sequence> parseTaggedPrimers (string filename);

int main (int argc, char *argv[]) {
	string r1_filename;
	string r2_filename;
	string exp_filename;
	string oligos_filename;
	string out_dir = "./";
	string restricted = "";
	bool mistags = false;
	bool trim = false;

	if (argc == 1) {
		printHelp();
		return 0;
	}

	/* --- Arguments parsing --- */
	for (int idx=1 ; idx<argc ; idx++) {
		string arg (argv[idx]);

		if (arg == "-h" || arg == "-help") {
			printHelp();
			return 0;
		} else if (arg == "-r1") {
			arg = string(argv[++idx]);
			r1_filename = arg;
		} else if (arg == "-r2") {
			arg = string(argv[++idx]);
			r2_filename = arg;
		} else if (arg == "-p" || arg == "-primers") {
			arg = string(argv[++idx]);
			oligos_filename = arg;
		} else if (arg == "-l" || arg == "-libraries") {
			arg = string(argv[++idx]);
			exp_filename = arg;
		} else if (arg == "-d" || arg == "-directory") {
			arg = string(argv[++idx]);
			out_dir = arg;
			if (out_dir[0] != '/')
				out_dir = "./" + out_dir;
		} else if (arg == "-m" || arg == "-mistag") {
			mistags = true;
		} else if (arg == "-t" || arg == "-trim") {
			trim = true;
		} else if (arg == "-rl" || arg == "-restrict-library") {
			restricted = string(argv[++idx]);
		} else {
			cerr << "No argument called " << arg << endl;
			return 0;
		}
	}

	if (r1_filename == "" || r2_filename == "" || exp_filename == "" || oligos_filename == "") {
		cerr << "Wrong command line" << endl;
		return 1;
	}

	/* --- Loading the tags --- */
	auto exps = parse_experiments(exp_filename, out_dir, restricted);
	auto oligos = parseTaggedPrimers(oligos_filename);

	/* --- Demultiplexing --- */
	// Create directory
	fs::path dir = fs::path(out_dir);
	if (! fs::exists(dir))
		if (mkdir(out_dir.c_str(), 0777)) {
			cerr << "Impossible to create directory " << out_dir << endl;
			exit(2);
		}

	// Flags activation
	if (mistags)
		activate_mistags (out_dir);
	if (trim)
		activate_triming ();

	// Demultiplex
	demux (r1_filename, r2_filename, exps, oligos);

	return 0;
}

vector<string> split (string word, string delim) {
	vector<string> words;

	size_t pos = 0;
	string token;
	while ((pos = word.find(delim)) != string::npos) {
		token = word.substr(0, pos);
		words.push_back(token);
		word.erase(0, pos + delim.length());
	}
	words.push_back(word);

	return words;
}

map<char, string> getIupac () {
	map<char, string> iupac;

	iupac['A'] = "A";
	iupac['C'] = "C";
	iupac['T'] = "T";
	iupac['G'] = "G";
	iupac['R'] = "AG";
	iupac['Y'] = "CT";
	iupac['S'] = "GC";
	iupac['W'] = "AT";
	iupac['K'] = "GT";
	iupac['M'] = "AC";
	iupac['B'] = "CGT";
	iupac['D'] = "AGT";
	iupac['H'] = "ACT";
	iupac['V'] = "ACG";
	iupac['N'] = "ACGT";

	return iupac;
}

/* Recursively split the sequence into multiple sequences, each time that a degenerate
 * nucleotide is encountered
 */
vector<Sequence> expandWithIupacCode (Sequence & seq, map<char, string> & iupac, int startIdx) {
	vector<Sequence> expanded;

	for (uint idx=startIdx ; idx<seq.sequence.size() ; idx++) {
		auto iVal = iupac[seq.sequence[idx]];

		if (iVal.size() > 1) {
			for (char c : iVal) {
				Sequence copy = Sequence(seq);
				copy.sequence[idx] = c;
				vector<Sequence> recur = expandWithIupacCode(copy, iupac, idx+1);
				expanded.insert(expanded.end(), recur.begin(), recur.end());
			}
		}
	}

	if (expanded.size() == 0)
		expanded.push_back(seq);

	return expanded;
}

map<string, Experiment> parse_experiments(string exp_filename, string out_dir, string restriction) {
	ifstream file (exp_filename);

	map<string, Experiment> exps;

	// Wrong file of path
	if (!file.is_open()) {
		cerr << "Impossible to open " << exp_filename << endl;
		exit(1);
	}

	// Read the header line
	string line;
	getline(file, line);
	vector<string> header = split(line, ",");

	int run_idx = -1;
	int sample_idx = -1;
	int r1_idx = -1;
	int r2_idx = -1;

	for (uint idx=0 ; idx<header.size() ; idx++) {
		string word = header[idx];

		if (word == "run")
			run_idx = idx;
		else if (word == "sample")
			sample_idx = idx;
		else if (word == "forward")
			r1_idx = idx;
		else if (word == "reverse")
			r2_idx = idx;
	}

	// If the csv is not correctly formated
	if (run_idx == -1)
		cerr << "No field run in " << exp_filename << endl;
	if (sample_idx == -1)
		cerr << "No field sample in " << exp_filename << endl;
	if (r1_idx == -1)
		cerr << "No field forward in " << exp_filename << endl;
	if (r2_idx == -1)
		cerr << "No field reverse in " << exp_filename << endl;
	if(run_idx == -1 || sample_idx == -1 || r1_idx == -1 || r2_idx == -1)
		exit(1);

	while (file.peek() != EOF) {
		getline(file, line);
		vector<string> values = split(line, ",");

		if (values.size() < 4 || (restriction != "" && values[run_idx] != restriction))
			continue;

		string base_filename =  out_dir + (out_dir[out_dir.size()-1] == '/' ? "" : "/")
			+ exp_filename.substr(0, exp_filename.find_last_of(".")) + '_' + values[run_idx] + "_" + values[sample_idx];
		Experiment e(values[run_idx], values[sample_idx], values[r1_idx], values[r2_idx],
			base_filename + "_fwd.fastq", base_filename + "_rev.fastq");
		exps[e.fwd_name + e.rev_name] = e;
	}

	return exps;
}

map<string, Sequence> parseTaggedPrimers (string filename) {
	map<string, Sequence> oligos;

	uint minSize = 1000000000;
	vector<Sequence> seqs;
	Parser fasta (filename);
	while (fasta.hasNext()) {
		Sequence seq = fasta.nextSequence();
		if (seq.sequence.size() < minSize)
			minSize = seq.sequence.size();
		seqs.push_back(seq);
	}

	auto iupac = getIupac();
	for (Sequence seq : seqs) {
		vector<Sequence> expanded = expandWithIupacCode(seq, iupac, 0);

		for (Sequence & exp : expanded) {
			oligos[exp.sequence.substr(0, minSize)] = seq;
		}
	}

	return oligos;
}

<commit_msg>bugfix: libraries absolute path to relative<commit_after>#include <iostream>
#include <sstream>
#include <string>
#include <fstream>
#include <vector>
#include <map>
#include <cstdio>

#include <sys/stat.h>

#include <boost/filesystem.hpp>

#include "Sequence.hpp"
#include "Parser.hpp"
#include "Experiment.hpp"

#include "demultiplexing.hpp"

using namespace std;
namespace fs=boost::filesystem;

void printHelp () {
	cout << "./dtd -r1 r1_filename -r2 r2_filename \
-o oligos_filename -e experiments [-d output_directory]" << endl;
	cout << "Command line description:" << endl;
	cout << "\t\e[1m-r1\e[0m: The FASTQ file containing all the reads R1 from \
a paired end amplicon sequencing." << endl;
	cout << "\t\e[1m-r2\e[0m: The FASTQ file containing all the reads R2 from \
a paired end amplicon sequencing." << endl;
	cout << "\t\e[1m-p or -primers\e[0m: The FASTA file containing all the tag-primer pairs. The \
header line must contain the name of the sequence using the convention \
<primer_name>-<tag_name>. For example F1-C. The primer can contain the '-' \
character but nor the tag name." << endl;
	// cout << "\t\e[1m-t or -tag-size\e[0m: The size of the tags in bp." << endl;
	cout << "\t\e[1m-l or -libraries\e[0m: The csv file containing the tags for the libraries and samples. \
The csv must have at least 4 columns named run, sample, forward and reverse. \
These columns corresponds respectively to the run name, the sample name, the forward \
taged primer name of the experiment and the reverse." << endl;
	cout << "\t\e[1m-d or -directory\e[0m: The directory where all the output FASTQ by \
by experiment will be created. By default this is the current directory." << endl;
	cout << "\t\e[1m-m or -mistag\e[0m: Two files named mistag_R1.fastq and \
mistag_R2.fastq will be created with non assigned read pairs. The primer names will be \
added to the end of the read headers." << endl;
	cout << "\t\e[1m-t or -trim\e[0m: Trim the primers from the sequence." << endl;
	cout << "\t\e[1m-rl or -restrict-library\e[0m: Restrict the demultiplexing to only one library." << endl;
}

map<string, Experiment> parse_experiments(string exp_filename, string out_dir, string restriction);
map<string, Sequence> parseTaggedPrimers (string filename);

int main (int argc, char *argv[]) {
	string r1_filename;
	string r2_filename;
	string exp_filename;
	string oligos_filename;
	string out_dir = "./";
	string restricted = "";
	bool mistags = false;
	bool trim = false;

	if (argc == 1) {
		printHelp();
		return 0;
	}

	/* --- Arguments parsing --- */
	for (int idx=1 ; idx<argc ; idx++) {
		string arg (argv[idx]);

		if (arg == "-h" || arg == "-help") {
			printHelp();
			return 0;
		} else if (arg == "-r1") {
			arg = string(argv[++idx]);
			r1_filename = arg;
		} else if (arg == "-r2") {
			arg = string(argv[++idx]);
			r2_filename = arg;
		} else if (arg == "-p" || arg == "-primers") {
			arg = string(argv[++idx]);
			oligos_filename = arg;
		} else if (arg == "-l" || arg == "-libraries") {
			arg = string(argv[++idx]);
			exp_filename = arg;
		} else if (arg == "-d" || arg == "-directory") {
			arg = string(argv[++idx]);
			out_dir = arg;
			if (out_dir[0] != '/')
				out_dir = "./" + out_dir;
		} else if (arg == "-m" || arg == "-mistag") {
			mistags = true;
		} else if (arg == "-t" || arg == "-trim") {
			trim = true;
		} else if (arg == "-rl" || arg == "-restrict-library") {
			restricted = string(argv[++idx]);
		} else {
			cerr << "No argument called " << arg << endl;
			return 0;
		}
	}

	if (r1_filename == "" || r2_filename == "" || exp_filename == "" || oligos_filename == "") {
		cerr << "Wrong command line" << endl;
		return 1;
	}

	/* --- Loading the tags --- */
	auto exps = parse_experiments(exp_filename, out_dir, restricted);
	auto oligos = parseTaggedPrimers(oligos_filename);

	/* --- Demultiplexing --- */
	// Create directory
	fs::path dir = fs::path(out_dir);
	if (! fs::exists(dir))
		if (mkdir(out_dir.c_str(), 0777)) {
			cerr << "Impossible to create directory " << out_dir << endl;
			exit(2);
		}

	// Flags activation
	if (mistags)
		activate_mistags (out_dir);
	if (trim)
		activate_triming ();

	// Demultiplex
	demux (r1_filename, r2_filename, exps, oligos);

	return 0;
}

vector<string> split (string word, string delim) {
	vector<string> words;

	size_t pos = 0;
	string token;
	while ((pos = word.find(delim)) != string::npos) {
		token = word.substr(0, pos);
		words.push_back(token);
		word.erase(0, pos + delim.length());
	}
	words.push_back(word);

	return words;
}

map<char, string> getIupac () {
	map<char, string> iupac;

	iupac['A'] = "A";
	iupac['C'] = "C";
	iupac['T'] = "T";
	iupac['G'] = "G";
	iupac['R'] = "AG";
	iupac['Y'] = "CT";
	iupac['S'] = "GC";
	iupac['W'] = "AT";
	iupac['K'] = "GT";
	iupac['M'] = "AC";
	iupac['B'] = "CGT";
	iupac['D'] = "AGT";
	iupac['H'] = "ACT";
	iupac['V'] = "ACG";
	iupac['N'] = "ACGT";

	return iupac;
}

/* Recursively split the sequence into multiple sequences, each time that a degenerate
 * nucleotide is encountered
 */
vector<Sequence> expandWithIupacCode (Sequence & seq, map<char, string> & iupac, int startIdx) {
	vector<Sequence> expanded;

	for (uint idx=startIdx ; idx<seq.sequence.size() ; idx++) {
		auto iVal = iupac[seq.sequence[idx]];

		if (iVal.size() > 1) {
			for (char c : iVal) {
				Sequence copy = Sequence(seq);
				copy.sequence[idx] = c;
				vector<Sequence> recur = expandWithIupacCode(copy, iupac, idx+1);
				expanded.insert(expanded.end(), recur.begin(), recur.end());
			}
		}
	}

	if (expanded.size() == 0)
		expanded.push_back(seq);

	return expanded;
}

map<string, Experiment> parse_experiments(string exp_filename, string out_dir, string restriction) {
	ifstream file (exp_filename);

	map<string, Experiment> exps;

	// Wrong file of path
	if (!file.is_open()) {
		cerr << "Impossible to open " << exp_filename << endl;
		exit(1);
	}

	// Read the header line
	string line;
	getline(file, line);
	vector<string> header = split(line, ",");

	int run_idx = -1;
	int sample_idx = -1;
	int r1_idx = -1;
	int r2_idx = -1;

	for (uint idx=0 ; idx<header.size() ; idx++) {
		string word = header[idx];

		if (word == "run")
			run_idx = idx;
		else if (word == "sample")
			sample_idx = idx;
		else if (word == "forward")
			r1_idx = idx;
		else if (word == "reverse")
			r2_idx = idx;
	}

	// If the csv is not correctly formated
	if (run_idx == -1)
		cerr << "No field run in " << exp_filename << endl;
	if (sample_idx == -1)
		cerr << "No field sample in " << exp_filename << endl;
	if (r1_idx == -1)
		cerr << "No field forward in " << exp_filename << endl;
	if (r2_idx == -1)
		cerr << "No field reverse in " << exp_filename << endl;
	if(run_idx == -1 || sample_idx == -1 || r1_idx == -1 || r2_idx == -1)
		exit(1);

	while (file.peek() != EOF) {
		getline(file, line);
		vector<string> values = split(line, ",");

		if (values.size() < 4 || (restriction != "" && values[run_idx] != restriction))
			continue;

		string short_filename = exp_filename.substr(0, exp_filename.find_last_of("."));
		if (short_filename.find_last_of("/") != string::npos)
			short_filename = short_filename.substr(short_filename.find_last_of("/"));

		string base_filename =  out_dir + (out_dir[out_dir.size()-1] == '/' ? "" : "/")
			+ short_filename + '_' + values[run_idx] + "_" + values[sample_idx];
		Experiment e(values[run_idx], values[sample_idx], values[r1_idx], values[r2_idx],
			base_filename + "_fwd.fastq", base_filename + "_rev.fastq");
		exps[e.fwd_name + e.rev_name] = e;
	}

	return exps;
}

map<string, Sequence> parseTaggedPrimers (string filename) {
	map<string, Sequence> oligos;

	uint minSize = 1000000000;
	vector<Sequence> seqs;
	Parser fasta (filename);
	while (fasta.hasNext()) {
		Sequence seq = fasta.nextSequence();
		if (seq.sequence.size() < minSize)
			minSize = seq.sequence.size();
		seqs.push_back(seq);
	}

	auto iupac = getIupac();
	for (Sequence seq : seqs) {
		vector<Sequence> expanded = expandWithIupacCode(seq, iupac, 0);

		for (Sequence & exp : expanded) {
			oligos[exp.sequence.substr(0, minSize)] = seq;
		}
	}

	return oligos;
}

<|endoftext|>


<commit_before>#include <QtTest/QtTest>

#include "TelepathyQt/key-file.h"

using namespace Tp;

class TestKeyFile : public QObject
{
    Q_OBJECT

private Q_SLOTS:
    void testKeyFile();
};

void TestKeyFile::testKeyFile()
{
    QString top_srcdir = QString::fromLocal8Bit(::getenv("abs_top_srcdir"));
    if (!top_srcdir.isEmpty()) {
        QDir::setCurrent(top_srcdir + QLatin1String("/tests"));
    }

    KeyFile defaultKeyFile;
    QCOMPARE(defaultKeyFile.status(), KeyFile::None);

    KeyFile notFoundkeyFile(QLatin1String("test-key-file-not-found.ini"));
    QCOMPARE(notFoundkeyFile.status(), KeyFile::NotFoundError);

    KeyFile formatErrorkeyFile(QLatin1String("test-key-file-format-error.ini"));
    QCOMPARE(formatErrorkeyFile.status(), KeyFile::FormatError);

    KeyFile keyFile(QLatin1String("test-key-file.ini"));
    QCOMPARE(keyFile.status(), KeyFile::NoError);

    QCOMPARE(keyFile.allGroups(),
             QStringList() << QString() <<
                              QLatin1String("test group 1") <<
                              QLatin1String("test group 2"));

    QStringList allKeys = keyFile.allKeys();
    allKeys.sort();
    QCOMPARE(allKeys,
             QStringList() <<
             QLatin1String("a") <<
             QLatin1String("b") <<
             QLatin1String("c") <<
             QLatin1String("d") <<
             QLatin1String("e"));

    keyFile.setGroup(QLatin1String("test group 1"));
    QCOMPARE(keyFile.contains(QLatin1String("f")), false);
    QCOMPARE(keyFile.value(QLatin1String("c")).length(), 5);

    keyFile.setGroup(QLatin1String("test group 2"));
    QCOMPARE(keyFile.contains(QLatin1String("e")), true);
    QCOMPARE(keyFile.value(QLatin1String("e")), QString(QLatin1String("space")));

    keyFile.setFileName(QLatin1String("telepathy/managers/test-manager-file.manager"));
    QCOMPARE(keyFile.status(), KeyFile::NoError);

    keyFile.setGroup(QLatin1String("Protocol somewhat-pathological"));
    QCOMPARE(keyFile.value(QLatin1String("param-foo")), QString(QLatin1String("s required")));
    QCOMPARE(keyFile.value(QLatin1String("default-foo")), QString(QLatin1String("hello world")));

    QCOMPARE(keyFile.value(QLatin1String("param-semicolons")), QString(QLatin1String("s secret")));
    QCOMPARE(keyFile.value(QLatin1String("default-semicolons")), QString(QLatin1String("list;of;misc;")));

    QCOMPARE(keyFile.value(QLatin1String("param-list")), QString(QLatin1String("as")));
    QCOMPARE(keyFile.value(QLatin1String("default-list")), QString(QLatin1String("list;of;misc;")));
    QCOMPARE(keyFile.valueAsStringList(QLatin1String("default-list")),
             QStringList() << QLatin1String("list") << QLatin1String("of") << QLatin1String("misc"));

    QCOMPARE(keyFile.value(QLatin1String("param-unterminated-list")), QString(QLatin1String("as")));
    QCOMPARE(keyFile.value(QLatin1String("default-unterminated-list")), QString(QLatin1String("list;of;misc")));
    QCOMPARE(keyFile.valueAsStringList(QLatin1String("default-unterminated-list")),
             QStringList() << QLatin1String("list") << QLatin1String("of") << QLatin1String("misc"));

    QCOMPARE(keyFile.value(QLatin1String("param-spaces-in-list")), QString(QLatin1String("as")));
    QCOMPARE(keyFile.value(QLatin1String("default-spaces-in-list")), QString(QLatin1String("list; of; misc ;")));
    QCOMPARE(keyFile.valueAsStringList(QLatin1String("default-spaces-in-list")),
             QStringList() << QLatin1String("list") << QLatin1String(" of") << QLatin1String(" misc "));

    QCOMPARE(keyFile.value(QLatin1String("param-escaped-semicolon-in-list")), QString(QLatin1String("as")));
    QCOMPARE(keyFile.value(QLatin1String("default-escaped-semicolon-in-list")), QString(QLatin1String("list;of;misc;")));
    QCOMPARE(keyFile.valueAsStringList(QLatin1String("default-escaped-semicolon-in-list")),
             QStringList() << QLatin1String("list;of") << QLatin1String("misc"));

    QCOMPARE(keyFile.value(QLatin1String("param-doubly-escaped-semicolon-in-list")), QString(QLatin1String("as")));
    QCOMPARE(keyFile.value(QLatin1String("default-doubly-escaped-semicolon-in-list")), QString(QLatin1String("list\\;of;misc;")));
    QCOMPARE(keyFile.valueAsStringList(QLatin1String("default-doubly-escaped-semicolon-in-list")),
             QStringList() << QLatin1String("list\\") << QLatin1String("of") << QLatin1String("misc"));

    QCOMPARE(keyFile.value(QLatin1String("param-triply-escaped-semicolon-in-list")), QString(QLatin1String("as")));
    QCOMPARE(keyFile.value(QLatin1String("default-triply-escaped-semicolon-in-list")), QString(QLatin1String("list\\;of;misc;")));
    QCOMPARE(keyFile.valueAsStringList(QLatin1String("default-triply-escaped-semicolon-in-list")),
             QStringList() << QLatin1String("list\\;of") << QLatin1String("misc"));

    QCOMPARE(keyFile.value(QLatin1String("param-empty-list")), QString(QLatin1String("as")));
    QCOMPARE(keyFile.value(QLatin1String("default-empty-list")), QString(QLatin1String("")));
    QCOMPARE(keyFile.valueAsStringList(QLatin1String("default-empty-list")), QStringList());

    QCOMPARE(keyFile.value(QLatin1String("param-list-of-empty-string")), QString(QLatin1String("as")));
    QCOMPARE(keyFile.value(QLatin1String("default-list-of-empty-string")), QString(QLatin1String(";")));
    QCOMPARE(keyFile.valueAsStringList(QLatin1String("default-list-of-empty-string")), QStringList() << QString());

    QCOMPARE(keyFile.value(QLatin1String("param-escaped-semicolon")), QString(QLatin1String("s")));
    QCOMPARE(keyFile.value(QLatin1String("default-escaped-semicolon")), QString(QLatin1String("foo;bar")));
}

QTEST_MAIN(TestKeyFile)

#include "_gen/key-file.cpp.moc.hpp"
<commit_msg>Fix TestKeyFile: sort list before comparing<commit_after>#include <QtTest/QtTest>

#include "TelepathyQt/key-file.h"

using namespace Tp;

class TestKeyFile : public QObject
{
    Q_OBJECT

private Q_SLOTS:
    void testKeyFile();
};

void TestKeyFile::testKeyFile()
{
    QString top_srcdir = QString::fromLocal8Bit(::getenv("abs_top_srcdir"));
    if (!top_srcdir.isEmpty()) {
        QDir::setCurrent(top_srcdir + QLatin1String("/tests"));
    }

    KeyFile defaultKeyFile;
    QCOMPARE(defaultKeyFile.status(), KeyFile::None);

    KeyFile notFoundkeyFile(QLatin1String("test-key-file-not-found.ini"));
    QCOMPARE(notFoundkeyFile.status(), KeyFile::NotFoundError);

    KeyFile formatErrorkeyFile(QLatin1String("test-key-file-format-error.ini"));
    QCOMPARE(formatErrorkeyFile.status(), KeyFile::FormatError);

    KeyFile keyFile(QLatin1String("test-key-file.ini"));
    QCOMPARE(keyFile.status(), KeyFile::NoError);

    QStringList allGroups = keyFile.allGroups();
    allGroups.sort();
    QCOMPARE(allGroups,
             QStringList() << QString() <<
                              QLatin1String("test group 1") <<
                              QLatin1String("test group 2"));

    QStringList allKeys = keyFile.allKeys();
    allKeys.sort();
    QCOMPARE(allKeys,
             QStringList() <<
             QLatin1String("a") <<
             QLatin1String("b") <<
             QLatin1String("c") <<
             QLatin1String("d") <<
             QLatin1String("e"));

    keyFile.setGroup(QLatin1String("test group 1"));
    QCOMPARE(keyFile.contains(QLatin1String("f")), false);
    QCOMPARE(keyFile.value(QLatin1String("c")).length(), 5);

    keyFile.setGroup(QLatin1String("test group 2"));
    QCOMPARE(keyFile.contains(QLatin1String("e")), true);
    QCOMPARE(keyFile.value(QLatin1String("e")), QString(QLatin1String("space")));

    keyFile.setFileName(QLatin1String("telepathy/managers/test-manager-file.manager"));
    QCOMPARE(keyFile.status(), KeyFile::NoError);

    keyFile.setGroup(QLatin1String("Protocol somewhat-pathological"));
    QCOMPARE(keyFile.value(QLatin1String("param-foo")), QString(QLatin1String("s required")));
    QCOMPARE(keyFile.value(QLatin1String("default-foo")), QString(QLatin1String("hello world")));

    QCOMPARE(keyFile.value(QLatin1String("param-semicolons")), QString(QLatin1String("s secret")));
    QCOMPARE(keyFile.value(QLatin1String("default-semicolons")), QString(QLatin1String("list;of;misc;")));

    QCOMPARE(keyFile.value(QLatin1String("param-list")), QString(QLatin1String("as")));
    QCOMPARE(keyFile.value(QLatin1String("default-list")), QString(QLatin1String("list;of;misc;")));
    QCOMPARE(keyFile.valueAsStringList(QLatin1String("default-list")),
             QStringList() << QLatin1String("list") << QLatin1String("of") << QLatin1String("misc"));

    QCOMPARE(keyFile.value(QLatin1String("param-unterminated-list")), QString(QLatin1String("as")));
    QCOMPARE(keyFile.value(QLatin1String("default-unterminated-list")), QString(QLatin1String("list;of;misc")));
    QCOMPARE(keyFile.valueAsStringList(QLatin1String("default-unterminated-list")),
             QStringList() << QLatin1String("list") << QLatin1String("of") << QLatin1String("misc"));

    QCOMPARE(keyFile.value(QLatin1String("param-spaces-in-list")), QString(QLatin1String("as")));
    QCOMPARE(keyFile.value(QLatin1String("default-spaces-in-list")), QString(QLatin1String("list; of; misc ;")));
    QCOMPARE(keyFile.valueAsStringList(QLatin1String("default-spaces-in-list")),
             QStringList() << QLatin1String("list") << QLatin1String(" of") << QLatin1String(" misc "));

    QCOMPARE(keyFile.value(QLatin1String("param-escaped-semicolon-in-list")), QString(QLatin1String("as")));
    QCOMPARE(keyFile.value(QLatin1String("default-escaped-semicolon-in-list")), QString(QLatin1String("list;of;misc;")));
    QCOMPARE(keyFile.valueAsStringList(QLatin1String("default-escaped-semicolon-in-list")),
             QStringList() << QLatin1String("list;of") << QLatin1String("misc"));

    QCOMPARE(keyFile.value(QLatin1String("param-doubly-escaped-semicolon-in-list")), QString(QLatin1String("as")));
    QCOMPARE(keyFile.value(QLatin1String("default-doubly-escaped-semicolon-in-list")), QString(QLatin1String("list\\;of;misc;")));
    QCOMPARE(keyFile.valueAsStringList(QLatin1String("default-doubly-escaped-semicolon-in-list")),
             QStringList() << QLatin1String("list\\") << QLatin1String("of") << QLatin1String("misc"));

    QCOMPARE(keyFile.value(QLatin1String("param-triply-escaped-semicolon-in-list")), QString(QLatin1String("as")));
    QCOMPARE(keyFile.value(QLatin1String("default-triply-escaped-semicolon-in-list")), QString(QLatin1String("list\\;of;misc;")));
    QCOMPARE(keyFile.valueAsStringList(QLatin1String("default-triply-escaped-semicolon-in-list")),
             QStringList() << QLatin1String("list\\;of") << QLatin1String("misc"));

    QCOMPARE(keyFile.value(QLatin1String("param-empty-list")), QString(QLatin1String("as")));
    QCOMPARE(keyFile.value(QLatin1String("default-empty-list")), QString(QLatin1String("")));
    QCOMPARE(keyFile.valueAsStringList(QLatin1String("default-empty-list")), QStringList());

    QCOMPARE(keyFile.value(QLatin1String("param-list-of-empty-string")), QString(QLatin1String("as")));
    QCOMPARE(keyFile.value(QLatin1String("default-list-of-empty-string")), QString(QLatin1String(";")));
    QCOMPARE(keyFile.valueAsStringList(QLatin1String("default-list-of-empty-string")), QStringList() << QString());

    QCOMPARE(keyFile.value(QLatin1String("param-escaped-semicolon")), QString(QLatin1String("s")));
    QCOMPARE(keyFile.value(QLatin1String("default-escaped-semicolon")), QString(QLatin1String("foo;bar")));
}

QTEST_MAIN(TestKeyFile)

#include "_gen/key-file.cpp.moc.hpp"
<|endoftext|>


<commit_before>
#include <map.hpp>

#include <datasource_cache.hpp>
#include <font_engine_freetype.hpp>
#include <agg_renderer.hpp>
#include <filter_factory.hpp>
#include <color_factory.hpp>
#include <image_util.hpp>

#include <iostream>

using namespace mapnik;

int main ( int argc , char** argv)
{
    if (argc != 2)
    {
        std::cout << "usage: ./rundemo <plugins_dir>\n";
        return EXIT_SUCCESS;
    }

    std::cout << " running demo ... \n";
    datasource_cache::instance()->register_datasources(argv[1]);
    freetype_engine::instance()->register_font("/usr/share/fonts/bitstream-vera/Vera.ttf");

    Map m(800,600);
    m.setBackground(color_factory::from_string("white"));

    // create styles

    // Provinces (polygon)
    feature_type_style provpoly_style;

    rule_type provpoly_rule_on;
    provpoly_rule_on.set_filter(create_filter("[NAME_EN] = 'Ontario'"));
    provpoly_rule_on.append(polygon_symbolizer(Color(250, 190, 183)));
    provpoly_style.add_rule(provpoly_rule_on);

    rule_type provpoly_rule_qc;
    provpoly_rule_qc.set_filter(create_filter("[NAME_EN] = 'Quebec'"));
    provpoly_rule_qc.append(polygon_symbolizer(Color(217, 235, 203)));
    provpoly_style.add_rule(provpoly_rule_qc);

    m.insert_style("provinces",provpoly_style);

    // Provinces (polyline)
    feature_type_style provlines_style;

    stroke provlines_stk (Color(0,0,0),1.0);
    provlines_stk.add_dash(8, 4);
    provlines_stk.add_dash(2, 2);
    provlines_stk.add_dash(2, 2);

    rule_type provlines_rule;
    provlines_rule.append(line_symbolizer(provlines_stk));
    provlines_style.add_rule(provlines_rule);

    m.insert_style("provlines",provlines_style);

    // Drainage
    feature_type_style qcdrain_style;

    rule_type qcdrain_rule;
    qcdrain_rule.set_filter(create_filter("[HYC] = 8"));
    qcdrain_rule.append(polygon_symbolizer(Color(153, 204, 255)));
    qcdrain_style.add_rule(qcdrain_rule);

    m.insert_style("drainage",qcdrain_style);

    // Roads 3 and 4 (The "grey" roads)
    feature_type_style roads34_style;
    rule_type roads34_rule;
    roads34_rule.set_filter(create_filter("[CLASS] = 3 or [CLASS] = 4"));
    stroke roads34_rule_stk(Color(171,158,137),2.0);
    roads34_rule_stk.set_line_cap(ROUND_CAP);
    roads34_rule_stk.set_line_join(ROUND_JOIN);
    roads34_rule.append(line_symbolizer(roads34_rule_stk));
    roads34_style.add_rule(roads34_rule);

    m.insert_style("smallroads",roads34_style);

    // Roads 2 (The thin yellow ones)
    feature_type_style roads2_style_1;
    rule_type roads2_rule_1;
    roads2_rule_1.set_filter(create_filter("[CLASS] = 2"));
    stroke roads2_rule_stk_1(Color(171,158,137),4.0);
    roads2_rule_stk_1.set_line_cap(ROUND_CAP);
    roads2_rule_stk_1.set_line_join(ROUND_JOIN);
    roads2_rule_1.append(line_symbolizer(roads2_rule_stk_1));
    roads2_style_1.add_rule(roads2_rule_1);

    m.insert_style("road-border", roads2_style_1);

    feature_type_style roads2_style_2;
    rule_type roads2_rule_2;
    roads2_rule_2.set_filter(create_filter("[CLASS] = 2"));
    stroke roads2_rule_stk_2(Color(255,250,115),2.0);
    roads2_rule_stk_2.set_line_cap(ROUND_CAP);
    roads2_rule_stk_2.set_line_join(ROUND_JOIN);
    roads2_rule_2.append(line_symbolizer(roads2_rule_stk_2));
    roads2_style_2.add_rule(roads2_rule_2);

    m.insert_style("road-fill", roads2_style_2);

    // Roads 1 (The big orange ones, the highways)
    feature_type_style roads1_style_1;
    rule_type roads1_rule_1;
    roads1_rule_1.set_filter(create_filter("[CLASS] = 1"));
    stroke roads1_rule_stk_1(Color(188,149,28),7.0);
    roads1_rule_stk_1.set_line_cap(ROUND_CAP);
    roads1_rule_stk_1.set_line_join(ROUND_JOIN);
    roads1_rule_1.append(line_symbolizer(roads1_rule_stk_1));
    roads1_style_1.add_rule(roads1_rule_1);
    m.insert_style("highway-border", roads1_style_1);

    feature_type_style roads1_style_2;
    rule_type roads1_rule_2;
    roads1_rule_2.set_filter(create_filter("[CLASS] = 1"));
    stroke roads1_rule_stk_2(Color(242,191,36),5.0);
    roads1_rule_stk_2.set_line_cap(ROUND_CAP);
    roads1_rule_stk_2.set_line_join(ROUND_JOIN);
    roads1_rule_2.append(line_symbolizer(roads1_rule_stk_2));
    roads1_style_2.add_rule(roads1_rule_2);
    m.insert_style("highway-fill", roads1_style_2);

    // Populated Places

    feature_type_style popplaces_style;
    rule_type popplaces_rule;
    text_symbolizer popplaces_text_symbolizer("GEONAME",10,Color(0,0,0));
    popplaces_text_symbolizer.set_halo_fill(Color(255,255,200));
    popplaces_text_symbolizer.set_halo_radius(1);
    popplaces_rule.append(popplaces_text_symbolizer);
    popplaces_style.add_rule(popplaces_rule);

    m.insert_style("popplaces",popplaces_style );

    // Layers
    // Provincial  polygons
    {
        parameters p;
        p["type"]="shape";
        p["file"]="../data/boundaries";

        Layer lyr("Provinces");
        lyr.set_datasource(datasource_cache::instance()->create(p));
        lyr.add_style("provinces");
        m.addLayer(lyr);
    }

    // Drainage
    {
        parameters p;
        p["type"]="shape";
        p["file"]="../data/qcdrainage";
        Layer lyr("Quebec Hydrography");
        lyr.set_datasource(datasource_cache::instance()->create(p));
        lyr.add_style("drainage");
        m.addLayer(lyr);
    }

    {
        parameters p;
        p["type"]="shape";
        p["file"]="../data/ontdrainage";

        Layer lyr("Ontario Hydrography");
        lyr.set_datasource(datasource_cache::instance()->create(p));
        lyr.add_style("drainage");
        m.addLayer(lyr);
    }

    // Provincial boundaries
    {
        parameters p;
        p["type"]="shape";
        p["file"]="../data/boundaries_l";
        Layer lyr("Provincial borders");
        lyr.set_datasource(datasource_cache::instance()->create(p));
        lyr.add_style("provlines");
        m.addLayer(lyr);
    }

    // Roads
    {
        parameters p;
        p["type"]="shape";
        p["file"]="../data/roads";
        Layer lyr("Roads");
        lyr.set_datasource(datasource_cache::instance()->create(p));
        lyr.add_style("smallroads");
        lyr.add_style("road-border");
        lyr.add_style("road-fill");
        lyr.add_style("highway-border");
        lyr.add_style("highway-fill");

        m.addLayer(lyr);
    }
    // popplaces
    {
        parameters p;
        p["type"]="shape";
        p["file"]="../data/popplaces";
        Layer lyr("Populated Places");
        lyr.set_datasource(datasource_cache::instance()->create(p));
        lyr.add_style("popplaces");
        m.addLayer(lyr);
    }

    m.zoomToBox(Envelope<double>(1405120.04127408,-247003.813399447,1706357.31328276,-25098.593149577));

    Image32 buf(m.getWidth(),m.getHeight());
    agg_renderer<Image32> ren(m,buf);
    ren.apply();

    ImageUtils::save_to_file("demo.jpg","jpeg",buf);
    ImageUtils::save_to_file("demo.png","png",buf);

    std::cout << "Two maps have been rendered in the current directory:\n"
        "- demo.jpg\n"
        "- demo.png\n"
        "Have a look!\n";

    return EXIT_SUCCESS;
}
<commit_msg>added copyleft header<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/
// $Id$

#include <map.hpp>

#include <datasource_cache.hpp>
#include <font_engine_freetype.hpp>
#include <agg_renderer.hpp>
#include <filter_factory.hpp>
#include <color_factory.hpp>
#include <image_util.hpp>

#include <iostream>

using namespace mapnik;

int main ( int argc , char** argv)
{
    if (argc != 2)
    {
        std::cout << "usage: ./rundemo <plugins_dir>\n";
        return EXIT_SUCCESS;
    }

    std::cout << " running demo ... \n";
    datasource_cache::instance()->register_datasources(argv[1]);
    freetype_engine::instance()->register_font("/usr/share/fonts/bitstream-vera/Vera.ttf");

    Map m(800,600);
    m.setBackground(color_factory::from_string("white"));

    // create styles

    // Provinces (polygon)
    feature_type_style provpoly_style;

    rule_type provpoly_rule_on;
    provpoly_rule_on.set_filter(create_filter("[NAME_EN] = 'Ontario'"));
    provpoly_rule_on.append(polygon_symbolizer(Color(250, 190, 183)));
    provpoly_style.add_rule(provpoly_rule_on);

    rule_type provpoly_rule_qc;
    provpoly_rule_qc.set_filter(create_filter("[NAME_EN] = 'Quebec'"));
    provpoly_rule_qc.append(polygon_symbolizer(Color(217, 235, 203)));
    provpoly_style.add_rule(provpoly_rule_qc);

    m.insert_style("provinces",provpoly_style);

    // Provinces (polyline)
    feature_type_style provlines_style;

    stroke provlines_stk (Color(0,0,0),1.0);
    provlines_stk.add_dash(8, 4);
    provlines_stk.add_dash(2, 2);
    provlines_stk.add_dash(2, 2);

    rule_type provlines_rule;
    provlines_rule.append(line_symbolizer(provlines_stk));
    provlines_style.add_rule(provlines_rule);

    m.insert_style("provlines",provlines_style);

    // Drainage
    feature_type_style qcdrain_style;

    rule_type qcdrain_rule;
    qcdrain_rule.set_filter(create_filter("[HYC] = 8"));
    qcdrain_rule.append(polygon_symbolizer(Color(153, 204, 255)));
    qcdrain_style.add_rule(qcdrain_rule);

    m.insert_style("drainage",qcdrain_style);

    // Roads 3 and 4 (The "grey" roads)
    feature_type_style roads34_style;
    rule_type roads34_rule;
    roads34_rule.set_filter(create_filter("[CLASS] = 3 or [CLASS] = 4"));
    stroke roads34_rule_stk(Color(171,158,137),2.0);
    roads34_rule_stk.set_line_cap(ROUND_CAP);
    roads34_rule_stk.set_line_join(ROUND_JOIN);
    roads34_rule.append(line_symbolizer(roads34_rule_stk));
    roads34_style.add_rule(roads34_rule);

    m.insert_style("smallroads",roads34_style);

    // Roads 2 (The thin yellow ones)
    feature_type_style roads2_style_1;
    rule_type roads2_rule_1;
    roads2_rule_1.set_filter(create_filter("[CLASS] = 2"));
    stroke roads2_rule_stk_1(Color(171,158,137),4.0);
    roads2_rule_stk_1.set_line_cap(ROUND_CAP);
    roads2_rule_stk_1.set_line_join(ROUND_JOIN);
    roads2_rule_1.append(line_symbolizer(roads2_rule_stk_1));
    roads2_style_1.add_rule(roads2_rule_1);

    m.insert_style("road-border", roads2_style_1);

    feature_type_style roads2_style_2;
    rule_type roads2_rule_2;
    roads2_rule_2.set_filter(create_filter("[CLASS] = 2"));
    stroke roads2_rule_stk_2(Color(255,250,115),2.0);
    roads2_rule_stk_2.set_line_cap(ROUND_CAP);
    roads2_rule_stk_2.set_line_join(ROUND_JOIN);
    roads2_rule_2.append(line_symbolizer(roads2_rule_stk_2));
    roads2_style_2.add_rule(roads2_rule_2);

    m.insert_style("road-fill", roads2_style_2);

    // Roads 1 (The big orange ones, the highways)
    feature_type_style roads1_style_1;
    rule_type roads1_rule_1;
    roads1_rule_1.set_filter(create_filter("[CLASS] = 1"));
    stroke roads1_rule_stk_1(Color(188,149,28),7.0);
    roads1_rule_stk_1.set_line_cap(ROUND_CAP);
    roads1_rule_stk_1.set_line_join(ROUND_JOIN);
    roads1_rule_1.append(line_symbolizer(roads1_rule_stk_1));
    roads1_style_1.add_rule(roads1_rule_1);
    m.insert_style("highway-border", roads1_style_1);

    feature_type_style roads1_style_2;
    rule_type roads1_rule_2;
    roads1_rule_2.set_filter(create_filter("[CLASS] = 1"));
    stroke roads1_rule_stk_2(Color(242,191,36),5.0);
    roads1_rule_stk_2.set_line_cap(ROUND_CAP);
    roads1_rule_stk_2.set_line_join(ROUND_JOIN);
    roads1_rule_2.append(line_symbolizer(roads1_rule_stk_2));
    roads1_style_2.add_rule(roads1_rule_2);
    m.insert_style("highway-fill", roads1_style_2);

    // Populated Places

    feature_type_style popplaces_style;
    rule_type popplaces_rule;
    text_symbolizer popplaces_text_symbolizer("GEONAME",10,Color(0,0,0));
    popplaces_text_symbolizer.set_halo_fill(Color(255,255,200));
    popplaces_text_symbolizer.set_halo_radius(1);
    popplaces_rule.append(popplaces_text_symbolizer);
    popplaces_style.add_rule(popplaces_rule);

    m.insert_style("popplaces",popplaces_style );

    // Layers
    // Provincial  polygons
    {
        parameters p;
        p["type"]="shape";
        p["file"]="../data/boundaries";

        Layer lyr("Provinces");
        lyr.set_datasource(datasource_cache::instance()->create(p));
        lyr.add_style("provinces");
        m.addLayer(lyr);
    }

    // Drainage
    {
        parameters p;
        p["type"]="shape";
        p["file"]="../data/qcdrainage";
        Layer lyr("Quebec Hydrography");
        lyr.set_datasource(datasource_cache::instance()->create(p));
        lyr.add_style("drainage");
        m.addLayer(lyr);
    }

    {
        parameters p;
        p["type"]="shape";
        p["file"]="../data/ontdrainage";

        Layer lyr("Ontario Hydrography");
        lyr.set_datasource(datasource_cache::instance()->create(p));
        lyr.add_style("drainage");
        m.addLayer(lyr);
    }

    // Provincial boundaries
    {
        parameters p;
        p["type"]="shape";
        p["file"]="../data/boundaries_l";
        Layer lyr("Provincial borders");
        lyr.set_datasource(datasource_cache::instance()->create(p));
        lyr.add_style("provlines");
        m.addLayer(lyr);
    }

    // Roads
    {
        parameters p;
        p["type"]="shape";
        p["file"]="../data/roads";
        Layer lyr("Roads");
        lyr.set_datasource(datasource_cache::instance()->create(p));
        lyr.add_style("smallroads");
        lyr.add_style("road-border");
        lyr.add_style("road-fill");
        lyr.add_style("highway-border");
        lyr.add_style("highway-fill");

        m.addLayer(lyr);
    }
    // popplaces
    {
        parameters p;
        p["type"]="shape";
        p["file"]="../data/popplaces";
        Layer lyr("Populated Places");
        lyr.set_datasource(datasource_cache::instance()->create(p));
        lyr.add_style("popplaces");
        m.addLayer(lyr);
    }

    m.zoomToBox(Envelope<double>(1405120.04127408,-247003.813399447,1706357.31328276,-25098.593149577));

    Image32 buf(m.getWidth(),m.getHeight());
    agg_renderer<Image32> ren(m,buf);
    ren.apply();

    ImageUtils::save_to_file("demo.jpg","jpeg",buf);
    ImageUtils::save_to_file("demo.png","png",buf);

    std::cout << "Two maps have been rendered in the current directory:\n"
        "- demo.jpg\n"
        "- demo.png\n"
        "Have a look!\n";

    return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/
// $Id$

// define before any includes
#define BOOST_SPIRIT_THREADSAFE

#include <mapnik/map.hpp>
#include <mapnik/datasource_cache.hpp>
#include <mapnik/font_engine_freetype.hpp>
#include <mapnik/agg_renderer.hpp>
#include <mapnik/filter_factory.hpp>
#include <mapnik/color_factory.hpp>
#include <mapnik/image_util.hpp>
#include <mapnik/config_error.hpp>

#include <iostream>

int main ( int argc , char** argv)
{
    if (argc != 2)
    {
        std::cout << "usage: ./rundemo <mapnik_install_dir>\n";
        return EXIT_SUCCESS;
    }

    using namespace mapnik;
    try {
        std::cout << " running demo ... \n";
        std::string mapnik_dir(argv[1]);
        datasource_cache::instance()->register_datasources(mapnik_dir + "/lib/mapnik/input/");
        freetype_engine::register_font(mapnik_dir + "/lib/mapnik/fonts/DejaVuSans.ttf");

        Map m(800,600);
        m.set_background(color_factory::from_string("white"));

        // create styles

        // Provinces (polygon)
        feature_type_style provpoly_style;

        rule_type provpoly_rule_on;
        provpoly_rule_on.set_filter(create_filter("[NAME_EN] = 'Ontario'"));
        provpoly_rule_on.append(polygon_symbolizer(Color(250, 190, 183)));
        provpoly_style.add_rule(provpoly_rule_on);

        rule_type provpoly_rule_qc;
        provpoly_rule_qc.set_filter(create_filter("[NAME_EN] = 'Quebec'"));
        provpoly_rule_qc.append(polygon_symbolizer(Color(217, 235, 203)));
        provpoly_style.add_rule(provpoly_rule_qc);

        m.insert_style("provinces",provpoly_style);

        // Provinces (polyline)
        feature_type_style provlines_style;

        stroke provlines_stk (Color(0,0,0),1.0);
        provlines_stk.add_dash(8, 4);
        provlines_stk.add_dash(2, 2);
        provlines_stk.add_dash(2, 2);

        rule_type provlines_rule;
        provlines_rule.append(line_symbolizer(provlines_stk));
        provlines_style.add_rule(provlines_rule);

        m.insert_style("provlines",provlines_style);

        // Drainage
        feature_type_style qcdrain_style;

        rule_type qcdrain_rule;
        qcdrain_rule.set_filter(create_filter("[HYC] = 8"));
        qcdrain_rule.append(polygon_symbolizer(Color(153, 204, 255)));
        qcdrain_style.add_rule(qcdrain_rule);

        m.insert_style("drainage",qcdrain_style);

        // Roads 3 and 4 (The "grey" roads)
        feature_type_style roads34_style;
        rule_type roads34_rule;
        roads34_rule.set_filter(create_filter("[CLASS] = 3 or [CLASS] = 4"));
        stroke roads34_rule_stk(Color(171,158,137),2.0);
        roads34_rule_stk.set_line_cap(ROUND_CAP);
        roads34_rule_stk.set_line_join(ROUND_JOIN);
        roads34_rule.append(line_symbolizer(roads34_rule_stk));
        roads34_style.add_rule(roads34_rule);

        m.insert_style("smallroads",roads34_style);

        // Roads 2 (The thin yellow ones)
        feature_type_style roads2_style_1;
        rule_type roads2_rule_1;
        roads2_rule_1.set_filter(create_filter("[CLASS] = 2"));
        stroke roads2_rule_stk_1(Color(171,158,137),4.0);
        roads2_rule_stk_1.set_line_cap(ROUND_CAP);
        roads2_rule_stk_1.set_line_join(ROUND_JOIN);
        roads2_rule_1.append(line_symbolizer(roads2_rule_stk_1));
        roads2_style_1.add_rule(roads2_rule_1);

        m.insert_style("road-border", roads2_style_1);

        feature_type_style roads2_style_2;
        rule_type roads2_rule_2;
        roads2_rule_2.set_filter(create_filter("[CLASS] = 2"));
        stroke roads2_rule_stk_2(Color(255,250,115),2.0);
        roads2_rule_stk_2.set_line_cap(ROUND_CAP);
        roads2_rule_stk_2.set_line_join(ROUND_JOIN);
        roads2_rule_2.append(line_symbolizer(roads2_rule_stk_2));
        roads2_style_2.add_rule(roads2_rule_2);

        m.insert_style("road-fill", roads2_style_2);

        // Roads 1 (The big orange ones, the highways)
        feature_type_style roads1_style_1;
        rule_type roads1_rule_1;
        roads1_rule_1.set_filter(create_filter("[CLASS] = 1"));
        stroke roads1_rule_stk_1(Color(188,149,28),7.0);
        roads1_rule_stk_1.set_line_cap(ROUND_CAP);
        roads1_rule_stk_1.set_line_join(ROUND_JOIN);
        roads1_rule_1.append(line_symbolizer(roads1_rule_stk_1));
        roads1_style_1.add_rule(roads1_rule_1);
        m.insert_style("highway-border", roads1_style_1);

        feature_type_style roads1_style_2;
        rule_type roads1_rule_2;
        roads1_rule_2.set_filter(create_filter("[CLASS] = 1"));
        stroke roads1_rule_stk_2(Color(242,191,36),5.0);
        roads1_rule_stk_2.set_line_cap(ROUND_CAP);
        roads1_rule_stk_2.set_line_join(ROUND_JOIN);
        roads1_rule_2.append(line_symbolizer(roads1_rule_stk_2));
        roads1_style_2.add_rule(roads1_rule_2);
        m.insert_style("highway-fill", roads1_style_2);

        // Populated Places

        feature_type_style popplaces_style;
        rule_type popplaces_rule;
        text_symbolizer popplaces_text_symbolizer("GEONAME","DejaVu Sans Book",10,Color(0,0,0));
        popplaces_text_symbolizer.set_halo_fill(Color(255,255,200));
        popplaces_text_symbolizer.set_halo_radius(1);
        popplaces_rule.append(popplaces_text_symbolizer);
        popplaces_style.add_rule(popplaces_rule);

        m.insert_style("popplaces",popplaces_style );

        // Layers
        // Provincial  polygons
        {
            parameters p;
            p["type"]="shape";
            p["file"]="../data/boundaries";

            Layer lyr("Provinces");
            lyr.set_datasource(datasource_cache::instance()->create(p));
            lyr.add_style("provinces");
            m.addLayer(lyr);
        }

        // Drainage
        {
            parameters p;
            p["type"]="shape";
            p["file"]="../data/qcdrainage";
            Layer lyr("Quebec Hydrography");
            lyr.set_datasource(datasource_cache::instance()->create(p));
            lyr.add_style("drainage");
            m.addLayer(lyr);
        }

        {
            parameters p;
            p["type"]="shape";
            p["file"]="../data/ontdrainage";

            Layer lyr("Ontario Hydrography");
            lyr.set_datasource(datasource_cache::instance()->create(p));
            lyr.add_style("drainage");
            m.addLayer(lyr);
        }

        // Provincial boundaries
        {
            parameters p;
            p["type"]="shape";
            p["file"]="../data/boundaries_l";
            Layer lyr("Provincial borders");
            lyr.set_datasource(datasource_cache::instance()->create(p));
            lyr.add_style("provlines");
            m.addLayer(lyr);
        }

        // Roads
        {
            parameters p;
            p["type"]="shape";
            p["file"]="../data/roads";
            Layer lyr("Roads");
            lyr.set_datasource(datasource_cache::instance()->create(p));
            lyr.add_style("smallroads");
            lyr.add_style("road-border");
            lyr.add_style("road-fill");
            lyr.add_style("highway-border");
            lyr.add_style("highway-fill");

            m.addLayer(lyr);
        }
        // popplaces
        {
            parameters p;
            p["type"]="shape";
            p["file"]="../data/popplaces";
            p["encoding"] = "latin1";
            Layer lyr("Populated Places");
            lyr.set_datasource(datasource_cache::instance()->create(p));
            lyr.add_style("popplaces");
            m.addLayer(lyr);
        }

        m.zoomToBox(Envelope<double>(1405120.04127408,-247003.813399447,
                                     1706357.31328276,-25098.593149577));

        Image32 buf(m.getWidth(),m.getHeight());
        agg_renderer<Image32> ren(m,buf);
        ren.apply();

        save_to_file<ImageData32>("demo.jpg","jpeg",buf.data());
        save_to_file<ImageData32>("demo.png","png",buf.data());
        save_to_file<ImageData32>("demo256.png","png256",buf.data());
        std::cout << "Three maps have been rendered in the current directory:\n"
           "- demo.jpg\n"
           "- demo.png\n"
           "- demo256.png\n"
           "Have a look!\n";
    }
    catch ( const mapnik::config_error & ex )
    {
        std::cerr << "### Configuration error: " << ex.what();
        return EXIT_FAILURE;
    }
    catch ( const std::exception & ex )
    {
        std::cerr << "### std::exception: " << ex.what();
        return EXIT_FAILURE;
    }
    catch ( ... )
    {
        std::cerr << "### Unknown exception." << std::endl;
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}
<commit_msg>updated to be compatble with latest trunk<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/
// $Id$

// define before any includes
#define BOOST_SPIRIT_THREADSAFE

#include <mapnik/map.hpp>
#include <mapnik/datasource_cache.hpp>
#include <mapnik/font_engine_freetype.hpp>
#include <mapnik/agg_renderer.hpp>
#include <mapnik/filter_factory.hpp>
#include <mapnik/color_factory.hpp>
#include <mapnik/image_util.hpp>
#include <mapnik/config_error.hpp>

#include <iostream>

int main ( int argc , char** argv)
{
    if (argc != 2)
    {
        std::cout << "usage: ./rundemo <mapnik_install_dir>\n";
        return EXIT_SUCCESS;
    }

    using namespace mapnik;
    try {
        std::cout << " running demo ... \n";
        std::string mapnik_dir(argv[1]);
        datasource_cache::instance()->register_datasources(mapnik_dir + "/lib/mapnik/input/");
        freetype_engine::register_font(mapnik_dir + "/lib/mapnik/fonts/DejaVuSans.ttf");

        Map m(800,600);
        m.set_background(color_factory::from_string("white"));

        // create styles

        // Provinces (polygon)
        feature_type_style provpoly_style;

        rule_type provpoly_rule_on;
        provpoly_rule_on.set_filter(create_filter("[NAME_EN] = 'Ontario'"));
        provpoly_rule_on.append(polygon_symbolizer(Color(250, 190, 183)));
        provpoly_style.add_rule(provpoly_rule_on);

        rule_type provpoly_rule_qc;
        provpoly_rule_qc.set_filter(create_filter("[NAME_EN] = 'Quebec'"));
        provpoly_rule_qc.append(polygon_symbolizer(Color(217, 235, 203)));
        provpoly_style.add_rule(provpoly_rule_qc);

        m.insert_style("provinces",provpoly_style);

        // Provinces (polyline)
        feature_type_style provlines_style;

        stroke provlines_stk (Color(0,0,0),1.0);
        provlines_stk.add_dash(8, 4);
        provlines_stk.add_dash(2, 2);
        provlines_stk.add_dash(2, 2);

        rule_type provlines_rule;
        provlines_rule.append(line_symbolizer(provlines_stk));
        provlines_style.add_rule(provlines_rule);

        m.insert_style("provlines",provlines_style);

        // Drainage
        feature_type_style qcdrain_style;

        rule_type qcdrain_rule;
        qcdrain_rule.set_filter(create_filter("[HYC] = 8"));
        qcdrain_rule.append(polygon_symbolizer(Color(153, 204, 255)));
        qcdrain_style.add_rule(qcdrain_rule);

        m.insert_style("drainage",qcdrain_style);

        // Roads 3 and 4 (The "grey" roads)
        feature_type_style roads34_style;
        rule_type roads34_rule;
        roads34_rule.set_filter(create_filter("[CLASS] = 3 or [CLASS] = 4"));
        stroke roads34_rule_stk(Color(171,158,137),2.0);
        roads34_rule_stk.set_line_cap(ROUND_CAP);
        roads34_rule_stk.set_line_join(ROUND_JOIN);
        roads34_rule.append(line_symbolizer(roads34_rule_stk));
        roads34_style.add_rule(roads34_rule);

        m.insert_style("smallroads",roads34_style);

        // Roads 2 (The thin yellow ones)
        feature_type_style roads2_style_1;
        rule_type roads2_rule_1;
        roads2_rule_1.set_filter(create_filter("[CLASS] = 2"));
        stroke roads2_rule_stk_1(Color(171,158,137),4.0);
        roads2_rule_stk_1.set_line_cap(ROUND_CAP);
        roads2_rule_stk_1.set_line_join(ROUND_JOIN);
        roads2_rule_1.append(line_symbolizer(roads2_rule_stk_1));
        roads2_style_1.add_rule(roads2_rule_1);

        m.insert_style("road-border", roads2_style_1);

        feature_type_style roads2_style_2;
        rule_type roads2_rule_2;
        roads2_rule_2.set_filter(create_filter("[CLASS] = 2"));
        stroke roads2_rule_stk_2(Color(255,250,115),2.0);
        roads2_rule_stk_2.set_line_cap(ROUND_CAP);
        roads2_rule_stk_2.set_line_join(ROUND_JOIN);
        roads2_rule_2.append(line_symbolizer(roads2_rule_stk_2));
        roads2_style_2.add_rule(roads2_rule_2);

        m.insert_style("road-fill", roads2_style_2);

        // Roads 1 (The big orange ones, the highways)
        feature_type_style roads1_style_1;
        rule_type roads1_rule_1;
        roads1_rule_1.set_filter(create_filter("[CLASS] = 1"));
        stroke roads1_rule_stk_1(Color(188,149,28),7.0);
        roads1_rule_stk_1.set_line_cap(ROUND_CAP);
        roads1_rule_stk_1.set_line_join(ROUND_JOIN);
        roads1_rule_1.append(line_symbolizer(roads1_rule_stk_1));
        roads1_style_1.add_rule(roads1_rule_1);
        m.insert_style("highway-border", roads1_style_1);

        feature_type_style roads1_style_2;
        rule_type roads1_rule_2;
        roads1_rule_2.set_filter(create_filter("[CLASS] = 1"));
        stroke roads1_rule_stk_2(Color(242,191,36),5.0);
        roads1_rule_stk_2.set_line_cap(ROUND_CAP);
        roads1_rule_stk_2.set_line_join(ROUND_JOIN);
        roads1_rule_2.append(line_symbolizer(roads1_rule_stk_2));
        roads1_style_2.add_rule(roads1_rule_2);
        m.insert_style("highway-fill", roads1_style_2);

        // Populated Places

        feature_type_style popplaces_style;
        rule_type popplaces_rule;
        text_symbolizer popplaces_text_symbolizer("GEONAME","DejaVu Sans Book",10,Color(0,0,0));
        popplaces_text_symbolizer.set_halo_fill(Color(255,255,200));
        popplaces_text_symbolizer.set_halo_radius(1);
        popplaces_rule.append(popplaces_text_symbolizer);
        popplaces_style.add_rule(popplaces_rule);

        m.insert_style("popplaces",popplaces_style );

        // Layers
        // Provincial  polygons
        {
            parameters p;
            p["type"]="shape";
            p["file"]="../data/boundaries";

            Layer lyr("Provinces");
            lyr.set_datasource(datasource_cache::instance()->create(p));
            lyr.add_style("provinces");
            m.addLayer(lyr);
        }

        // Drainage
        {
            parameters p;
            p["type"]="shape";
            p["file"]="../data/qcdrainage";
            Layer lyr("Quebec Hydrography");
            lyr.set_datasource(datasource_cache::instance()->create(p));
            lyr.add_style("drainage");
            m.addLayer(lyr);
        }

        {
            parameters p;
            p["type"]="shape";
            p["file"]="../data/ontdrainage";

            Layer lyr("Ontario Hydrography");
            lyr.set_datasource(datasource_cache::instance()->create(p));
            lyr.add_style("drainage");
            m.addLayer(lyr);
        }

        // Provincial boundaries
        {
            parameters p;
            p["type"]="shape";
            p["file"]="../data/boundaries_l";
            Layer lyr("Provincial borders");
            lyr.set_datasource(datasource_cache::instance()->create(p));
            lyr.add_style("provlines");
            m.addLayer(lyr);
        }

        // Roads
        {
            parameters p;
            p["type"]="shape";
            p["file"]="../data/roads";
            Layer lyr("Roads");
            lyr.set_datasource(datasource_cache::instance()->create(p));
            lyr.add_style("smallroads");
            lyr.add_style("road-border");
            lyr.add_style("road-fill");
            lyr.add_style("highway-border");
            lyr.add_style("highway-fill");

            m.addLayer(lyr);
        }
        // popplaces
        {
            parameters p;
            p["type"]="shape";
            p["file"]="../data/popplaces";
            p["encoding"] = "latin1";
            Layer lyr("Populated Places");
            lyr.set_datasource(datasource_cache::instance()->create(p));
            lyr.add_style("popplaces");
            m.addLayer(lyr);
        }

        m.zoomToBox(Envelope<double>(1405120.04127408,-247003.813399447,
                                     1706357.31328276,-25098.593149577));

        Image32 buf(m.getWidth(),m.getHeight());
        agg_renderer<Image32> ren(m,buf);
        ren.apply();

        save_to_file<ImageData32>(buf.data(),"demo.jpg","jpeg");
        save_to_file<ImageData32>(buf.data(),"demo.png","png");
        save_to_file<ImageData32>(buf.data(),"demo256.png","png256");
        std::cout << "Three maps have been rendered in the current directory:\n"
           "- demo.jpg\n"
           "- demo.png\n"
           "- demo256.png\n"
           "Have a look!\n";
    }
    catch ( const mapnik::config_error & ex )
    {
        std::cerr << "### Configuration error: " << ex.what();
        return EXIT_FAILURE;
    }
    catch ( const std::exception & ex )
    {
        std::cerr << "### std::exception: " << ex.what();
        return EXIT_FAILURE;
    }
    catch ( ... )
    {
        std::cerr << "### Unknown exception." << std::endl;
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>/**
 * @file
 */
#pragma once

#include "libbirch/external.hpp"
#include "libbirch/memory.hpp"
#include "libbirch/class.hpp"

namespace libbirch {
/**
 * Base class for reference counted objects.
 *
 * @attention In order to work correctly, Counted must be the *first* base
 * class in any inheritance hierarchy. This is particularly important when
 * multiple inheritance is used.
 *
 * @ingroup libbirch
 */
class Counted {
protected:
  /**
   * Constructor.
   */
  Counted();

  /**
   * Copy constructor.
   */
  Counted(const Counted& o);

  /**
   * Destructor.
   */
  virtual ~Counted();

  /**
   * Assignment operator.
   */
  Counted& operator=(const Counted&) = delete;

public:
  /**
   * Create an object,
   */
  template<class... Args>
  static Counted* create_(Args... args) {
    return emplace_(allocate<sizeof(Counted)>(), args...);
  }

  /**
   * Create an object in previously-allocated memory.
   */
  template<class... Args>
  static Counted* emplace_(void* ptr, Args... args) {
    auto o = new (ptr) Counted();
    o->size = sizeof(Counted);
    return o;
  }

  /**
   * Clone the object.
   */
  virtual Counted* clone_() const {
    return emplace_(allocate<sizeof(Counted)>(), *this);
  }

  /**
   * Clone the object into previous allocation.
   */
  virtual Counted* clone_(void* ptr) const {
    return emplace_(ptr, *this);
  }

  /**
   * Destroy the object.
   */
  virtual void destroy_() {
    this->~Counted();
  }

  /**
   * Deallocate the object.
   */
  void deallocate();

  /**
   * Get the size, in bytes, of the object.
   */
  unsigned getSize() const;

  /**
   * Increment the shared count.
   */
  void incShared();

  /**
   * Decrement the shared count.
   */
  void decShared();

  /**
   * Shared count.
   */
  unsigned numShared() const;

  /**
   * Increment the weak count.
   */
  void incWeak();

  /**
   * Decrement the weak count.
   */
  void decWeak();

  /**
   * Weak count.
   */
  unsigned numWeak() const;

  #if ENABLE_LAZY_DEEP_CLONE
  /**
   * Increment the memo count (implies an increment of the weak count also).
   */
  void incMemo();

  /**
   * Decrement the memo count (implies a decrement of the weak count also).
   */
  void decMemo();

  /**
   * Memo count.
   */
  unsigned numMemo() const;

  /**
   * Is the object reachable? An object is reachable if it contains a shared
   * count of one or more, or a weak count greater than the memo count. When
   * the weak count equals the memo count (it cannot be less), the object
   * is only reachable via keys in memos, which will never be triggered, and
   * so the object is not considered reachable.
   */
  bool isReachable() const;
  #endif

  /**
   * Name of the class.
   */
  virtual const char* name_() const {
    return "Counted";
  }

protected:
  /**
   * Shared count.
   */
  Atomic<unsigned> sharedCount;

  /**
   * Weak count.
   */
  Atomic<unsigned> weakCount;

  #if ENABLE_LAZY_DEEP_CLONE
  /**
   * Memo count. This is the number of times that the object occurs as a key
   * in a memo. It is always less than or equal to the weak count, as each
   * memo reference implies a weak reference also.
   */
  Atomic<unsigned> memoCount;
  #endif

  /**
   * Size of the object. This is set immediately after construction. A value
   * of zero is also indicative that the object is still being constructed.
   * Consequently, if the shared count reaches zero while the size is zero,
   * the object is not destroyed. This can happen when constructors create
   * shared pointers to `this`.
   */
  unsigned size;

  /**
   * Id of the thread associated with the object. This is used to return the
   * allocation to the correct pool after use, even when returned by a
   * different thread.
   */
  unsigned tid;
};
}

#include "libbirch/thread.hpp"

inline libbirch::Counted::Counted() :
    sharedCount(0u),
    weakCount(1u),
    #if ENABLE_LAZY_DEEP_CLONE
    memoCount(0u),
    #endif
    size(0u),
    tid(libbirch::tid) {
  //
}

inline libbirch::Counted::Counted(const Counted& o) :
    sharedCount(0u),
    weakCount(1u),
    #if ENABLE_LAZY_DEEP_CLONE
    memoCount(0u),
    #endif
    size(o.size),
    tid(libbirch::tid) {
  //
}

inline libbirch::Counted::~Counted() {
  assert(sharedCount.load() == 0u);
}

inline void libbirch::Counted::deallocate() {
  assert(sharedCount.load() == 0u);
  assert(weakCount.load() == 0u);
  libbirch::deallocate(this, size, tid);
}

inline unsigned libbirch::Counted::getSize() const {
  return size;
}

inline void libbirch::Counted::incShared() {
  sharedCount.increment();
}

inline void libbirch::Counted::decShared() {
  assert(sharedCount.load() > 0u);
  if (--sharedCount == 0u && size > 0u) {
    // ^ size == 0u during construction, never destroy in that case
    destroy_();
    decWeak();  // release weak self-reference
  }
}

inline unsigned libbirch::Counted::numShared() const {
  return sharedCount.load();
}

inline void libbirch::Counted::incWeak() {
  weakCount.increment();
}

inline void libbirch::Counted::decWeak() {
  assert(weakCount.load() > 0u);
  if (--weakCount == 0u) {
    assert(sharedCount.load() == 0u);
    // ^ because of weak self-reference, the weak count should not expire
    //   before the shared count
    deallocate();
  }
}

inline unsigned libbirch::Counted::numWeak() const {
  return weakCount.load();
}

#if ENABLE_LAZY_DEEP_CLONE
inline void libbirch::Counted::incMemo() {
  /* the order of operations here is important, as the weak count should
   * never be less than the memo count */
  incWeak();
  memoCount.increment();
}

inline void libbirch::Counted::decMemo() {
  /* the order of operations here is important, as the weak count should
   * never be less than the memo count */
  assert(memoCount.load() > 0u);
  memoCount.decrement();
  decWeak();
}

inline unsigned libbirch::Counted::numMemo() const {
  return memoCount.load();
}

inline bool libbirch::Counted::isReachable() const {
  return numWeak() > numMemo();
}
#endif
<commit_msg>Fixed race condition between weak and memo reference counts. (Compilers silently ignoring seq_cst ordering?)<commit_after>/**
 * @file
 */
#pragma once

#include "libbirch/external.hpp"
#include "libbirch/memory.hpp"
#include "libbirch/class.hpp"

namespace libbirch {
/**
 * Base class for reference counted objects.
 *
 * @attention In order to work correctly, Counted must be the *first* base
 * class in any inheritance hierarchy. This is particularly important when
 * multiple inheritance is used.
 *
 * @ingroup libbirch
 */
class Counted {
protected:
  /**
   * Constructor.
   */
  Counted();

  /**
   * Copy constructor.
   */
  Counted(const Counted& o);

  /**
   * Destructor.
   */
  virtual ~Counted();

  /**
   * Assignment operator.
   */
  Counted& operator=(const Counted&) = delete;

public:
  /**
   * Create an object,
   */
  template<class... Args>
  static Counted* create_(Args... args) {
    return emplace_(allocate<sizeof(Counted)>(), args...);
  }

  /**
   * Create an object in previously-allocated memory.
   */
  template<class... Args>
  static Counted* emplace_(void* ptr, Args... args) {
    auto o = new (ptr) Counted();
    o->size = sizeof(Counted);
    return o;
  }

  /**
   * Clone the object.
   */
  virtual Counted* clone_() const {
    return emplace_(allocate<sizeof(Counted)>(), *this);
  }

  /**
   * Clone the object into previous allocation.
   */
  virtual Counted* clone_(void* ptr) const {
    return emplace_(ptr, *this);
  }

  /**
   * Destroy the object.
   */
  virtual void destroy_() {
    this->~Counted();
  }

  /**
   * Deallocate the object.
   */
  void deallocate();

  /**
   * Get the size, in bytes, of the object.
   */
  unsigned getSize() const;

  /**
   * Increment the shared count.
   */
  void incShared();

  /**
   * Decrement the shared count.
   */
  void decShared();

  /**
   * Shared count.
   */
  unsigned numShared() const;

  /**
   * Increment the weak count.
   */
  void incWeak();

  /**
   * Decrement the weak count.
   */
  void decWeak();

  /**
   * Weak count.
   */
  unsigned numWeak() const;

  #if ENABLE_LAZY_DEEP_CLONE
  /**
   * Increment the memo count (implies an increment of the weak count also).
   */
  void incMemo();

  /**
   * Decrement the memo count (implies a decrement of the weak count also).
   */
  void decMemo();

  /**
   * Memo count.
   */
  unsigned numMemo() const;

  /**
   * Is the object reachable? An object is reachable if it contains a shared
   * count of one or more, or a weak count greater than the memo count. When
   * the weak count equals the memo count (it cannot be less), the object
   * is only reachable via keys in memos, which will never be triggered, and
   * so the object is not considered reachable.
   */
  bool isReachable() const;
  #endif

  /**
   * Name of the class.
   */
  virtual const char* name_() const {
    return "Counted";
  }

protected:
  /**
   * Shared count.
   */
  Atomic<unsigned> sharedCount;

  /**
   * Weak count. This is one plus the number of times that the object is held
   * by a weak pointer. The plus one is a self-reference that is released
   * when the shared count reaches zero.
   */
  Atomic<unsigned> weakCount;

  #if ENABLE_LAZY_DEEP_CLONE
  /**
   * Memo count. This is one plus the number of times that the object occurs
   * as a key in a memo. The plus one is a self-reference that is relased
   * when the weak count reaches zero.
   */
  Atomic<unsigned> memoCount;
  #endif

  /**
   * Size of the object. This is set immediately after construction. A value
   * of zero is also indicative that the object is still being constructed.
   * Consequently, if the shared count reaches zero while the size is zero,
   * the object is not destroyed. This can happen when constructors create
   * shared pointers to `this`.
   */
  unsigned size;

  /**
   * Id of the thread associated with the object. This is used to return the
   * allocation to the correct pool after use, even when returned by a
   * different thread.
   */
  unsigned tid;
};
}

#include "libbirch/thread.hpp"

inline libbirch::Counted::Counted() :
    sharedCount(0u),
    weakCount(1u),
    #if ENABLE_LAZY_DEEP_CLONE
    memoCount(1u),
    #endif
    size(0u),
    tid(libbirch::tid) {
  //
}

inline libbirch::Counted::Counted(const Counted& o) :
    sharedCount(0u),
    weakCount(1u),
    #if ENABLE_LAZY_DEEP_CLONE
    memoCount(1u),
    #endif
    size(o.size),
    tid(libbirch::tid) {
  //
}

inline libbirch::Counted::~Counted() {
  assert(sharedCount.load() == 0u);
}

inline void libbirch::Counted::deallocate() {
  assert(sharedCount.load() == 0u);
  assert(weakCount.load() == 0u);
  libbirch::deallocate(this, size, tid);
}

inline unsigned libbirch::Counted::getSize() const {
  return size;
}

inline void libbirch::Counted::incShared() {
  sharedCount.increment();
}

inline void libbirch::Counted::decShared() {
  assert(sharedCount.load() > 0u);
  if (--sharedCount == 0u && size > 0u) {
    // ^ size == 0u during construction, never destroy in that case
    destroy_();
    decWeak();  // release weak self-reference
  }
}

inline unsigned libbirch::Counted::numShared() const {
  return sharedCount.load();
}

inline void libbirch::Counted::incWeak() {
  weakCount.increment();
}

inline void libbirch::Counted::decWeak() {
  assert(weakCount.load() > 0u);
  if (--weakCount == 0u) {
    assert(sharedCount.load() == 0u);
    #if ENABLE_LAZY_DEEP_CLONE
    decMemo();
    #else
    deallocate();
    #endif
  }
}

inline unsigned libbirch::Counted::numWeak() const {
  return weakCount.load();
}

#if ENABLE_LAZY_DEEP_CLONE
inline void libbirch::Counted::incMemo() {
  memoCount.increment();
}

inline void libbirch::Counted::decMemo() {
  assert(memoCount.load() > 0u);
  if (--memoCount == 0u) {
    assert(sharedCount.load() == 0u);
    assert(weakCount.load() == 0u);
    deallocate();
  }
}

inline unsigned libbirch::Counted::numMemo() const {
  return memoCount.load();
}

inline bool libbirch::Counted::isReachable() const {
  return numWeak() > 0u;
}
#endif
<|endoftext|>


<commit_before>/*
 * libcpu: interface.cpp
 *
 * This is the interface to the client.
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>

#include <memory>

#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/LinkAllPasses.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Verifier.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Transforms/Utils/Cloning.h"

/* project global headers */
#include "libcpu.h"
#include "libcpu_llvm.h"
#include "tag.h"
#include "translate_all.h"
#include "translate_singlestep.h"
#include "translate_singlestep_bb.h"
#include "function.h"
#include "optimize.h"
#include "stat.h"

/* architecture descriptors */
extern arch_func_t arch_func_6502;
extern arch_func_t arch_func_m68k;
extern arch_func_t arch_func_mips;
extern arch_func_t arch_func_m88k;
extern arch_func_t arch_func_arm;
extern arch_func_t arch_func_8086;
extern arch_func_t arch_func_fapra;

#define IS_LITTLE_ENDIAN(cpu) (((cpu)->info.common_flags & CPU_FLAG_ENDIAN_MASK) == CPU_FLAG_ENDIAN_LITTLE)

static inline bool
is_valid_gpr_size(size_t size)
{
	switch (size) {
		case 0: case 1: case 8: case 16: case 32: case 64:
			return true;
		default:
			return false;
	}
}

static inline bool
is_valid_fpr_size(size_t size)
{
	switch (size) {
		case 0: case 32: case 64: case 80: case 128:
			return true;
		default:
			return false;
	}
}

static inline bool
is_valid_vr_size(size_t size)
{
	switch (size) {
		case 0: case 64: case 128:
			return true;
		default:
			return false;
	}
}

//////////////////////////////////////////////////////////////////////
// cpu_t
//////////////////////////////////////////////////////////////////////

cpu_t *
cpu_new(cpu_arch_t arch, uint32_t flags, uint32_t arch_flags)
{
	cpu_t *cpu;

	llvm::InitializeNativeTarget();

	cpu = new cpu_t;
	assert(cpu != NULL);
	memset(&cpu->info, 0, sizeof(cpu->info));
	memset(&cpu->rf, 0, sizeof(cpu->rf));

	cpu->ctx = new LLVMContext();
	cpu->info.type = arch;
	cpu->info.name = "noname";
	cpu->info.common_flags = flags;
	cpu->info.arch_flags = arch_flags;

	switch (arch) {
		case CPU_ARCH_6502:
			cpu->f = arch_func_6502;
			break;
		case CPU_ARCH_M68K:
			cpu->f = arch_func_m68k;
			break;
		case CPU_ARCH_MIPS:
			cpu->f = arch_func_mips;
			break;
		case CPU_ARCH_M88K:
			cpu->f = arch_func_m88k;
			break;
		case CPU_ARCH_ARM:
			cpu->f = arch_func_arm;
			break;
		case CPU_ARCH_8086:
			cpu->f = arch_func_8086;
			break;
		case CPU_ARCH_FAPRA:
			cpu->f = arch_func_fapra;
			break;
		default:
			printf("illegal arch: %d\n", arch);
			exit(1);
	}

	cpu->code_start = 0;
	cpu->code_end = 0;
	cpu->code_entry = 0;
	cpu->tag = NULL;

	uint32_t i;
	for (i = 0; i < sizeof(cpu->func)/sizeof(*cpu->func); i++)
		cpu->func[i] = NULL;
	for (i = 0; i < sizeof(cpu->fp)/sizeof(*cpu->fp); i++)
		cpu->fp[i] = NULL;
	cpu->functions = 0;

	cpu->flags_codegen = CPU_CODEGEN_OPTIMIZE;
	cpu->flags_debug = CPU_DEBUG_NONE;
	cpu->flags_hint = CPU_HINT_NONE;
	cpu->flags = 0;

	// init the frontend
	cpu->f.init(cpu, &cpu->info, &cpu->rf);

	assert(is_valid_gpr_size(cpu->info.register_size[CPU_REG_GPR]) &&
		"the specified GPR size is not guaranteed to work");
	assert(is_valid_fpr_size(cpu->info.register_size[CPU_REG_FPR]) &&
		"the specified FPR size is not guaranteed to work");
	assert(is_valid_vr_size(cpu->info.register_size[CPU_REG_VR]) &&
		"the specified VR size is not guaranteed to work");
	assert(is_valid_gpr_size(cpu->info.register_size[CPU_REG_XR]) &&
		"the specified XR size is not guaranteed to work");

	uint32_t count = cpu->info.register_count[CPU_REG_GPR];
	if (count != 0) {
		cpu->ptr_gpr = (Value **)calloc(count, sizeof(Value *));
		cpu->in_ptr_gpr = (Value **)calloc(count, sizeof(Value *));
	} else {
		cpu->ptr_gpr = NULL;
		cpu->in_ptr_gpr = NULL;
	}

	count = cpu->info.register_count[CPU_REG_XR];
	if (count != 0) {
		cpu->ptr_xr = (Value **)calloc(count, sizeof(Value *));
		cpu->in_ptr_xr = (Value **)calloc(count, sizeof(Value *));
	} else {
		cpu->ptr_xr = NULL;
		cpu->in_ptr_xr = NULL;
	}

	count = cpu->info.register_count[CPU_REG_FPR];
	if (count != 0) {
		cpu->ptr_fpr = (Value **)calloc(count, sizeof(Value *));
		cpu->in_ptr_fpr = (Value **)calloc(count, sizeof(Value *));
	} else {
		cpu->ptr_fpr = NULL;
		cpu->in_ptr_fpr = NULL;
	}

	if (cpu->info.psr_size != 0) {
		cpu->ptr_FLAG = (Value **)calloc(cpu->info.flags_count,
				sizeof(Value*));
		assert(cpu->ptr_FLAG != NULL);
	}

	// init LLVM
	std::unique_ptr<llvm::Module> module_ptr(new Module(cpu->info.name, _CTX()));
	cpu->mod = module_ptr.get();
	assert(cpu->mod != NULL);
	EngineBuilder builder{std::move(module_ptr)};
	builder.setEngineKind(EngineKind::Kind::JIT);
	cpu->exec_engine = builder.create();
	assert(cpu->exec_engine != NULL);

	// check if FP80 and FP128 are supported by this architecture.
	// XXX there is a better way to do this?
	std::string data_layout = cpu->exec_engine->getDataLayout().getStringRepresentation();
	if (data_layout.find("f80") != std::string::npos) {
		LOG("INFO: FP80 supported.\n");
		cpu->flags |= CPU_FLAG_FP80;
	}
	if (data_layout.find("f128") != std::string::npos) {
		LOG("INFO: FP128 supported.\n");
		cpu->flags |= CPU_FLAG_FP128;
	}

	// check if we need to swap guest memory.
	if (cpu->exec_engine->getDataLayout().isLittleEndian()
			^ IS_LITTLE_ENDIAN(cpu))
		cpu->flags |= CPU_FLAG_SWAPMEM;

	cpu->timer_total[TIMER_TAG] = 0;
	cpu->timer_total[TIMER_FE] = 0;
	cpu->timer_total[TIMER_BE] = 0;
	cpu->timer_total[TIMER_RUN] = 0;

	return cpu;
}

void
cpu_free(cpu_t *cpu)
{
	if (cpu->f.done != NULL)
		cpu->f.done(cpu);
	if (cpu->exec_engine != NULL) {
		if (cpu->cur_func != NULL) {
			cpu->cur_func->eraseFromParent();
		}
		delete cpu->exec_engine;
	}
	if (cpu->ctx != NULL)
		delete cpu->ctx;
	if (cpu->ptr_FLAG != NULL)
		free(cpu->ptr_FLAG);
	if (cpu->in_ptr_fpr != NULL)
		free(cpu->in_ptr_fpr);
	if (cpu->ptr_fpr != NULL)
		free(cpu->ptr_fpr);
	if (cpu->in_ptr_xr != NULL)
		free(cpu->in_ptr_xr);
	if (cpu->ptr_xr != NULL)
		free(cpu->ptr_xr);
	if (cpu->in_ptr_gpr != NULL)
		free(cpu->in_ptr_gpr);
	if (cpu->ptr_gpr != NULL)
		free(cpu->ptr_gpr);

	delete cpu;
}

void
cpu_set_ram(cpu_t*cpu, uint8_t *r)
{
	cpu->RAM = r;
}

void
cpu_set_flags_codegen(cpu_t *cpu, uint32_t f)
{
	cpu->flags_codegen = f;
}

void
cpu_set_flags_debug(cpu_t *cpu, uint32_t f)
{
	cpu->flags_debug = f;
}

void
cpu_set_flags_hint(cpu_t *cpu, uint32_t f)
{
	cpu->flags_hint = f;
}

void
cpu_tag(cpu_t *cpu, addr_t pc)
{
	update_timing(cpu, TIMER_TAG, true);
	tag_start(cpu, pc);
	update_timing(cpu, TIMER_TAG, false);
}

static void
cpu_translate_function(cpu_t *cpu)
{
	BasicBlock *bb_ret, *bb_trap, *label_entry, *bb_start;

	/* create function and fill it with std basic blocks */
	cpu->cur_func = cpu_create_function(cpu, "jitmain", &bb_ret, &bb_trap, &label_entry);
	cpu->func[cpu->functions] = cpu->cur_func;

	/* TRANSLATE! */
	update_timing(cpu, TIMER_FE, true);
	if (cpu->flags_debug & CPU_DEBUG_SINGLESTEP) {
		bb_start = cpu_translate_singlestep(cpu, bb_ret, bb_trap);
	} else if (cpu->flags_debug & CPU_DEBUG_SINGLESTEP_BB) {
		bb_start = cpu_translate_singlestep_bb(cpu, bb_ret, bb_trap);
	} else {
		bb_start = cpu_translate_all(cpu, bb_ret, bb_trap);
	}
	update_timing(cpu, TIMER_FE, false);

	/* finish entry basicblock */
	BranchInst::Create(bb_start, label_entry);

	/* make sure everything is OK */
	verifyFunction(*cpu->cur_func, &llvm::errs());

	if (cpu->flags_debug & CPU_DEBUG_PRINT_IR)
		cpu->mod->print(llvm::errs(), nullptr);

	if (cpu->flags_codegen & CPU_CODEGEN_OPTIMIZE) {
		LOG("*** Optimizing...");
		optimize(cpu);
		LOG("done.\n");
		if (cpu->flags_debug & CPU_DEBUG_PRINT_IR_OPTIMIZED)
			cpu->mod->print(llvm::errs(), nullptr);
	}

	LOG("*** Translating...");
	update_timing(cpu, TIMER_BE, true);
	cpu->fp[cpu->functions] = cpu->exec_engine->getPointerToFunction(cpu->cur_func);
	assert(cpu->fp[cpu->functions] != NULL);
	update_timing(cpu, TIMER_BE, false);
	LOG("done.\n");

	cpu->functions++;
}

/* forces ahead of time translation (e.g. for benchmarking the run) */
void
cpu_translate(cpu_t *cpu)
{
	/* on demand translation */
	if (cpu->tags_dirty)
		cpu_translate_function(cpu);

	cpu->tags_dirty = false;
}

typedef int (*fp_t)(uint8_t *RAM, void *grf, void *frf, debug_function_t fp);

#ifdef __GNUC__
void __attribute__((noinline))
breakpoint() {
asm("nop");
}
#else
void breakpoint() {}
#endif

int
cpu_run(cpu_t *cpu, debug_function_t debug_function)
{
	addr_t pc = 0, orig_pc = 0;
	uint32_t i;
	int ret;
	bool success;
	bool do_translate = true;

	/* try to find the entry in all functions */
	while(true) {
		if (do_translate) {
			cpu_translate(cpu);
			pc = cpu->f.get_pc(cpu, cpu->rf.grf);
		}

		orig_pc = pc;
		success = false;
		for (i = 0; i < cpu->functions; i++) {
			fp_t FP = (fp_t)cpu->fp[i];
			update_timing(cpu, TIMER_RUN, true);
			breakpoint();
			ret = FP(cpu->RAM, cpu->rf.grf, cpu->rf.frf, debug_function);
			update_timing(cpu, TIMER_RUN, false);
			pc = cpu->f.get_pc(cpu, cpu->rf.grf);
			if (ret != JIT_RETURN_FUNCNOTFOUND)
				return ret;
			if (!is_inside_code_area(cpu, pc))
				return ret;
			if (pc != orig_pc) {
				success = true;
				break;
			}
		}
		if (!success) {
			LOG("{%" PRIx64 "}", pc);
			cpu_tag(cpu, pc);
			do_translate = true;
		}
	}
}
//printf("%d\n", __LINE__);

void
cpu_flush(cpu_t *cpu)
{
	cpu->cur_func->eraseFromParent();

	cpu->functions = 0;

	// reset bb caching mapping
	cpu->func_bb.clear();

//	delete cpu->mod;
//	cpu->mod = NULL;
}

void
cpu_print_statistics(cpu_t *cpu)
{
	printf("tag = %8" PRId64 "\n", cpu->timer_total[TIMER_TAG]);
	printf("fe  = %8" PRId64 "\n", cpu->timer_total[TIMER_FE]);
	printf("be  = %8" PRId64 "\n", cpu->timer_total[TIMER_BE]);
	printf("run = %8" PRId64 "\n", cpu->timer_total[TIMER_RUN]);
}
//printf("%s:%d\n", __func__, __LINE__);
<commit_msg>llvm: Initialize assembly printer<commit_after>/*
 * libcpu: interface.cpp
 *
 * This is the interface to the client.
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>

#include <memory>

#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/LinkAllPasses.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Verifier.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Transforms/Utils/Cloning.h"

/* project global headers */
#include "libcpu.h"
#include "libcpu_llvm.h"
#include "tag.h"
#include "translate_all.h"
#include "translate_singlestep.h"
#include "translate_singlestep_bb.h"
#include "function.h"
#include "optimize.h"
#include "stat.h"

/* architecture descriptors */
extern arch_func_t arch_func_6502;
extern arch_func_t arch_func_m68k;
extern arch_func_t arch_func_mips;
extern arch_func_t arch_func_m88k;
extern arch_func_t arch_func_arm;
extern arch_func_t arch_func_8086;
extern arch_func_t arch_func_fapra;

#define IS_LITTLE_ENDIAN(cpu) (((cpu)->info.common_flags & CPU_FLAG_ENDIAN_MASK) == CPU_FLAG_ENDIAN_LITTLE)

static inline bool
is_valid_gpr_size(size_t size)
{
	switch (size) {
		case 0: case 1: case 8: case 16: case 32: case 64:
			return true;
		default:
			return false;
	}
}

static inline bool
is_valid_fpr_size(size_t size)
{
	switch (size) {
		case 0: case 32: case 64: case 80: case 128:
			return true;
		default:
			return false;
	}
}

static inline bool
is_valid_vr_size(size_t size)
{
	switch (size) {
		case 0: case 64: case 128:
			return true;
		default:
			return false;
	}
}

//////////////////////////////////////////////////////////////////////
// cpu_t
//////////////////////////////////////////////////////////////////////

cpu_t *
cpu_new(cpu_arch_t arch, uint32_t flags, uint32_t arch_flags)
{
	cpu_t *cpu;

	llvm::InitializeNativeTarget();
	llvm::InitializeNativeTargetAsmPrinter();

	cpu = new cpu_t;
	assert(cpu != NULL);
	memset(&cpu->info, 0, sizeof(cpu->info));
	memset(&cpu->rf, 0, sizeof(cpu->rf));

	cpu->ctx = new LLVMContext();
	cpu->info.type = arch;
	cpu->info.name = "noname";
	cpu->info.common_flags = flags;
	cpu->info.arch_flags = arch_flags;

	switch (arch) {
		case CPU_ARCH_6502:
			cpu->f = arch_func_6502;
			break;
		case CPU_ARCH_M68K:
			cpu->f = arch_func_m68k;
			break;
		case CPU_ARCH_MIPS:
			cpu->f = arch_func_mips;
			break;
		case CPU_ARCH_M88K:
			cpu->f = arch_func_m88k;
			break;
		case CPU_ARCH_ARM:
			cpu->f = arch_func_arm;
			break;
		case CPU_ARCH_8086:
			cpu->f = arch_func_8086;
			break;
		case CPU_ARCH_FAPRA:
			cpu->f = arch_func_fapra;
			break;
		default:
			printf("illegal arch: %d\n", arch);
			exit(1);
	}

	cpu->code_start = 0;
	cpu->code_end = 0;
	cpu->code_entry = 0;
	cpu->tag = NULL;

	uint32_t i;
	for (i = 0; i < sizeof(cpu->func)/sizeof(*cpu->func); i++)
		cpu->func[i] = NULL;
	for (i = 0; i < sizeof(cpu->fp)/sizeof(*cpu->fp); i++)
		cpu->fp[i] = NULL;
	cpu->functions = 0;

	cpu->flags_codegen = CPU_CODEGEN_OPTIMIZE;
	cpu->flags_debug = CPU_DEBUG_NONE;
	cpu->flags_hint = CPU_HINT_NONE;
	cpu->flags = 0;

	// init the frontend
	cpu->f.init(cpu, &cpu->info, &cpu->rf);

	assert(is_valid_gpr_size(cpu->info.register_size[CPU_REG_GPR]) &&
		"the specified GPR size is not guaranteed to work");
	assert(is_valid_fpr_size(cpu->info.register_size[CPU_REG_FPR]) &&
		"the specified FPR size is not guaranteed to work");
	assert(is_valid_vr_size(cpu->info.register_size[CPU_REG_VR]) &&
		"the specified VR size is not guaranteed to work");
	assert(is_valid_gpr_size(cpu->info.register_size[CPU_REG_XR]) &&
		"the specified XR size is not guaranteed to work");

	uint32_t count = cpu->info.register_count[CPU_REG_GPR];
	if (count != 0) {
		cpu->ptr_gpr = (Value **)calloc(count, sizeof(Value *));
		cpu->in_ptr_gpr = (Value **)calloc(count, sizeof(Value *));
	} else {
		cpu->ptr_gpr = NULL;
		cpu->in_ptr_gpr = NULL;
	}

	count = cpu->info.register_count[CPU_REG_XR];
	if (count != 0) {
		cpu->ptr_xr = (Value **)calloc(count, sizeof(Value *));
		cpu->in_ptr_xr = (Value **)calloc(count, sizeof(Value *));
	} else {
		cpu->ptr_xr = NULL;
		cpu->in_ptr_xr = NULL;
	}

	count = cpu->info.register_count[CPU_REG_FPR];
	if (count != 0) {
		cpu->ptr_fpr = (Value **)calloc(count, sizeof(Value *));
		cpu->in_ptr_fpr = (Value **)calloc(count, sizeof(Value *));
	} else {
		cpu->ptr_fpr = NULL;
		cpu->in_ptr_fpr = NULL;
	}

	if (cpu->info.psr_size != 0) {
		cpu->ptr_FLAG = (Value **)calloc(cpu->info.flags_count,
				sizeof(Value*));
		assert(cpu->ptr_FLAG != NULL);
	}

	// init LLVM
	std::unique_ptr<llvm::Module> module_ptr(new Module(cpu->info.name, _CTX()));
	cpu->mod = module_ptr.get();
	assert(cpu->mod != NULL);
	EngineBuilder builder{std::move(module_ptr)};
	builder.setEngineKind(EngineKind::Kind::JIT);
	cpu->exec_engine = builder.create();
	assert(cpu->exec_engine != NULL);

	// check if FP80 and FP128 are supported by this architecture.
	// XXX there is a better way to do this?
	std::string data_layout = cpu->exec_engine->getDataLayout().getStringRepresentation();
	if (data_layout.find("f80") != std::string::npos) {
		LOG("INFO: FP80 supported.\n");
		cpu->flags |= CPU_FLAG_FP80;
	}
	if (data_layout.find("f128") != std::string::npos) {
		LOG("INFO: FP128 supported.\n");
		cpu->flags |= CPU_FLAG_FP128;
	}

	// check if we need to swap guest memory.
	if (cpu->exec_engine->getDataLayout().isLittleEndian()
			^ IS_LITTLE_ENDIAN(cpu))
		cpu->flags |= CPU_FLAG_SWAPMEM;

	cpu->timer_total[TIMER_TAG] = 0;
	cpu->timer_total[TIMER_FE] = 0;
	cpu->timer_total[TIMER_BE] = 0;
	cpu->timer_total[TIMER_RUN] = 0;

	return cpu;
}

void
cpu_free(cpu_t *cpu)
{
	if (cpu->f.done != NULL)
		cpu->f.done(cpu);
	if (cpu->exec_engine != NULL) {
		if (cpu->cur_func != NULL) {
			cpu->cur_func->eraseFromParent();
		}
		delete cpu->exec_engine;
	}
	if (cpu->ctx != NULL)
		delete cpu->ctx;
	if (cpu->ptr_FLAG != NULL)
		free(cpu->ptr_FLAG);
	if (cpu->in_ptr_fpr != NULL)
		free(cpu->in_ptr_fpr);
	if (cpu->ptr_fpr != NULL)
		free(cpu->ptr_fpr);
	if (cpu->in_ptr_xr != NULL)
		free(cpu->in_ptr_xr);
	if (cpu->ptr_xr != NULL)
		free(cpu->ptr_xr);
	if (cpu->in_ptr_gpr != NULL)
		free(cpu->in_ptr_gpr);
	if (cpu->ptr_gpr != NULL)
		free(cpu->ptr_gpr);

	delete cpu;
}

void
cpu_set_ram(cpu_t*cpu, uint8_t *r)
{
	cpu->RAM = r;
}

void
cpu_set_flags_codegen(cpu_t *cpu, uint32_t f)
{
	cpu->flags_codegen = f;
}

void
cpu_set_flags_debug(cpu_t *cpu, uint32_t f)
{
	cpu->flags_debug = f;
}

void
cpu_set_flags_hint(cpu_t *cpu, uint32_t f)
{
	cpu->flags_hint = f;
}

void
cpu_tag(cpu_t *cpu, addr_t pc)
{
	update_timing(cpu, TIMER_TAG, true);
	tag_start(cpu, pc);
	update_timing(cpu, TIMER_TAG, false);
}

static void
cpu_translate_function(cpu_t *cpu)
{
	BasicBlock *bb_ret, *bb_trap, *label_entry, *bb_start;

	/* create function and fill it with std basic blocks */
	cpu->cur_func = cpu_create_function(cpu, "jitmain", &bb_ret, &bb_trap, &label_entry);
	cpu->func[cpu->functions] = cpu->cur_func;

	/* TRANSLATE! */
	update_timing(cpu, TIMER_FE, true);
	if (cpu->flags_debug & CPU_DEBUG_SINGLESTEP) {
		bb_start = cpu_translate_singlestep(cpu, bb_ret, bb_trap);
	} else if (cpu->flags_debug & CPU_DEBUG_SINGLESTEP_BB) {
		bb_start = cpu_translate_singlestep_bb(cpu, bb_ret, bb_trap);
	} else {
		bb_start = cpu_translate_all(cpu, bb_ret, bb_trap);
	}
	update_timing(cpu, TIMER_FE, false);

	/* finish entry basicblock */
	BranchInst::Create(bb_start, label_entry);

	/* make sure everything is OK */
	verifyFunction(*cpu->cur_func, &llvm::errs());

	if (cpu->flags_debug & CPU_DEBUG_PRINT_IR)
		cpu->mod->print(llvm::errs(), nullptr);

	if (cpu->flags_codegen & CPU_CODEGEN_OPTIMIZE) {
		LOG("*** Optimizing...");
		optimize(cpu);
		LOG("done.\n");
		if (cpu->flags_debug & CPU_DEBUG_PRINT_IR_OPTIMIZED)
			cpu->mod->print(llvm::errs(), nullptr);
	}

	LOG("*** Translating...");
	update_timing(cpu, TIMER_BE, true);
	cpu->fp[cpu->functions] = cpu->exec_engine->getPointerToFunction(cpu->cur_func);
	assert(cpu->fp[cpu->functions] != NULL);
	update_timing(cpu, TIMER_BE, false);
	LOG("done.\n");

	cpu->functions++;
}

/* forces ahead of time translation (e.g. for benchmarking the run) */
void
cpu_translate(cpu_t *cpu)
{
	/* on demand translation */
	if (cpu->tags_dirty)
		cpu_translate_function(cpu);

	cpu->tags_dirty = false;
}

typedef int (*fp_t)(uint8_t *RAM, void *grf, void *frf, debug_function_t fp);

#ifdef __GNUC__
void __attribute__((noinline))
breakpoint() {
asm("nop");
}
#else
void breakpoint() {}
#endif

int
cpu_run(cpu_t *cpu, debug_function_t debug_function)
{
	addr_t pc = 0, orig_pc = 0;
	uint32_t i;
	int ret;
	bool success;
	bool do_translate = true;

	/* try to find the entry in all functions */
	while(true) {
		if (do_translate) {
			cpu_translate(cpu);
			pc = cpu->f.get_pc(cpu, cpu->rf.grf);
		}

		orig_pc = pc;
		success = false;
		for (i = 0; i < cpu->functions; i++) {
			fp_t FP = (fp_t)cpu->fp[i];
			update_timing(cpu, TIMER_RUN, true);
			breakpoint();
			ret = FP(cpu->RAM, cpu->rf.grf, cpu->rf.frf, debug_function);
			update_timing(cpu, TIMER_RUN, false);
			pc = cpu->f.get_pc(cpu, cpu->rf.grf);
			if (ret != JIT_RETURN_FUNCNOTFOUND)
				return ret;
			if (!is_inside_code_area(cpu, pc))
				return ret;
			if (pc != orig_pc) {
				success = true;
				break;
			}
		}
		if (!success) {
			LOG("{%" PRIx64 "}", pc);
			cpu_tag(cpu, pc);
			do_translate = true;
		}
	}
}
//printf("%d\n", __LINE__);

void
cpu_flush(cpu_t *cpu)
{
	cpu->cur_func->eraseFromParent();

	cpu->functions = 0;

	// reset bb caching mapping
	cpu->func_bb.clear();

//	delete cpu->mod;
//	cpu->mod = NULL;
}

void
cpu_print_statistics(cpu_t *cpu)
{
	printf("tag = %8" PRId64 "\n", cpu->timer_total[TIMER_TAG]);
	printf("fe  = %8" PRId64 "\n", cpu->timer_total[TIMER_FE]);
	printf("be  = %8" PRId64 "\n", cpu->timer_total[TIMER_BE]);
	printf("run = %8" PRId64 "\n", cpu->timer_total[TIMER_RUN]);
}
//printf("%s:%d\n", __func__, __LINE__);
<|endoftext|>