<commit_before>#include <QFile>

#include "quagzipfile.h"

class QuaGzipFilePrivate {
    friend class QuaGzipFile;
    QString fileName;
    gzFile gzd;
    inline QuaGzipFilePrivate(): gzd(NULL) {}
    inline QuaGzipFilePrivate(const QString &fileName):
        fileName(fileName), gzd(NULL) {}
    template<typename FileId> bool open(FileId id,
        QIODevice::OpenMode mode, QString &error);
    template<typename FileId> gzFile open(FileId id,
        const char *modeString);
};

template<> // const QString& doesn't work in MSVS 2008 for some reason
gzFile QuaGzipFilePrivate::open(QString id, const char *modeString)
{
    return gzopen(QFile::encodeName(id).constData(), modeString);
}

template<>
gzFile QuaGzipFilePrivate::open(int id, const char *modeString)
{
    return gzdopen(id, modeString);
}

template<typename FileId>
bool QuaGzipFilePrivate::open(FileId id, QIODevice::OpenMode mode,
                              QString &error)
{
    char modeString[2];
    modeString[0] = modeString[1] = '\0';
    if ((mode & QIODevice::ReadOnly) != 0
            && (mode & QIODevice::WriteOnly) != 0) {
        error = QuaGzipFile::trUtf8("Opening gzip for both reading"
            " and writing is not supported");
        return false;
    } else if ((mode & QIODevice::ReadOnly) != 0) {
        modeString[0] = 'r';
    } else if ((mode & QIODevice::WriteOnly) != 0) {
        modeString[0] = 'w';
    } else {
        error = QuaGzipFile::trUtf8("You can open a gzip either for reading"
            " or for writing. Which is it?");
        return false;
    }
    gzd = open(id, modeString);
    if (gzd == NULL) {
        error = QuaGzipFile::trUtf8("Could not gzopen() file");
        return false;
    }
    return true;
}

QuaGzipFile::QuaGzipFile():
d(new QuaGzipFilePrivate())
{
}

QuaGzipFile::QuaGzipFile(QObject *parent):
QIODevice(parent),
d(new QuaGzipFilePrivate())
{
}

QuaGzipFile::QuaGzipFile(const QString &fileName, QObject *parent):
  QIODevice(parent),
d(new QuaGzipFilePrivate(fileName))
{
}

QuaGzipFile::~QuaGzipFile()
{
  if (isOpen()) {
    close();
  }
  delete d;
}

void QuaGzipFile::setFileName(const QString& fileName)
{
    d->fileName = fileName;
}

QString QuaGzipFile::getFileName() const
{
    return d->fileName;
}

bool QuaGzipFile::isSequential() const
{
  return true;
}

bool QuaGzipFile::open(QIODevice::OpenMode mode)
{
    QString error;
    if (!d->open(d->fileName, mode, error)) {
        setErrorString(error);
        return false;
    }
    return QIODevice::open(mode);
}

bool QuaGzipFile::open(int fd, QIODevice::OpenMode mode)
{
    QString error;
    if (!d->open(fd, mode, error)) {
        setErrorString(error);
        return false;
    }
    return QIODevice::open(mode);
}

bool QuaGzipFile::flush()
{
    return gzflush(d->gzd, Z_SYNC_FLUSH) == Z_OK;
}

void QuaGzipFile::close()
{
  QIODevice::close();
  gzclose(d->gzd);
}

qint64 QuaGzipFile::readData(char *data, qint64 maxSize)
{
    return gzread(d->gzd, (voidp)data, (unsigned)maxSize);
}

qint64 QuaGzipFile::writeData(const char *data, qint64 maxSize)
{
    if (maxSize == 0)
        return 0;
    int written = gzwrite(d->gzd, (voidp)data, (unsigned)maxSize);
    if (written == 0)
        return -1;
    else
        return written;
}
<commit_msg>Removed unnecessary templates<commit_after>#include <QFile>

#include "quagzipfile.h"

class QuaGzipFilePrivate {
    friend class QuaGzipFile;
    QString fileName;
    gzFile gzd;
    inline QuaGzipFilePrivate(): gzd(NULL) {}
    inline QuaGzipFilePrivate(const QString &fileName):
        fileName(fileName), gzd(NULL) {}
    template<typename FileId> bool open(FileId id,
        QIODevice::OpenMode mode, QString &error);
    gzFile open(int fd, const char *modeString);
    gzFile open(const QString &name, const char *modeString);
};

gzFile QuaGzipFilePrivate::open(const QString &name, const char *modeString)
{
    return gzopen(QFile::encodeName(name).constData(), modeString);
}

gzFile QuaGzipFilePrivate::open(int fd, const char *modeString)
{
    return gzdopen(fd, modeString);
}

template<typename FileId>
bool QuaGzipFilePrivate::open(FileId id, QIODevice::OpenMode mode,
                              QString &error)
{
    char modeString[2];
    modeString[0] = modeString[1] = '\0';
    if ((mode & QIODevice::ReadOnly) != 0
            && (mode & QIODevice::WriteOnly) != 0) {
        error = QuaGzipFile::trUtf8("Opening gzip for both reading"
            " and writing is not supported");
        return false;
    } else if ((mode & QIODevice::ReadOnly) != 0) {
        modeString[0] = 'r';
    } else if ((mode & QIODevice::WriteOnly) != 0) {
        modeString[0] = 'w';
    } else {
        error = QuaGzipFile::trUtf8("You can open a gzip either for reading"
            " or for writing. Which is it?");
        return false;
    }
    gzd = open(id, modeString);
    if (gzd == NULL) {
        error = QuaGzipFile::trUtf8("Could not gzopen() file");
        return false;
    }
    return true;
}

QuaGzipFile::QuaGzipFile():
d(new QuaGzipFilePrivate())
{
}

QuaGzipFile::QuaGzipFile(QObject *parent):
QIODevice(parent),
d(new QuaGzipFilePrivate())
{
}

QuaGzipFile::QuaGzipFile(const QString &fileName, QObject *parent):
  QIODevice(parent),
d(new QuaGzipFilePrivate(fileName))
{
}

QuaGzipFile::~QuaGzipFile()
{
  if (isOpen()) {
    close();
  }
  delete d;
}

void QuaGzipFile::setFileName(const QString& fileName)
{
    d->fileName = fileName;
}

QString QuaGzipFile::getFileName() const
{
    return d->fileName;
}

bool QuaGzipFile::isSequential() const
{
  return true;
}

bool QuaGzipFile::open(QIODevice::OpenMode mode)
{
    QString error;
    if (!d->open(d->fileName, mode, error)) {
        setErrorString(error);
        return false;
    }
    return QIODevice::open(mode);
}

bool QuaGzipFile::open(int fd, QIODevice::OpenMode mode)
{
    QString error;
    if (!d->open(fd, mode, error)) {
        setErrorString(error);
        return false;
    }
    return QIODevice::open(mode);
}

bool QuaGzipFile::flush()
{
    return gzflush(d->gzd, Z_SYNC_FLUSH) == Z_OK;
}

void QuaGzipFile::close()
{
  QIODevice::close();
  gzclose(d->gzd);
}

qint64 QuaGzipFile::readData(char *data, qint64 maxSize)
{
    return gzread(d->gzd, (voidp)data, (unsigned)maxSize);
}

qint64 QuaGzipFile::writeData(const char *data, qint64 maxSize)
{
    if (maxSize == 0)
        return 0;
    int written = gzwrite(d->gzd, (voidp)data, (unsigned)maxSize);
    if (written == 0)
        return -1;
    else
        return written;
}
<|endoftext|>


<commit_before>#include <stdlib.h>
#include <algorithm>
#include <iostream>
#include <vector>
#include <unistd.h>
#include <dirent.h>
#include <fstream>
#include <sstream>
#include <queue>
#include "omp.h"

// Contains the various options the user can pass ptgz.
struct Settings {
	Settings(): extract(),
				compress(),
   				verbose(),
				output() {}
	bool extract;
	bool compress;
	bool verbose;
	bool output;
	std::string name;
};

// Checks if the user asks for help.
// Provides usage information to the user.
// Parameters: argc (int) number of cli arguments.
// 			   argv (char *[]) user provided arguments.
void helpCheck(int argc, char *argv[]) {
	if (argc == 1) {
		std::cout << "ERROR: ptgz was passed no parameters. \"ptgz -h\" for help." << std::endl;
		exit(0);
	}

	if (argv[1] == std::string("-h") || argv[1] == std::string("--help")) {
		std::cout << "\nptgz - Parallel Tar GZ by Ryan Chui (2017)\n" << std::endl;
		exit(0);
	}
}

// Gets the parameters passed by the user and stores them.
// Parameters: argc (int) number of cli arguments.
// 			   argv (char *[]) user provided arguments.
// 			   instance (Settings *) user argument storage.
void getSettings(int argc, char *argv[], Settings *instance) {
	// Get all passed arguments
	std::queue<std::string> settings;
	for (int i = 1; i < argc; ++i) {
		settings.push(argv[i]);
	}

	// Continue to check until there are no more passed arguments.
	while (!settings.empty()) {
		std::string arg = settings.front();

		if (arg == "-x") {
			if ((*instance).compress) {
				std::cout << "ERROR: ptgz cannot both compress and extract. \"ptgz -h\" for help." << std::endl;
				exit(0);
			}
			(*instance).extract = true;
		} else if (arg == "-c") {
			if ((*instance).extract) {
				std::cout << "ERROR: ptgz cannot both compress and extract. \"ptgz -h\" for help." << std::endl;
				exit(0);
			}
			(*instance).compress = true;
		} else if (arg == "-v"){
			(*instance).verbose = true;
		} else if (arg == "-o") {
			(*instance).output = true;
		} else {
			if (settings.size() > 1) {
				std::cout << "ERROR: ptgz was called incorrectly. \"ptgz -h\" for help." << std::endl;
				exit(0);
			}
			(*instance).output = true;
			(*instance).name = arg;
		}

		settings.pop();
	}

	if (!(*instance).output) {
		std::cout << "ERROR: No output file name given. \"ptgz -h\" for help." << std::endl;
		exit(0);
	}
}

// Finds the number of files in the space to store.
// Parameters: numFiles (int *) number of files.
// 			   cwd (const char *) current working directory.
void findAll(int *numFiles, const char *cwd) {
	DIR *dir;
	struct dirent *ent;

	// Check if cwd is a directory
	if ((dir = opendir(cwd)) != NULL) {
		// Get all file paths within directory.
		while ((ent = readdir (dir)) != NULL) {
			std::string fileBuff = std::string(ent -> d_name);
			if (fileBuff != "." && fileBuff != "..") {
				DIR *dir2;
				std::string filePath = std::string(cwd) + "/" + fileBuff;
				// Check if file path is a directory.
				if ((dir2 = opendir(filePath.c_str())) != NULL) {
					closedir(dir2);
					findAll(numFiles, filePath.c_str());
				} else {
					*numFiles += 1;
				}
			}
		}
		closedir(dir);
	}
}

// Gets the paths for all files in the space to store.
// Parameters: filePaths (std::vector<std::string> *) holder for all file paths.
// 			   cwd (const char *) current working directory.
// 			   rootPath (std::string) path from the root of the directory to be stored.
void getPaths(std::vector<std::string> *filePaths, const char *cwd, std::string rootPath) {
	DIR *dir;
	struct dirent *ent;

	// Check if cwd is a directory
	if ((dir = opendir(cwd)) != NULL) {
		// Get all file paths within directory.
		while ((ent = readdir (dir)) != NULL) {
			std::string fileBuff = std::string(ent -> d_name);
			if (fileBuff != "." && fileBuff != "..") {
				DIR *dir2;
				std::string filePath = std::string(cwd) + "/" + fileBuff;
				// Check if file path is a directory.
				if ((dir2 = opendir(filePath.c_str())) != NULL) {
					closedir(dir2);
					getPaths(filePaths, filePath.c_str(), rootPath + fileBuff + "/");
				} else {
					filePaths->push_back(rootPath + fileBuff);
				}
			}
		}
		closedir(dir);
	}
}

// Divides files into blocks.
// Compresses each block into a single file.
// Combines all compressed blocks into a single file.
// Removes temporary blocks and header files.
// Parameters: filePaths (std::vector<std::string> *) holder for all file paths.
// 			   name (std::string) user given name for storage file.
// 			   verbose (bool) user option for verbose output.
void compression(std::vector<std::string> *filePaths, std::string name, bool verbose) {
	std::random_shuffle(filePaths->begin(), filePaths->end());
	unsigned long long int filePathSize = filePaths->size();
	unsigned long long int blockSize = (filePathSize / (omp_get_max_threads() * 10)) + 1;
	std::vector<std::string> *tarNames = new std::vector<std::string>(filePathSize / blockSize + 1);

	// Gzips the blocks of files into a single compressed file
	#pragma omp parallel for schedule(dynamic)
	for (int i = 0; i < omp_get_max_threads() * 10; ++i) {
		unsigned long long int start = blockSize * i;
		if (start < filePathSize) {
			// Store the name of each file for a block owned by each thread.
			// Each thread will use the file to tar and gzip compress their block.
			std::ofstream tmp;
			tmp.open(std::to_string(i) + "." + name + ".ptgz.tmp", std::ios_base::app);
			std::string gzCommand = "GZIP=-1 tar -cz -T " + std::to_string(i) + "." + name + ".ptgz.tmp -f " + std::to_string(i) + "." + name + ".tar.gz";
			for (unsigned long long int j = start; j < std::min(start + blockSize, filePathSize); ++j) {
				tmp << filePaths->at(j) + "\n";
			}

			if (verbose) {
				std::cout << gzCommand + "\n";
			}

			tmp.close();
			system(gzCommand.c_str());
			tarNames->at(i) = std::to_string(i) + "." + name + ".tar.gz";
		}
	}

	// Combines gzipped blocks together into a single tarball.
	// Write tarball names into an idx file for extraction.
	std::ofstream idx, tmp;
	idx.open(name + ".ptgz.idx", std::ios_base::app);
	std::string tarCommand = "tar -c -T " + name + ".ptgz.idx -f " + name + ".ptgz.tar";
	for (unsigned long long int i = 0; i < tarNames->size(); ++i) {
		idx << tarNames->at(i) + "\n";
	}
	idx << name + ".ptgz.idx" + "\n";
	idx.close();

	if (verbose) {
		std::cout << tarCommand + "\n";
	}

	system(tarCommand.c_str());

	// Removes all temporary blocks and idx file.
	#pragma omp parallel for schedule(static)
	for (unsigned long long int i = 0; i < tarNames->size(); ++i) {
		std::string rmCommand = tarNames->at(i);
		if (verbose) {
			std::cout << "remove(" + rmCommand + ")\n";
		}
		if (remove(rmCommand.c_str())) {
			std::cout << "ERROR: " + rmCommand + " could not be removed.\n";
		}

		rmCommand = std::to_string(i) + "." + name + ".ptgz.tmp";
		if (verbose) {
			std::cout << "remove(" + rmCommand + ")\n";
		}
		if (remove(rmCommand.c_str())) {
			std::cout << "ERROR: " + rmCommand + " could not be removed.\n";
		}
	}

	std::string rmCommand;
	if (verbose) {
		std::cout << "remove(" + name + ".ptgz.idx)\n";
	}
	rmCommand = name + ".ptgz.idx";
	if (remove(rmCommand.c_str())) {
		std::cout << "ERROR: " + rmCommand + " could not be removed.\n";
	}

	tarNames->clear();
	delete(tarNames);
}

void extraction(std::vector<std::string> *filePaths, std::string name, bool verbose) {
	// Unpack the 1st layer tarball
	std::string exCommand = "tar xf " + name;
	if (verbose) {
		std::cout << exCommand + "\n";
	}
	// system(exCommand.c_str());

	// Get the name from the name of the 1st layer tarball
	for (int i = 0; i < 9; ++i) {
		name.pop_back();
	}

	std::ifstream idx;
	std::string line;
	idx.open(name + ".ptgz.idx", std::ios_base::in);
	while (std::getline(idx, line)) {
		filePaths->push_back(line);
	}
	idx.close();
	filePaths->pop_back();

	for (int i = 0; i < filePaths->size(); ++i) {
		std::cout << filePaths->at(i) << std::endl;
	}
}

char cwd [PATH_MAX];

// Checks to see if the user asks for help.
// Gathers the user provided settings for ptgz.
// Finds the number of files that need to be stored.
// Gathers the file paths of all files to be stored.
// Either compresses the files or extracts the ptgz.tar archive.
int main(int argc, char *argv[]) {
	Settings *instance = new Settings;
	int *numFiles = new int(0);
	std::vector<std::string> *filePaths = new std::vector<std::string>();

	helpCheck(argc, argv);
	getSettings(argc, argv, instance);
	getcwd(cwd, PATH_MAX);

	if ((*instance).compress) {
		findAll(numFiles, cwd);
		getPaths(filePaths, cwd, "");
		compression(filePaths, (*instance).name, (*instance).verbose);
	} else {
		extraction(filePaths, (*instance).name, (*instance).verbose);
	}

	delete(instance);
	delete(numFiles);
	filePaths->clear();
	delete(filePaths);
	return 0;
}
<commit_msg>Added keep option to keep ptgz.tar archive. Added keep error if used without extract. Added tar.gz deletion after extraction. Added tar.gz unpacking.<commit_after>#include <stdlib.h>
#include <algorithm>
#include <iostream>
#include <vector>
#include <unistd.h>
#include <dirent.h>
#include <fstream>
#include <sstream>
#include <queue>
#include "omp.h"

// Contains the various options the user can pass ptgz.
struct Settings {
	Settings(): extract(),
				compress(),
   				verbose(),
				keep(),
				output() {}
	bool extract;
	bool compress;
	bool verbose;
	bool keep;
	bool output;
	std::string name;
};

// Checks if the user asks for help.
// Provides usage information to the user.
// Parameters: argc (int) number of cli arguments.
// 			   argv (char *[]) user provided arguments.
void helpCheck(int argc, char *argv[]) {
	if (argc == 1) {
		std::cout << "ERROR: ptgz was passed no parameters. \"ptgz -h\" for help." << std::endl;
		exit(0);
	}

	if (argv[1] == std::string("-h") || argv[1] == std::string("--help")) {
		std::cout << "\nptgz - Parallel Tar GZ by Ryan Chui (2017)\n" << std::endl;
		exit(0);
	}
}

// Gets the parameters passed by the user and stores them.
// Parameters: argc (int) number of cli arguments.
// 			   argv (char *[]) user provided arguments.
// 			   instance (Settings *) user argument storage.
void getSettings(int argc, char *argv[], Settings *instance) {
	// Get all passed arguments
	std::queue<std::string> settings;
	for (int i = 1; i < argc; ++i) {
		settings.push(argv[i]);
	}

	// Continue to check until there are no more passed arguments.
	while (!settings.empty()) {
		std::string arg = settings.front();

		if (arg == "-x") {
			if ((*instance).compress) {
				std::cout << "ERROR: ptgz cannot both compress and extract. \"ptgz -h\" for help." << std::endl;
				exit(0);
			}
			(*instance).extract = true;
		} else if (arg == "-c") {
			if ((*instance).extract) {
				std::cout << "ERROR: ptgz cannot both compress and extract. \"ptgz -h\" for help." << std::endl;
				exit(0);
			}
			(*instance).compress = true;
		} else if (arg == "-v"){
			(*instance).verbose = true;
		} else if (arg == "-o") {
			(*instance).output = true;
		} else if (arg == "-k") {
			(*instance).keep = true;
		} else {
			if (settings.size() > 1) {
				std::cout << "ERROR: ptgz was called incorrectly. \"ptgz -h\" for help." << std::endl;
				exit(0);
			}
			(*instance).output = true;
			(*instance).name = arg;
		}

		settings.pop();
	}

	if (!(*instance).output) {
		std::cout << "ERROR: No output file name given. \"ptgz -h\" for help." << std::endl;
		exit(0);
	} else if (((*instance).keep && !(*instance).extract) {
		std::cout << "ERROR: Can't use keep option without extract. \"ptgz -h\" for help." << std::endl;
	}
}

// Finds the number of files in the space to store.
// Parameters: numFiles (int *) number of files.
// 			   cwd (const char *) current working directory.
void findAll(int *numFiles, const char *cwd) {
	DIR *dir;
	struct dirent *ent;

	// Check if cwd is a directory
	if ((dir = opendir(cwd)) != NULL) {
		// Get all file paths within directory.
		while ((ent = readdir (dir)) != NULL) {
			std::string fileBuff = std::string(ent -> d_name);
			if (fileBuff != "." && fileBuff != "..") {
				DIR *dir2;
				std::string filePath = std::string(cwd) + "/" + fileBuff;
				// Check if file path is a directory.
				if ((dir2 = opendir(filePath.c_str())) != NULL) {
					closedir(dir2);
					findAll(numFiles, filePath.c_str());
				} else {
					*numFiles += 1;
				}
			}
		}
		closedir(dir);
	}
}

// Gets the paths for all files in the space to store.
// Parameters: filePaths (std::vector<std::string> *) holder for all file paths.
// 			   cwd (const char *) current working directory.
// 			   rootPath (std::string) path from the root of the directory to be stored.
void getPaths(std::vector<std::string> *filePaths, const char *cwd, std::string rootPath) {
	DIR *dir;
	struct dirent *ent;

	// Check if cwd is a directory
	if ((dir = opendir(cwd)) != NULL) {
		// Get all file paths within directory.
		while ((ent = readdir (dir)) != NULL) {
			std::string fileBuff = std::string(ent -> d_name);
			if (fileBuff != "." && fileBuff != "..") {
				DIR *dir2;
				std::string filePath = std::string(cwd) + "/" + fileBuff;
				// Check if file path is a directory.
				if ((dir2 = opendir(filePath.c_str())) != NULL) {
					closedir(dir2);
					getPaths(filePaths, filePath.c_str(), rootPath + fileBuff + "/");
				} else {
					filePaths->push_back(rootPath + fileBuff);
				}
			}
		}
		closedir(dir);
	}
}

// Divides files into blocks.
// Compresses each block into a single file.
// Combines all compressed blocks into a single file.
// Removes temporary blocks and header files.
// Parameters: filePaths (std::vector<std::string> *) holder for all file paths.
// 			   name (std::string) user given name for storage file.
// 			   verbose (bool) user option for verbose output.
void compression(std::vector<std::string> *filePaths, std::string name, bool verbose) {
	std::random_shuffle(filePaths->begin(), filePaths->end());
	unsigned long long int filePathSize = filePaths->size();
	unsigned long long int blockSize = (filePathSize / (omp_get_max_threads() * 10)) + 1;
	std::vector<std::string> *tarNames = new std::vector<std::string>(filePathSize / blockSize + 1);

	// Gzips the blocks of files into a single compressed file
	#pragma omp parallel for schedule(dynamic)
	for (int i = 0; i < omp_get_max_threads() * 10; ++i) {
		unsigned long long int start = blockSize * i;
		if (start < filePathSize) {
			// Store the name of each file for a block owned by each thread.
			// Each thread will use the file to tar and gzip compress their block.
			std::ofstream tmp;
			tmp.open(std::to_string(i) + "." + name + ".ptgz.tmp", std::ios_base::app);
			std::string gzCommand = "GZIP=-1 tar -cz -T " + std::to_string(i) + "." + name + ".ptgz.tmp -f " + std::to_string(i) + "." + name + ".tar.gz";
			for (unsigned long long int j = start; j < std::min(start + blockSize, filePathSize); ++j) {
				tmp << filePaths->at(j) + "\n";
			}

			if (verbose) {
				std::cout << gzCommand + "\n";
			}

			tmp.close();
			system(gzCommand.c_str());
			tarNames->at(i) = std::to_string(i) + "." + name + ".tar.gz";
		}
	}

	// Combines gzipped blocks together into a single tarball.
	// Write tarball names into an idx file for extraction.
	std::ofstream idx, tmp;
	idx.open(name + ".ptgz.idx", std::ios_base::app);
	std::string tarCommand = "tar -c -T " + name + ".ptgz.idx -f " + name + ".ptgz.tar";
	for (unsigned long long int i = 0; i < tarNames->size(); ++i) {
		idx << tarNames->at(i) + "\n";
	}
	idx << name + ".ptgz.idx" + "\n";
	idx.close();

	if (verbose) {
		std::cout << tarCommand + "\n";
	}

	system(tarCommand.c_str());

	// Removes all temporary blocks and idx file.
	#pragma omp parallel for schedule(static)
	for (unsigned long long int i = 0; i < tarNames->size(); ++i) {
		std::string rmCommand = tarNames->at(i);
		if (verbose) {
			std::cout << "remove(" + rmCommand + ")\n";
		}
		if (remove(rmCommand.c_str())) {
			std::cout << "ERROR: " + rmCommand + " could not be removed.\n";
		}

		rmCommand = std::to_string(i) + "." + name + ".ptgz.tmp";
		if (verbose) {
			std::cout << "remove(" + rmCommand + ")\n";
		}
		if (remove(rmCommand.c_str())) {
			std::cout << "ERROR: " + rmCommand + " could not be removed.\n";
		}
	}

	std::string rmCommand;
	if (verbose) {
		std::cout << "remove(" + name + ".ptgz.idx)\n";
	}
	rmCommand = name + ".ptgz.idx";
	if (remove(rmCommand.c_str())) {
		std::cout << "ERROR: " + rmCommand + " could not be removed.\n";
	}

	tarNames->clear();
	delete(tarNames);
}

void extraction(std::vector<std::string> *filePaths, std::string name, bool verbose, bool keep) {
	// Unpack the 1st layer tarball
	std::string exCommand = "tar xf " + name;
	if (verbose) {
		std::cout << exCommand + "\n";
	}
	// system(exCommand.c_str());

	// Get the name from the name of the 1st layer tarball
	for (int i = 0; i < 9; ++i) {
		name.pop_back();
	}

	// Read in all tar.gz files form the ptgz.idx file
	// Delete the ptgz.idx file
	std::ifstream idx;
	std::string line;
	idx.open(name + ".ptgz.idx", std::ios_base::in);
	while (std::getline(idx, line)) {
		filePaths->push_back(line);
	}
	idx.close();
	std::string idxRmCommand = filePaths->back();
	remove(idxRmCommand.c_str());
	filePaths->pop_back();

	// Unpack each tar.gz file
	#pragma omp parallel for schedule(dynamic)
	for (int i = 0; i < filePaths->size(); ++i) {
		std::string gzCommand = "tar xzf " + filePaths->at(i);
		if (verbose) {
			std::cout << gzCommand + "\n";
		}
		system(gzCommand.c_str());
	}

	// Delete each tar.gz file
	#pragma omp parallel for schedule(static)
	for (int i = 0; i < filePaths->size(); ++i) {
		std::string gzRmCommand = filePaths->at(i);
		remove(gzRmCommand.c_str());
	}

	// Decided whether or not to keep the ptgz.tar archive
	if (!keep) {
		std::string tarRmCommand = name + ".ptgz.tar";
		remove(tarRmCommand);
	}
}

char cwd [PATH_MAX];

// Checks to see if the user asks for help.
// Gathers the user provided settings for ptgz.
// Finds the number of files that need to be stored.
// Gathers the file paths of all files to be stored.
// Either compresses the files or extracts the ptgz.tar archive.
int main(int argc, char *argv[]) {
	Settings *instance = new Settings;
	int *numFiles = new int(0);
	std::vector<std::string> *filePaths = new std::vector<std::string>();

	helpCheck(argc, argv);
	getSettings(argc, argv, instance);
	getcwd(cwd, PATH_MAX);

	if ((*instance).compress) {
		findAll(numFiles, cwd);
		getPaths(filePaths, cwd, "");
		compression(filePaths, (*instance).name, (*instance).verbose);
	} else {
		extraction(filePaths, (*instance).name, (*instance).verbose, (*instance).keep);
	}

	delete(instance);
	delete(numFiles);
	filePaths->clear();
	delete(filePaths);
	return 0;
}
<|endoftext|>


<commit_before>//Copyright (c) 2022 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.

#include <polyclipping/clipper.hpp>

#include "Application.h" //To get settings.
#include "ExtruderTrain.h"
#include "raft.h"
#include "Slice.h"
#include "sliceDataStorage.h"
#include "support.h"
#include "settings/EnumSettings.h" //For EPlatformAdhesion.
#include "utils/math.h"

namespace cura
{

void Raft::generate(SliceDataStorage& storage)
{
    assert(storage.raftOutline.size() == 0 && "Raft polygon isn't generated yet, so should be empty!");
    const Settings& settings = Application::getInstance().current_slice->scene.current_mesh_group->settings.get<ExtruderTrain&>("adhesion_extruder_nr").settings;
    const coord_t distance = settings.get<coord_t>("raft_margin");
    constexpr bool include_support = true;
    constexpr bool include_prime_tower = true;
    Polygons global_raft_outlines{ storage.getLayerOutlines(0, include_support, include_prime_tower).offset(distance, ClipperLib::jtRound) };
    const coord_t shield_line_width_layer0 = settings.get<coord_t>("skirt_brim_line_width");
    if (storage.draft_protection_shield.size() > 0)
    {
        Polygons draft_shield_raft = storage.draft_protection_shield.offset(shield_line_width_layer0) // start half a line width outside shield
                                        .difference(storage.draft_protection_shield.offset(-distance - shield_line_width_layer0 / 2, ClipperLib::jtRound)); // end distance inside shield
        global_raft_outlines = global_raft_outlines.unionPolygons(draft_shield_raft);
    }
    if (storage.oozeShield.size() > 0 && storage.oozeShield[0].size() > 0)
    {
        const Polygons& ooze_shield = storage.oozeShield[0];
        Polygons ooze_shield_raft = ooze_shield.offset(shield_line_width_layer0) // start half a line width outside shield
                                        .difference(ooze_shield.offset(-distance - shield_line_width_layer0 / 2, ClipperLib::jtRound)); // end distance inside shield
        global_raft_outlines = global_raft_outlines.unionPolygons(ooze_shield_raft);
    }

    if(settings.get<bool>("raft_remove_inside_corners"))
    {
        global_raft_outlines.makeConvex();
    }
    else
    {
        const coord_t smoothing = settings.get<coord_t>("raft_smoothing");
        global_raft_outlines = global_raft_outlines.offset(smoothing, ClipperLib::jtRound).offset(-smoothing, ClipperLib::jtRound); // remove small holes and smooth inward corners
    }

    constexpr bool dont_include_prime_tower = false;
    const Polygons raw_raft_without_prime{ storage.getLayerOutlines(0, include_support, dont_include_prime_tower).offset(distance, ClipperLib::jtRound) };
    storage.primeRaftOutline = global_raft_outlines.difference(raw_raft_without_prime);
    storage.raftOutline = global_raft_outlines.difference(storage.primeRaftOutline);
}

coord_t Raft::getTotalThickness()
{
    const ExtruderTrain& train = Application::getInstance().current_slice->scene.current_mesh_group->settings.get<ExtruderTrain&>("adhesion_extruder_nr");
    return train.settings.get<coord_t>("raft_base_thickness")
        + train.settings.get<size_t>("raft_interface_layers") * train.settings.get<coord_t>("raft_interface_thickness")
        + train.settings.get<size_t>("raft_surface_layers") * train.settings.get<coord_t>("raft_surface_thickness");
}

coord_t Raft::getZdiffBetweenRaftAndLayer1()
{
    const Settings& mesh_group_settings = Application::getInstance().current_slice->scene.current_mesh_group->settings;
    const ExtruderTrain& train = mesh_group_settings.get<ExtruderTrain&>("adhesion_extruder_nr");
    if (mesh_group_settings.get<EPlatformAdhesion>("adhesion_type") != EPlatformAdhesion::RAFT)
    {
        return 0;
    }
    const coord_t airgap = std::max(coord_t(0), train.settings.get<coord_t>("raft_airgap"));
    const coord_t layer_0_overlap = mesh_group_settings.get<coord_t>("layer_0_z_overlap");

    const coord_t layer_height_0 = mesh_group_settings.get<coord_t>("layer_height_0");

    const coord_t z_diff_raft_to_bottom_of_layer_1 = std::max(coord_t(0), airgap + layer_height_0 - layer_0_overlap);
    return z_diff_raft_to_bottom_of_layer_1;
}

size_t Raft::getFillerLayerCount()
{
    const coord_t normal_layer_height = Application::getInstance().current_slice->scene.current_mesh_group->settings.get<coord_t>("layer_height");
    return round_divide(getZdiffBetweenRaftAndLayer1(), normal_layer_height);
}

coord_t Raft::getFillerLayerHeight()
{
    const Settings& mesh_group_settings = Application::getInstance().current_slice->scene.current_mesh_group->settings;
    if (mesh_group_settings.get<EPlatformAdhesion>("adhesion_type") != EPlatformAdhesion::RAFT)
    {
        const coord_t normal_layer_height = mesh_group_settings.get<coord_t>("layer_height");
        return normal_layer_height;
    }
    return round_divide(getZdiffBetweenRaftAndLayer1(), getFillerLayerCount());
}

size_t Raft::getTotalExtraLayers()
{
    const ExtruderTrain& train = Application::getInstance().current_slice->scene.current_mesh_group->settings.get<ExtruderTrain&>("adhesion_extruder_nr");
    if (train.settings.get<EPlatformAdhesion>("adhesion_type") != EPlatformAdhesion::RAFT)
    {
        return 0;
    }
    return 1 + train.settings.get<size_t>("raft_interface_layers") + train.settings.get<size_t>("raft_surface_layers") + getFillerLayerCount();
}

}//namespace cura
<commit_msg>Don't print 'all same extruder' prime raft without prime tower.<commit_after>//Copyright (c) 2022 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.

#include <polyclipping/clipper.hpp>

#include "Application.h" //To get settings.
#include "ExtruderTrain.h"
#include "raft.h"
#include "Slice.h"
#include "sliceDataStorage.h"
#include "support.h"
#include "settings/EnumSettings.h" //For EPlatformAdhesion.
#include "utils/math.h"

namespace cura
{

void Raft::generate(SliceDataStorage& storage)
{
    assert(storage.raftOutline.size() == 0 && "Raft polygon isn't generated yet, so should be empty!");
    const Settings& settings = Application::getInstance().current_slice->scene.current_mesh_group->settings.get<ExtruderTrain&>("adhesion_extruder_nr").settings;
    const coord_t distance = settings.get<coord_t>("raft_margin");
    constexpr bool include_support = true;
    constexpr bool include_prime_tower = true;
    Polygons global_raft_outlines{ storage.getLayerOutlines(0, include_support, include_prime_tower).offset(distance, ClipperLib::jtRound) };
    const coord_t shield_line_width_layer0 = settings.get<coord_t>("skirt_brim_line_width");
    if (storage.draft_protection_shield.size() > 0)
    {
        Polygons draft_shield_raft = storage.draft_protection_shield.offset(shield_line_width_layer0) // start half a line width outside shield
                                        .difference(storage.draft_protection_shield.offset(-distance - shield_line_width_layer0 / 2, ClipperLib::jtRound)); // end distance inside shield
        global_raft_outlines = global_raft_outlines.unionPolygons(draft_shield_raft);
    }
    if (storage.oozeShield.size() > 0 && storage.oozeShield[0].size() > 0)
    {
        const Polygons& ooze_shield = storage.oozeShield[0];
        Polygons ooze_shield_raft = ooze_shield.offset(shield_line_width_layer0) // start half a line width outside shield
                                        .difference(ooze_shield.offset(-distance - shield_line_width_layer0 / 2, ClipperLib::jtRound)); // end distance inside shield
        global_raft_outlines = global_raft_outlines.unionPolygons(ooze_shield_raft);
    }

    if(settings.get<bool>("raft_remove_inside_corners"))
    {
        global_raft_outlines.makeConvex();
    }
    else
    {
        const coord_t smoothing = settings.get<coord_t>("raft_smoothing");
        global_raft_outlines = global_raft_outlines.offset(smoothing, ClipperLib::jtRound).offset(-smoothing, ClipperLib::jtRound); // remove small holes and smooth inward corners
    }

    constexpr bool dont_include_prime_tower = false;
    const Polygons raw_raft_without_prime{ storage.getLayerOutlines(0, include_support, dont_include_prime_tower).offset(distance, ClipperLib::jtRound) };
    storage.primeRaftOutline = global_raft_outlines.difference(raw_raft_without_prime);
    storage.raftOutline = global_raft_outlines.difference(storage.primeRaftOutline);

    if (storage.primeTower.enabled && ! storage.primeTower.would_have_actual_tower)
    {
        // Find out if the prime-tower part of the raft still needs to be printed, even if there is no actual tower.
        // This will only happen if the different raft layers are printed by different extruders.
        const Settings& mesh_group_settings = Application::getInstance().current_slice->scene.current_mesh_group->settings;
        const size_t base_extruder_nr = mesh_group_settings.get<ExtruderTrain&>("raft_base_extruder_nr").extruder_nr;
        const size_t interface_extruder_nr = mesh_group_settings.get<ExtruderTrain&>("raft_interface_extruder_nr").extruder_nr;
        const size_t surface_extruder_nr = mesh_group_settings.get<ExtruderTrain&>("raft_surface_extruder_nr").extruder_nr;
        if (base_extruder_nr == interface_extruder_nr && base_extruder_nr == surface_extruder_nr)
        {
            storage.primeRaftOutline.clear();
        }
    }
}

coord_t Raft::getTotalThickness()
{
    const ExtruderTrain& train = Application::getInstance().current_slice->scene.current_mesh_group->settings.get<ExtruderTrain&>("adhesion_extruder_nr");
    return train.settings.get<coord_t>("raft_base_thickness")
        + train.settings.get<size_t>("raft_interface_layers") * train.settings.get<coord_t>("raft_interface_thickness")
        + train.settings.get<size_t>("raft_surface_layers") * train.settings.get<coord_t>("raft_surface_thickness");
}

coord_t Raft::getZdiffBetweenRaftAndLayer1()
{
    const Settings& mesh_group_settings = Application::getInstance().current_slice->scene.current_mesh_group->settings;
    const ExtruderTrain& train = mesh_group_settings.get<ExtruderTrain&>("adhesion_extruder_nr");
    if (mesh_group_settings.get<EPlatformAdhesion>("adhesion_type") != EPlatformAdhesion::RAFT)
    {
        return 0;
    }
    const coord_t airgap = std::max(coord_t(0), train.settings.get<coord_t>("raft_airgap"));
    const coord_t layer_0_overlap = mesh_group_settings.get<coord_t>("layer_0_z_overlap");

    const coord_t layer_height_0 = mesh_group_settings.get<coord_t>("layer_height_0");

    const coord_t z_diff_raft_to_bottom_of_layer_1 = std::max(coord_t(0), airgap + layer_height_0 - layer_0_overlap);
    return z_diff_raft_to_bottom_of_layer_1;
}

size_t Raft::getFillerLayerCount()
{
    const coord_t normal_layer_height = Application::getInstance().current_slice->scene.current_mesh_group->settings.get<coord_t>("layer_height");
    return round_divide(getZdiffBetweenRaftAndLayer1(), normal_layer_height);
}

coord_t Raft::getFillerLayerHeight()
{
    const Settings& mesh_group_settings = Application::getInstance().current_slice->scene.current_mesh_group->settings;
    if (mesh_group_settings.get<EPlatformAdhesion>("adhesion_type") != EPlatformAdhesion::RAFT)
    {
        const coord_t normal_layer_height = mesh_group_settings.get<coord_t>("layer_height");
        return normal_layer_height;
    }
    return round_divide(getZdiffBetweenRaftAndLayer1(), getFillerLayerCount());
}

size_t Raft::getTotalExtraLayers()
{
    const ExtruderTrain& train = Application::getInstance().current_slice->scene.current_mesh_group->settings.get<ExtruderTrain&>("adhesion_extruder_nr");
    if (train.settings.get<EPlatformAdhesion>("adhesion_type") != EPlatformAdhesion::RAFT)
    {
        return 0;
    }
    return 1 + train.settings.get<size_t>("raft_interface_layers") + train.settings.get<size_t>("raft_surface_layers") + getFillerLayerCount();
}

}//namespace cura
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "src/profiling/memory/unwinding.h"

#include <sys/types.h>
#include <unistd.h>

#include <unwindstack/MachineArm.h>
#include <unwindstack/MachineArm64.h>
#include <unwindstack/MachineMips.h>
#include <unwindstack/MachineMips64.h>
#include <unwindstack/MachineX86.h>
#include <unwindstack/MachineX86_64.h>
#include <unwindstack/Maps.h>
#include <unwindstack/Memory.h>
#include <unwindstack/Regs.h>
#include <unwindstack/RegsArm.h>
#include <unwindstack/RegsArm64.h>
#include <unwindstack/RegsMips.h>
#include <unwindstack/RegsMips64.h>
#include <unwindstack/RegsX86.h>
#include <unwindstack/RegsX86_64.h>
#include <unwindstack/Unwinder.h>
#include <unwindstack/UserArm.h>
#include <unwindstack/UserArm64.h>
#include <unwindstack/UserMips.h>
#include <unwindstack/UserMips64.h>
#include <unwindstack/UserX86.h>
#include <unwindstack/UserX86_64.h>

#include <procinfo/process_map.h>

#include "perfetto/base/file_utils.h"
#include "perfetto/base/logging.h"
#include "perfetto/base/scoped_file.h"
#include "perfetto/base/string_utils.h"
#include "src/profiling/memory/wire_protocol.h"

namespace perfetto {
namespace profiling {
namespace {

size_t kMaxFrames = 1000;

#pragma GCC diagnostic push
// We do not care about deterministic destructor order.
#pragma GCC diagnostic ignored "-Wglobal-constructors"
#pragma GCC diagnostic ignored "-Wexit-time-destructors"
static std::vector<std::string> kSkipMaps{"heapprofd_client.so"};
#pragma GCC diagnostic pop

std::unique_ptr<unwindstack::Regs> CreateFromRawData(unwindstack::ArchEnum arch,
                                                     void* raw_data) {
  std::unique_ptr<unwindstack::Regs> ret;
  // unwindstack::RegsX::Read returns a raw ptr which we are expected to free.
  switch (arch) {
    case unwindstack::ARCH_X86:
      ret.reset(unwindstack::RegsX86::Read(raw_data));
      break;
    case unwindstack::ARCH_X86_64:
      ret.reset(unwindstack::RegsX86_64::Read(raw_data));
      break;
    case unwindstack::ARCH_ARM:
      ret.reset(unwindstack::RegsArm::Read(raw_data));
      break;
    case unwindstack::ARCH_ARM64:
      ret.reset(unwindstack::RegsArm64::Read(raw_data));
      break;
    case unwindstack::ARCH_MIPS:
      ret.reset(unwindstack::RegsMips::Read(raw_data));
      break;
    case unwindstack::ARCH_MIPS64:
      ret.reset(unwindstack::RegsMips64::Read(raw_data));
      break;
    case unwindstack::ARCH_UNKNOWN:
      ret.reset(nullptr);
      break;
  }
  return ret;
}

// Behaves as a pread64, emulating it if not already exposed by the standard
// library. Safe to use on 32bit platforms for addresses with the top bit set.
// Clobbers the |fd| seek position if emulating.
ssize_t ReadAtOffsetClobberSeekPos(int fd,
                                   void* buf,
                                   size_t count,
                                   uint64_t addr) {
#ifdef __BIONIC__
  return pread64(fd, buf, count, static_cast<off64_t>(addr));
#else
  if (lseek64(fd, static_cast<off64_t>(addr), SEEK_SET) == -1)
    return -1;
  return read(fd, buf, count);
#endif
}

}  // namespace

StackOverlayMemory::StackOverlayMemory(std::shared_ptr<unwindstack::Memory> mem,
                                       uint64_t sp,
                                       uint8_t* stack,
                                       size_t size)
    : mem_(std::move(mem)), sp_(sp), stack_end_(sp + size), stack_(stack) {}

size_t StackOverlayMemory::Read(uint64_t addr, void* dst, size_t size) {
  if (addr >= sp_ && addr + size <= stack_end_ && addr + size > sp_) {
    size_t offset = static_cast<size_t>(addr - sp_);
    memcpy(dst, stack_ + offset, size);
    return size;
  }

  return mem_->Read(addr, dst, size);
}

FDMemory::FDMemory(base::ScopedFile mem_fd) : mem_fd_(std::move(mem_fd)) {}

size_t FDMemory::Read(uint64_t addr, void* dst, size_t size) {
  ssize_t rd = ReadAtOffsetClobberSeekPos(*mem_fd_, dst, size, addr);
  if (rd == -1) {
    PERFETTO_DPLOG("read at offset");
    return 0;
  }
  return static_cast<size_t>(rd);
}

FileDescriptorMaps::FileDescriptorMaps(base::ScopedFile fd)
    : fd_(std::move(fd)) {}

bool FileDescriptorMaps::Parse() {
  // If the process has already exited, lseek or ReadFileDescriptor will
  // return false.
  if (lseek(*fd_, 0, SEEK_SET) == -1)
    return false;

  std::string content;
  if (!base::ReadFileDescriptor(*fd_, &content))
    return false;
  return android::procinfo::ReadMapFileContent(
      &content[0], [&](uint64_t start, uint64_t end, uint16_t flags,
                       uint64_t pgoff, ino_t, const char* name) {
        // Mark a device map in /dev/ and not in /dev/ashmem/ specially.
        if (strncmp(name, "/dev/", 5) == 0 &&
            strncmp(name + 5, "ashmem/", 7) != 0) {
          flags |= unwindstack::MAPS_FLAGS_DEVICE_MAP;
        }
        maps_.push_back(
            new unwindstack::MapInfo(nullptr, start, end, pgoff, flags, name));
      });
}

void FileDescriptorMaps::Reset() {
  for (unwindstack::MapInfo* info : maps_)
    delete info;
  maps_.clear();
}

bool DoUnwind(WireMessage* msg, UnwindingMetadata* metadata, AllocRecord* out) {
  AllocMetadata* alloc_metadata = msg->alloc_header;
  std::unique_ptr<unwindstack::Regs> regs(
      CreateFromRawData(alloc_metadata->arch, alloc_metadata->register_data));
  if (regs == nullptr) {
    unwindstack::FrameData frame_data{};
    frame_data.function_name = "ERROR READING REGISTERS";
    frame_data.map_name = "ERROR";

    out->frames.emplace_back(frame_data, "");
    PERFETTO_DLOG("regs");
    return false;
  }
  uint8_t* stack = reinterpret_cast<uint8_t*>(msg->payload);
  std::shared_ptr<unwindstack::Memory> mems =
      std::make_shared<StackOverlayMemory>(metadata->fd_mem,
                                           alloc_metadata->stack_pointer, stack,
                                           msg->payload_size);

  unwindstack::Unwinder unwinder(kMaxFrames, &metadata->maps, regs.get(), mems);
#if PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
  unwinder.SetJitDebug(metadata->jit_debug.get(), regs->Arch());
  unwinder.SetDexFiles(metadata->dex_files.get(), regs->Arch());
#endif
  // Surpress incorrect "variable may be uninitialized" error for if condition
  // after this loop. error_code = LastErrorCode gets run at least once.
  uint8_t error_code = 0;
  for (int attempt = 0; attempt < 2; ++attempt) {
    if (attempt > 0) {
      metadata->ReparseMaps();
#if PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
      unwinder.SetJitDebug(metadata->jit_debug.get(), regs->Arch());
      unwinder.SetDexFiles(metadata->dex_files.get(), regs->Arch());
#endif
    }
    unwinder.Unwind(&kSkipMaps, nullptr);
    error_code = unwinder.LastErrorCode();
    if (error_code != unwindstack::ERROR_INVALID_MAP)
      break;
  }
  std::vector<unwindstack::FrameData> frames = unwinder.ConsumeFrames();
  for (unwindstack::FrameData& fd : frames) {
    std::string build_id;
    if (fd.map_name != "") {
      unwindstack::MapInfo* map_info = metadata->maps.Find(fd.pc);
      if (map_info)
        build_id = map_info->GetBuildID();
    }

    out->frames.emplace_back(std::move(fd), std::move(build_id));
  }

  if (error_code != 0) {
    unwindstack::FrameData frame_data{};
    frame_data.function_name = "ERROR " + std::to_string(error_code);
    frame_data.map_name = "ERROR";

    out->frames.emplace_back(frame_data, "");
    PERFETTO_DLOG("unwinding failed %" PRIu8, error_code);
  }

  return true;
}

bool HandleUnwindingRecord(UnwindingRecord* rec, BookkeepingRecord* out) {
  WireMessage msg;
  if (!ReceiveWireMessage(reinterpret_cast<char*>(rec->data.get()), rec->size,
                          &msg))
    return false;
  if (msg.record_type == RecordType::Malloc) {
    std::shared_ptr<UnwindingMetadata> metadata = rec->metadata.lock();
    if (!metadata) {
      // Process has already gone away.
      return false;
    }

    out->alloc_record.alloc_metadata = *msg.alloc_header;
    out->pid = rec->pid;
    out->client_generation = msg.alloc_header->client_generation;
    out->record_type = BookkeepingRecord::Type::Malloc;
    DoUnwind(&msg, metadata.get(), &out->alloc_record);
    return true;
  } else if (msg.record_type == RecordType::Free) {
    out->record_type = BookkeepingRecord::Type::Free;
    out->pid = rec->pid;
    out->client_generation = msg.free_header->client_generation;
    // We need to keep this alive, because msg.free_header is a pointer into
    // this.
    out->free_record.free_data = std::move(rec->data);
    out->free_record.metadata = msg.free_header;
    return true;
  } else {
    PERFETTO_DFATAL("Invalid record type.");
    return false;
  }
}

void UnwindingMainLoop(BoundedQueue<UnwindingRecord>* input_queue,
                       BoundedQueue<BookkeepingRecord>* output_queue) {
  for (;;) {
    UnwindingRecord rec;
    if (!input_queue->Get(&rec))
      return;
    BookkeepingRecord out;
    if (HandleUnwindingRecord(&rec, &out))
      output_queue->Add(std::move(out));
  }
}

}  // namespace profiling
}  // namespace perfetto
<commit_msg>Use emplace_back over push_back to support unique_ptr. am: 5abc126b07 am: ec0446a677<commit_after>/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "src/profiling/memory/unwinding.h"

#include <sys/types.h>
#include <unistd.h>

#include <unwindstack/MachineArm.h>
#include <unwindstack/MachineArm64.h>
#include <unwindstack/MachineMips.h>
#include <unwindstack/MachineMips64.h>
#include <unwindstack/MachineX86.h>
#include <unwindstack/MachineX86_64.h>
#include <unwindstack/Maps.h>
#include <unwindstack/Memory.h>
#include <unwindstack/Regs.h>
#include <unwindstack/RegsArm.h>
#include <unwindstack/RegsArm64.h>
#include <unwindstack/RegsMips.h>
#include <unwindstack/RegsMips64.h>
#include <unwindstack/RegsX86.h>
#include <unwindstack/RegsX86_64.h>
#include <unwindstack/Unwinder.h>
#include <unwindstack/UserArm.h>
#include <unwindstack/UserArm64.h>
#include <unwindstack/UserMips.h>
#include <unwindstack/UserMips64.h>
#include <unwindstack/UserX86.h>
#include <unwindstack/UserX86_64.h>

#include <procinfo/process_map.h>

#include "perfetto/base/file_utils.h"
#include "perfetto/base/logging.h"
#include "perfetto/base/scoped_file.h"
#include "perfetto/base/string_utils.h"
#include "src/profiling/memory/wire_protocol.h"

namespace perfetto {
namespace profiling {
namespace {

size_t kMaxFrames = 1000;

#pragma GCC diagnostic push
// We do not care about deterministic destructor order.
#pragma GCC diagnostic ignored "-Wglobal-constructors"
#pragma GCC diagnostic ignored "-Wexit-time-destructors"
static std::vector<std::string> kSkipMaps{"heapprofd_client.so"};
#pragma GCC diagnostic pop

std::unique_ptr<unwindstack::Regs> CreateFromRawData(unwindstack::ArchEnum arch,
                                                     void* raw_data) {
  std::unique_ptr<unwindstack::Regs> ret;
  // unwindstack::RegsX::Read returns a raw ptr which we are expected to free.
  switch (arch) {
    case unwindstack::ARCH_X86:
      ret.reset(unwindstack::RegsX86::Read(raw_data));
      break;
    case unwindstack::ARCH_X86_64:
      ret.reset(unwindstack::RegsX86_64::Read(raw_data));
      break;
    case unwindstack::ARCH_ARM:
      ret.reset(unwindstack::RegsArm::Read(raw_data));
      break;
    case unwindstack::ARCH_ARM64:
      ret.reset(unwindstack::RegsArm64::Read(raw_data));
      break;
    case unwindstack::ARCH_MIPS:
      ret.reset(unwindstack::RegsMips::Read(raw_data));
      break;
    case unwindstack::ARCH_MIPS64:
      ret.reset(unwindstack::RegsMips64::Read(raw_data));
      break;
    case unwindstack::ARCH_UNKNOWN:
      ret.reset(nullptr);
      break;
  }
  return ret;
}

// Behaves as a pread64, emulating it if not already exposed by the standard
// library. Safe to use on 32bit platforms for addresses with the top bit set.
// Clobbers the |fd| seek position if emulating.
ssize_t ReadAtOffsetClobberSeekPos(int fd,
                                   void* buf,
                                   size_t count,
                                   uint64_t addr) {
#ifdef __BIONIC__
  return pread64(fd, buf, count, static_cast<off64_t>(addr));
#else
  if (lseek64(fd, static_cast<off64_t>(addr), SEEK_SET) == -1)
    return -1;
  return read(fd, buf, count);
#endif
}

}  // namespace

StackOverlayMemory::StackOverlayMemory(std::shared_ptr<unwindstack::Memory> mem,
                                       uint64_t sp,
                                       uint8_t* stack,
                                       size_t size)
    : mem_(std::move(mem)), sp_(sp), stack_end_(sp + size), stack_(stack) {}

size_t StackOverlayMemory::Read(uint64_t addr, void* dst, size_t size) {
  if (addr >= sp_ && addr + size <= stack_end_ && addr + size > sp_) {
    size_t offset = static_cast<size_t>(addr - sp_);
    memcpy(dst, stack_ + offset, size);
    return size;
  }

  return mem_->Read(addr, dst, size);
}

FDMemory::FDMemory(base::ScopedFile mem_fd) : mem_fd_(std::move(mem_fd)) {}

size_t FDMemory::Read(uint64_t addr, void* dst, size_t size) {
  ssize_t rd = ReadAtOffsetClobberSeekPos(*mem_fd_, dst, size, addr);
  if (rd == -1) {
    PERFETTO_DPLOG("read at offset");
    return 0;
  }
  return static_cast<size_t>(rd);
}

FileDescriptorMaps::FileDescriptorMaps(base::ScopedFile fd)
    : fd_(std::move(fd)) {}

bool FileDescriptorMaps::Parse() {
  // If the process has already exited, lseek or ReadFileDescriptor will
  // return false.
  if (lseek(*fd_, 0, SEEK_SET) == -1)
    return false;

  std::string content;
  if (!base::ReadFileDescriptor(*fd_, &content))
    return false;
  return android::procinfo::ReadMapFileContent(
      &content[0], [&](uint64_t start, uint64_t end, uint16_t flags,
                       uint64_t pgoff, ino_t, const char* name) {
        // Mark a device map in /dev/ and not in /dev/ashmem/ specially.
        if (strncmp(name, "/dev/", 5) == 0 &&
            strncmp(name + 5, "ashmem/", 7) != 0) {
          flags |= unwindstack::MAPS_FLAGS_DEVICE_MAP;
        }
        maps_.emplace_back(
            new unwindstack::MapInfo(nullptr, start, end, pgoff, flags, name));
      });
}

void FileDescriptorMaps::Reset() {
  maps_.clear();
}

bool DoUnwind(WireMessage* msg, UnwindingMetadata* metadata, AllocRecord* out) {
  AllocMetadata* alloc_metadata = msg->alloc_header;
  std::unique_ptr<unwindstack::Regs> regs(
      CreateFromRawData(alloc_metadata->arch, alloc_metadata->register_data));
  if (regs == nullptr) {
    unwindstack::FrameData frame_data{};
    frame_data.function_name = "ERROR READING REGISTERS";
    frame_data.map_name = "ERROR";

    out->frames.emplace_back(frame_data, "");
    PERFETTO_DLOG("regs");
    return false;
  }
  uint8_t* stack = reinterpret_cast<uint8_t*>(msg->payload);
  std::shared_ptr<unwindstack::Memory> mems =
      std::make_shared<StackOverlayMemory>(metadata->fd_mem,
                                           alloc_metadata->stack_pointer, stack,
                                           msg->payload_size);

  unwindstack::Unwinder unwinder(kMaxFrames, &metadata->maps, regs.get(), mems);
#if PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
  unwinder.SetJitDebug(metadata->jit_debug.get(), regs->Arch());
  unwinder.SetDexFiles(metadata->dex_files.get(), regs->Arch());
#endif
  // Surpress incorrect "variable may be uninitialized" error for if condition
  // after this loop. error_code = LastErrorCode gets run at least once.
  uint8_t error_code = 0;
  for (int attempt = 0; attempt < 2; ++attempt) {
    if (attempt > 0) {
      metadata->ReparseMaps();
#if PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
      unwinder.SetJitDebug(metadata->jit_debug.get(), regs->Arch());
      unwinder.SetDexFiles(metadata->dex_files.get(), regs->Arch());
#endif
    }
    unwinder.Unwind(&kSkipMaps, nullptr);
    error_code = unwinder.LastErrorCode();
    if (error_code != unwindstack::ERROR_INVALID_MAP)
      break;
  }
  std::vector<unwindstack::FrameData> frames = unwinder.ConsumeFrames();
  for (unwindstack::FrameData& fd : frames) {
    std::string build_id;
    if (fd.map_name != "") {
      unwindstack::MapInfo* map_info = metadata->maps.Find(fd.pc);
      if (map_info)
        build_id = map_info->GetBuildID();
    }

    out->frames.emplace_back(std::move(fd), std::move(build_id));
  }

  if (error_code != 0) {
    unwindstack::FrameData frame_data{};
    frame_data.function_name = "ERROR " + std::to_string(error_code);
    frame_data.map_name = "ERROR";

    out->frames.emplace_back(frame_data, "");
    PERFETTO_DLOG("unwinding failed %" PRIu8, error_code);
  }

  return true;
}

bool HandleUnwindingRecord(UnwindingRecord* rec, BookkeepingRecord* out) {
  WireMessage msg;
  if (!ReceiveWireMessage(reinterpret_cast<char*>(rec->data.get()), rec->size,
                          &msg))
    return false;
  if (msg.record_type == RecordType::Malloc) {
    std::shared_ptr<UnwindingMetadata> metadata = rec->metadata.lock();
    if (!metadata) {
      // Process has already gone away.
      return false;
    }

    out->alloc_record.alloc_metadata = *msg.alloc_header;
    out->pid = rec->pid;
    out->client_generation = msg.alloc_header->client_generation;
    out->record_type = BookkeepingRecord::Type::Malloc;
    DoUnwind(&msg, metadata.get(), &out->alloc_record);
    return true;
  } else if (msg.record_type == RecordType::Free) {
    out->record_type = BookkeepingRecord::Type::Free;
    out->pid = rec->pid;
    out->client_generation = msg.free_header->client_generation;
    // We need to keep this alive, because msg.free_header is a pointer into
    // this.
    out->free_record.free_data = std::move(rec->data);
    out->free_record.metadata = msg.free_header;
    return true;
  } else {
    PERFETTO_DFATAL("Invalid record type.");
    return false;
  }
}

void UnwindingMainLoop(BoundedQueue<UnwindingRecord>* input_queue,
                       BoundedQueue<BookkeepingRecord>* output_queue) {
  for (;;) {
    UnwindingRecord rec;
    if (!input_queue->Get(&rec))
      return;
    BookkeepingRecord out;
    if (HandleUnwindingRecord(&rec, &out))
      output_queue->Add(std::move(out));
  }
}

}  // namespace profiling
}  // namespace perfetto
<|endoftext|>


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

#pragma once

#include "Common.hpp"
#include "DictEntry.hpp"

namespace opencc {
  class OPENCC_EXPORT Dict {
    public:
      virtual size_t KeyMaxLength() const = 0;
      virtual Optional<DictEntry> Match(const char* word) = 0;
      virtual Optional<DictEntry> MatchPrefix(const char* word);
      virtual vector<DictEntry> MatchAllPrefixes(const char* word);
      virtual vector<DictEntry> GetLexicon() = 0;
      virtual void LoadFromDict(Dict* dictionary) = 0;
  };
}
<commit_msg>Add std::string interface for Dict<commit_after>/*
 * Open Chinese Convert
 *
 * Copyright 2010-2013 BYVoid <byvoid@byvoid.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

#include "Common.hpp"
#include "DictEntry.hpp"

namespace opencc {
  class OPENCC_EXPORT Dict {
    public:
      virtual size_t KeyMaxLength() const = 0;
      virtual Optional<DictEntry> Match(const char* word) = 0;
      virtual Optional<DictEntry> MatchPrefix(const char* word);
      virtual vector<DictEntry> MatchAllPrefixes(const char* word);
      Optional<DictEntry> Match(const string& word) {
        return Match(word.c_str());
      }
      Optional<DictEntry> MatchPrefix(const string& word) {
        return MatchPrefix(word.c_str());
      }
      vector<DictEntry> MatchAllPrefixes(const string& word) {
        return MatchAllPrefixes(word.c_str());
      }
      virtual vector<DictEntry> GetLexicon() = 0;
      virtual void LoadFromDict(Dict* dictionary) = 0;
  };
}
<|endoftext|>


<commit_before>#include "protocol.h"

void Protocol::connectServer() {

}

bool Protocol::connected() {

}

bool Protocol::shouldUnload() {

}

void Protocol::disconnect() {

}

void Protocol::onRehash() {

}

void Protocol::sendMsg(const std::string& client, const std::string& target, const std::string& message, const std::map<std::string, std::string>& tags) {

}

void Protocol::sendNotice(const std::string& client, const std::string& target, const std::string& message, const std::map<std::string, std::string>& tags) {

}

void Protocol::setMode(const std::string& client, const std::string& target, const std::list<std::tuple<bool, std::string, std::string>>& modes, const std::map<std::string, std::string>& tags) {

}

void Protocol::joinChan(const std::string& client, const std::string& channel, const std::map<std::string, std::string>& tags) {

}

void Protocol::joinChan(const std::string& client, const std::string& channel, const std::map<std::string, std::string>& tags) {

}

void Protocol::partChan(const std::string& client, const std::string& channel, const std::string& reason, const std::map<std::string, std::string>& tags) {

}

void Protocol::kickUser(const std::string& client, const std::string& channel, const std::string& user, const std::string& reason, const std::map<std::string, std::string>& tags) {

}

void Protocol::setTopic(const std::string& client, const std::string& channel, const std::string& topic, const std::map<std::string, std::string>& tags) {

}

void Protocol::inviteUser(const std::string& client, const std::string& channel, const std::string& user, const std::map<std::string, std::string>& tags) {

}

void Protocol::knock(const std::string& client, const std::string& channel, const std::string& reason, const std::map<std::string, std::string>& tags) {

}

void Protocol::changeNick(const std::string& client, const std::string& newNick, const std::map<std::string, std::string>& tags) {

}

void Protocol::sendPing(const std::string& client, const std::string& data, const std::map<std::string, std::string>& tags) {

}

void Protocol::setAway(const std::string& client, const std::string& reason, const std::map<std::string, std::string>& tags) {

}

void Protocol::setUnaway(const std::string& client, const std::map<std::string, std::string>& tags) {

}

void Protocol::oper(const std::string& client, const std::string& username, const std::string& password, const std::map<std::string, std::string>& tags) {

}

void Protocol::sendWallops(const std::string& client, const std::string& message, const std::map<std::string, std::string>& tags) {

}

void Protocol::sendOtherData(const std::string& client, const IRCMessage* line) {

}

std::string Protocol::addClient(const std::string& nick, const std::string& ident, const std::string& gecos) {

}

void Protocol::removeClient(const std::string& client) {

}

std::set<std::string> Protocol::serverCapabilities() {

}

std::set<char> Protocol::chanTypes() {

}

std::list<std::pair<ModeType, std::string>> Protocol::allChanModes() {

}

ModeType Protocol::chanModeType(const std::string& mode) {

}

char Protocol::prefixSymbol(const std::string& mode) {

}

std::pair<std::string, char> Protocol::compareStatus(const std::string& status0, const std::string& status1) {

}

std::pair<std::string, char> Protocol::compareStatus(const std::string& status0, char status1) {

}

std::pair<std::string, char> Protocol::compareStatus(char status0, char status1) {

}

std::string Protocol::chanTopic(const std::string& channel) {

}

std::string Protocol::chanTopicSetter(const std::string& channel) {

}

time_t Protocol::chanTopicTimestamp(const std::string& channel) {

}

time_t Protocol::chanTimestamp(const std::string& channel) {

}

std::list<std::string> Protocol::chanUsers(const std::string& channel) {

}

bool Protocol::userInChan(const std::string& channel, const std::string& user) {

}

std::pair<std::string, char> Protocol::userStatus(const std::string& channel, const std::string& user) {

}

bool Protocol::userHasStatus(const std::string& channel, const std::string& user, const std::string& status) {

}

bool Protocol::userHasStatus(const std::string& channel, const std::string& user, char status) {

}

bool Protocol::userHasStatusOrGreater(const std::string& channel, const std::string& user, const std::string& status) {

}

bool Protocol::userHasStatusOrGreater(const std::string& channel, const std::string& user, char status) {

}

std::map<std::string, std::string> Protocol::chanModes(const std::string& channel) {

}

bool Protocol::chanHasMode(const std::string& channel, const std::string& mode) {

}

std::string Protocol::chanModeParam(const std::string& channel, const std::string& mode) {

}

std::list<std::string> Protocol::chanListModeList(const std::string& channel, const std::string& mode) {

}

std::list<std::string> Protocol::clientList() {

}

std::string Protocol::userNick(const std::string& user) {

}

std::string Protocol::userIdent(const std::string& user) {

}

std::string Protocol::userHost(const std::string& user) {

}

std::string Protocol::userGecos(const std::string& user) {

}

std::string Protocol::idFromNick(const std::string& nick) {

}

std::list<std::pair<ModeType, std::string>> Protocol::allUserModes() {

}

ModeType Protocol::userModeType(const std::string& mode) {

}

std::map<std::string, std::string> Protocol::userModes(const std::string& user) {

}

bool Protocol::userHasMode(const std::string& user, const std::string& mode) {

}

std::string Protocol::userModeParam(const std::string& user, const std::string& mode) {

}

std::list<std::string> Protocol::userListModeList(const std::string& user, const std::string& listMode) {

}

std::set<std::string> Protocol::userChans(const std::string& user) {

}<commit_msg>Fix Protocol definition signatures<commit_after>#include "protocol.h"

void Protocol::connectServer() {

}

bool Protocol::connected() {

}

bool Protocol::shouldUnload() {

}

void Protocol::disconnect() {

}

void Protocol::onRehash() {

}

void Protocol::sendMsg(const std::string& client, const std::string& target, const std::string& message, const std::map<std::string, std::string>& tags) {

}

void Protocol::sendNotice(const std::string& client, const std::string& target, const std::string& message, const std::map<std::string, std::string>& tags) {

}

void Protocol::setMode(const std::string& client, const std::string& target, const std::list<std::tuple<bool, std::string, std::string>>& modes, const std::map<std::string, std::string>& tags) {

}

void Protocol::joinChan(const std::string& client, const std::string& channel, const std::map<std::string, std::string>& tags) {

}

void Protocol::joinChan(const std::string& client, const std::string& channel, const std::string& key, const std::map<std::string, std::string>& tags) {

}

void Protocol::partChan(const std::string& client, const std::string& channel, const std::string& reason, const std::map<std::string, std::string>& tags) {

}

void Protocol::kickUser(const std::string& client, const std::string& channel, const std::string& user, const std::string& reason, const std::map<std::string, std::string>& tags) {

}

void Protocol::setTopic(const std::string& client, const std::string& channel, const std::string& topic, const std::map<std::string, std::string>& tags) {

}

void Protocol::inviteUser(const std::string& client, const std::string& channel, const std::string& user, const std::map<std::string, std::string>& tags) {

}

void Protocol::knock(const std::string& client, const std::string& channel, const std::string& reason, const std::map<std::string, std::string>& tags) {

}

void Protocol::changeNick(const std::string& client, const std::string& newNick, const std::map<std::string, std::string>& tags) {

}

void Protocol::sendPing(const std::string& client, const std::string& data, const std::map<std::string, std::string>& tags) {

}

void Protocol::setAway(const std::string& client, const std::string& reason, const std::map<std::string, std::string>& tags) {

}

void Protocol::setUnaway(const std::string& client, const std::map<std::string, std::string>& tags) {

}

void Protocol::oper(const std::string& client, const std::string& username, const std::string& password, const std::map<std::string, std::string>& tags) {

}

void Protocol::sendWallops(const std::string& client, const std::string& message, const std::map<std::string, std::string>& tags) {

}

void Protocol::sendOtherData(const std::string& client, const IRCMessage* line) {

}

std::string Protocol::addClient(const std::string& nick, const std::string& ident, const std::string& gecos) {

}

void Protocol::removeClient(const std::string& client) {

}

std::set<std::string> Protocol::serverCapabilities() {

}

std::set<char> Protocol::chanTypes() {

}

std::list<std::pair<ModeType, std::string>> Protocol::allChanModes() {

}

ModeType Protocol::chanModeType(const std::string& mode) {

}

char Protocol::prefixSymbol(const std::string& mode) {

}

std::pair<std::string, char> Protocol::compareStatus(const std::string& status0, const std::string& status1) {

}

std::pair<std::string, char> Protocol::compareStatus(const std::string& status0, char status1) {

}

std::pair<std::string, char> Protocol::compareStatus(char status0, char status1) {

}

std::string Protocol::chanTopic(const std::string& channel) {

}

std::string Protocol::chanTopicSetter(const std::string& channel) {

}

time_t Protocol::chanTopicTimestamp(const std::string& channel) {

}

time_t Protocol::chanTimestamp(const std::string& channel) {

}

std::list<std::string> Protocol::chanUsers(const std::string& channel) {

}

bool Protocol::userInChan(const std::string& channel, const std::string& user) {

}

std::pair<std::string, char> Protocol::userStatus(const std::string& channel, const std::string& user) {

}

bool Protocol::userHasStatus(const std::string& channel, const std::string& user, const std::string& status) {

}

bool Protocol::userHasStatus(const std::string& channel, const std::string& user, char status) {

}

bool Protocol::userHasStatusOrGreater(const std::string& channel, const std::string& user, const std::string& status) {

}

bool Protocol::userHasStatusOrGreater(const std::string& channel, const std::string& user, char status) {

}

std::map<std::string, std::string> Protocol::chanModes(const std::string& channel) {

}

bool Protocol::chanHasMode(const std::string& channel, const std::string& mode) {

}

std::string Protocol::chanModeParam(const std::string& channel, const std::string& mode) {

}

std::list<std::string> Protocol::chanListModeList(const std::string& channel, const std::string& mode) {

}

std::list<std::string> Protocol::clientList() {

}

std::string Protocol::userNick(const std::string& user) {

}

std::string Protocol::userIdent(const std::string& user) {

}

std::string Protocol::userHost(const std::string& user) {

}

std::string Protocol::userGecos(const std::string& user) {

}

std::string Protocol::idFromNick(const std::string& nick) {

}

std::list<std::pair<ModeType, std::string>> Protocol::allUserModes() {

}

ModeType Protocol::userModeType(const std::string& mode) {

}

std::map<std::string, std::string> Protocol::userModes(const std::string& user) {

}

bool Protocol::userHasMode(const std::string& user, const std::string& mode) {

}

std::string Protocol::userModeParam(const std::string& user, const std::string& mode) {

}

std::list<std::string> Protocol::userListModeList(const std::string& user, const std::string& listMode) {

}

std::set<std::string> Protocol::userChans(const std::string& user) {

}<|endoftext|>


<commit_before>///
/// @file   Erat.cpp
/// @brief  The Erat class manages prime sieving using the
///         EratSmall, EratMedium, EratBig classes.
///
/// Copyright (C) 2020 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <primesieve/config.hpp>
#include <primesieve/CpuInfo.hpp>
#include <primesieve/Erat.hpp>
#include <primesieve/EratSmall.hpp>
#include <primesieve/EratMedium.hpp>
#include <primesieve/EratBig.hpp>
#include <primesieve/PreSieve.hpp>
#include <primesieve/pmath.hpp>

#include <stdint.h>
#include <array>
#include <algorithm>
#include <cassert>
#include <memory>

using namespace std;
using namespace primesieve;

namespace {

/// unset bits < start
const array<uint8_t, 37> unsetSmaller =
{
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xfe, 0xfe, 0xfe, 0xfe, 0xfc, 0xfc, 0xf8, 0xf8,
  0xf8, 0xf8, 0xf0, 0xf0, 0xe0, 0xe0, 0xe0, 0xe0,
  0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x80, 0x80,
  0x00, 0x00, 0x00, 0x00, 0x00
};

/// unset bits > stop
const array<uint8_t, 37> unsetLarger =
{
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
  0x01, 0x01, 0x01, 0x03, 0x03, 0x07, 0x07, 0x07,
  0x07, 0x0f, 0x0f, 0x1f, 0x1f, 0x1f, 0x1f, 0x3f,
  0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x7f, 0x7f, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff
};

} // namespace

namespace primesieve {

Erat::Erat() = default;

Erat::Erat(uint64_t start, uint64_t stop) :
  start_(start),
  stop_(stop)
{ }

/// @start:     Sieve primes >= start
/// @stop:      Sieve primes <= stop
/// @sieveSize: Sieve size in KiB
/// @preSieve:  Pre-sieve small primes
///
void Erat::init(uint64_t start,
                uint64_t stop,
                uint64_t sieveSize,
                PreSieve& preSieve)
{
  if (start > stop)
    return;

  assert(start >= 7);
  start_ = start;
  stop_ = stop;
  preSieve_ = &preSieve;
  preSieve_->init(start, stop);
  maxPreSieve_ = preSieve_->getMaxPrime();
  initSieve(sieveSize);

  // The 8 bits of each byte of the sieve array correspond to
  // the offsets { 7, 11, 13, 17, 19, 23, 29, 31 }. If we
  // would set dist = sieveSize * 30 we would not include the
  // last bit of the last byte which corresponds to the offset
  // 31. For this reason we set dist = sieveSize * 30 + 6.
  uint64_t rem = byteRemainder(start);
  uint64_t dist = sieveSize_ * 30 + 6;
  segmentLow_ = start_ - rem;
  segmentHigh_ = checkedAdd(segmentLow_, dist);
  segmentHigh_ = min(segmentHigh_, stop);

  initErat();
}

void Erat::initSieve(uint64_t sieveSize)
{
  sieveSize_ = floorPow2(sieveSize);
  sieveSize_ = inBetween(8, sieveSize_, 4096);
  sieveSize_ *= 1024;

  sieve_ = new uint8_t[sieveSize_];
  deleter_.reset(sieve_);
}

void Erat::initErat()
{
  uint64_t sqrtStop = isqrt(stop_);
  uint64_t l1CacheSize = getL1CacheSize();

  maxEratSmall_ = (uint64_t) (l1CacheSize * config::FACTOR_ERATSMALL);
  maxEratMedium_ = (uint64_t) (sieveSize_ * config::FACTOR_ERATMEDIUM);

  if (sqrtStop > maxPreSieve_)
    eratSmall_.init(stop_, l1CacheSize, maxEratSmall_);
  if (sqrtStop > maxEratSmall_)
    eratMedium_.init(stop_, sieveSize_, maxEratMedium_);
  if (sqrtStop > maxEratMedium_)
    eratBig_.init(stop_, sieveSize_, sqrtStop);
}

/// EratMedium and EratBig usually run fastest using a sieve
/// size that matches the CPUs L2 cache size. EratSmall
/// however runs fastest using a sieve size that matches the
/// CPUs L1 cache size. Hence we use a smaller sieve size
/// (L1 cache size) in EratSmall and a larger sieve size (L2
/// cache size) in both EratMedium and EratBig.
///
uint64_t Erat::getL1CacheSize() const
{
  if (!cpuInfo.hasL1Cache())
    return sieveSize_;

  uint64_t size = cpuInfo.l1CacheSize();
  uint64_t minSize = 8 << 10;
  uint64_t maxSize = 4096 << 10;

  size = std::min(size, sieveSize_);
  size = inBetween(minSize, size, maxSize);

  return size;
}

bool Erat::hasNextSegment() const
{
  return segmentLow_ < stop_;
}

uint64_t Erat::byteRemainder(uint64_t n)
{
  n %= 30;
  if (n <= 6) n += 30;
  return n;
}

/// Pre-sieve multiples of small primes e.g. <= 19
/// to speed up the sieve of Eratosthenes
///
void Erat::preSieve()
{
  preSieve_->copy(sieve_, sieveSize_, segmentLow_);

  // unset bits < start
  if (segmentLow_ <= start_)
  {
    if (start_ <= maxPreSieve_)
      sieve_[0] = 0xff;
    uint64_t rem = byteRemainder(start_);
    sieve_[0] &= unsetSmaller[rem];
  }
}

void Erat::crossOff()
{
  if (eratSmall_.enabled())
    eratSmall_.crossOff(sieve_, sieveSize_);
  if (eratMedium_.enabled())
    eratMedium_.crossOff(sieve_, sieveSize_);
  if (eratBig_.enabled())
    eratBig_.crossOff(sieve_);
}

void Erat::sieveSegment()
{
  if (segmentHigh_ == stop_)
    sieveLastSegment();
  else
  {
    preSieve();
    crossOff();

    uint64_t dist = sieveSize_ * 30;
    segmentLow_ = checkedAdd(segmentLow_, dist);
    segmentHigh_ = checkedAdd(segmentHigh_, dist);
    segmentHigh_ = min(segmentHigh_, stop_);
  }
}

void Erat::sieveLastSegment()
{
  uint64_t rem = byteRemainder(stop_);
  uint64_t dist = (stop_ - rem) - segmentLow_;
  sieveSize_ = dist / 30 + 1;

  preSieve();
  crossOff();

  // unset bits > stop
  sieve_[sieveSize_ - 1] &= unsetLarger[rem];

  // unset bytes > stop
  uint64_t bytes = sieveSize_ % 8;
  bytes = (8 - bytes) % 8;
  fill_n(&sieve_[sieveSize_], bytes, (uint8_t) 0);

  segmentLow_ = stop_;
}

} // namespace
<commit_msg>Remove using namespace<commit_after>///
/// @file   Erat.cpp
/// @brief  The Erat class manages prime sieving using the
///         EratSmall, EratMedium, EratBig classes.
///
/// Copyright (C) 2020 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <primesieve/config.hpp>
#include <primesieve/CpuInfo.hpp>
#include <primesieve/Erat.hpp>
#include <primesieve/EratSmall.hpp>
#include <primesieve/EratMedium.hpp>
#include <primesieve/EratBig.hpp>
#include <primesieve/PreSieve.hpp>
#include <primesieve/pmath.hpp>

#include <stdint.h>
#include <array>
#include <algorithm>
#include <cassert>
#include <memory>

using namespace std;

namespace {

/// unset bits < start
const array<uint8_t, 37> unsetSmaller =
{
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xfe, 0xfe, 0xfe, 0xfe, 0xfc, 0xfc, 0xf8, 0xf8,
  0xf8, 0xf8, 0xf0, 0xf0, 0xe0, 0xe0, 0xe0, 0xe0,
  0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x80, 0x80,
  0x00, 0x00, 0x00, 0x00, 0x00
};

/// unset bits > stop
const array<uint8_t, 37> unsetLarger =
{
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
  0x01, 0x01, 0x01, 0x03, 0x03, 0x07, 0x07, 0x07,
  0x07, 0x0f, 0x0f, 0x1f, 0x1f, 0x1f, 0x1f, 0x3f,
  0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x7f, 0x7f, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff
};

} // namespace

namespace primesieve {

Erat::Erat() = default;

Erat::Erat(uint64_t start, uint64_t stop) :
  start_(start),
  stop_(stop)
{ }

/// @start:     Sieve primes >= start
/// @stop:      Sieve primes <= stop
/// @sieveSize: Sieve size in KiB
/// @preSieve:  Pre-sieve small primes
///
void Erat::init(uint64_t start,
                uint64_t stop,
                uint64_t sieveSize,
                PreSieve& preSieve)
{
  if (start > stop)
    return;

  assert(start >= 7);
  start_ = start;
  stop_ = stop;
  preSieve_ = &preSieve;
  preSieve_->init(start, stop);
  maxPreSieve_ = preSieve_->getMaxPrime();
  initSieve(sieveSize);

  // The 8 bits of each byte of the sieve array correspond to
  // the offsets { 7, 11, 13, 17, 19, 23, 29, 31 }. If we
  // would set dist = sieveSize * 30 we would not include the
  // last bit of the last byte which corresponds to the offset
  // 31. For this reason we set dist = sieveSize * 30 + 6.
  uint64_t rem = byteRemainder(start);
  uint64_t dist = sieveSize_ * 30 + 6;
  segmentLow_ = start_ - rem;
  segmentHigh_ = checkedAdd(segmentLow_, dist);
  segmentHigh_ = min(segmentHigh_, stop);

  initErat();
}

void Erat::initSieve(uint64_t sieveSize)
{
  sieveSize_ = floorPow2(sieveSize);
  sieveSize_ = inBetween(8, sieveSize_, 4096);
  sieveSize_ *= 1024;

  sieve_ = new uint8_t[sieveSize_];
  deleter_.reset(sieve_);
}

void Erat::initErat()
{
  uint64_t sqrtStop = isqrt(stop_);
  uint64_t l1CacheSize = getL1CacheSize();

  maxEratSmall_ = (uint64_t) (l1CacheSize * config::FACTOR_ERATSMALL);
  maxEratMedium_ = (uint64_t) (sieveSize_ * config::FACTOR_ERATMEDIUM);

  if (sqrtStop > maxPreSieve_)
    eratSmall_.init(stop_, l1CacheSize, maxEratSmall_);
  if (sqrtStop > maxEratSmall_)
    eratMedium_.init(stop_, sieveSize_, maxEratMedium_);
  if (sqrtStop > maxEratMedium_)
    eratBig_.init(stop_, sieveSize_, sqrtStop);
}

/// EratMedium and EratBig usually run fastest using a sieve
/// size that matches the CPUs L2 cache size. EratSmall
/// however runs fastest using a sieve size that matches the
/// CPUs L1 cache size. Hence we use a smaller sieve size
/// (L1 cache size) in EratSmall and a larger sieve size (L2
/// cache size) in both EratMedium and EratBig.
///
uint64_t Erat::getL1CacheSize() const
{
  if (!cpuInfo.hasL1Cache())
    return sieveSize_;

  uint64_t size = cpuInfo.l1CacheSize();
  uint64_t minSize = 8 << 10;
  uint64_t maxSize = 4096 << 10;

  size = std::min(size, sieveSize_);
  size = inBetween(minSize, size, maxSize);

  return size;
}

bool Erat::hasNextSegment() const
{
  return segmentLow_ < stop_;
}

uint64_t Erat::byteRemainder(uint64_t n)
{
  n %= 30;
  if (n <= 6) n += 30;
  return n;
}

/// Pre-sieve multiples of small primes e.g. <= 19
/// to speed up the sieve of Eratosthenes
///
void Erat::preSieve()
{
  preSieve_->copy(sieve_, sieveSize_, segmentLow_);

  // unset bits < start
  if (segmentLow_ <= start_)
  {
    if (start_ <= maxPreSieve_)
      sieve_[0] = 0xff;
    uint64_t rem = byteRemainder(start_);
    sieve_[0] &= unsetSmaller[rem];
  }
}

void Erat::crossOff()
{
  if (eratSmall_.enabled())
    eratSmall_.crossOff(sieve_, sieveSize_);
  if (eratMedium_.enabled())
    eratMedium_.crossOff(sieve_, sieveSize_);
  if (eratBig_.enabled())
    eratBig_.crossOff(sieve_);
}

void Erat::sieveSegment()
{
  if (segmentHigh_ == stop_)
    sieveLastSegment();
  else
  {
    preSieve();
    crossOff();

    uint64_t dist = sieveSize_ * 30;
    segmentLow_ = checkedAdd(segmentLow_, dist);
    segmentHigh_ = checkedAdd(segmentHigh_, dist);
    segmentHigh_ = min(segmentHigh_, stop_);
  }
}

void Erat::sieveLastSegment()
{
  uint64_t rem = byteRemainder(stop_);
  uint64_t dist = (stop_ - rem) - segmentLow_;
  sieveSize_ = dist / 30 + 1;

  preSieve();
  crossOff();

  // unset bits > stop
  sieve_[sieveSize_ - 1] &= unsetLarger[rem];

  // unset bytes > stop
  uint64_t bytes = sieveSize_ % 8;
  bytes = (8 - bytes) % 8;
  fill_n(&sieve_[sieveSize_], bytes, (uint8_t) 0);

  segmentLow_ = stop_;
}

} // namespace
<|endoftext|>