<commit_before>/*
 * Android File Transfer for Linux: MTP client for android devices
 * Copyright (C) 2015  Vladimir Menshakov

 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.

 * This program 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 General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "createdirectorydialog.h"
#include "progressdialog.h"
#include "renamedialog.h"
#include "mtpobjectsmodel.h"
#include "fileuploader.h"
#include "utils.h"
#include <mtp/usb/TimeoutException.h>
#include <QDebug>
#include <QSortFilterProxyModel>
#include <QMessageBox>
#include <QKeyEvent>
#include <QFileDialog>
#include <QSettings>
#include <QDir>

MainWindow::MainWindow(QWidget *parent) :
	QMainWindow(parent),
	_ui(new Ui::MainWindow),
	_proxyModel(new QSortFilterProxyModel),
	_objectModel(new MtpObjectsModel()),
	_uploader(new FileUploader(_objectModel, this))
{
	_ui->setupUi(this);
	setWindowIcon(QIcon(":/icons/android-file-transfer.png"));

	_ui->listView->setModel(_proxyModel);

	_proxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
	_proxyModel->sort(0);
	_proxyModel->setDynamicSortFilter(true);

	_objectModel->moveToThread(QApplication::instance()->thread());

	connect(_ui->listView->selectionModel(), SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)), SLOT(onSelectionChanged()));
	connect(_ui->listView, SIGNAL(doubleClicked(QModelIndex)), SLOT(onActivated(QModelIndex)));
	connect(_ui->listView, SIGNAL(customContextMenuRequested(QPoint)), SLOT(showContextMenu(QPoint)));
	connect(_ui->actionBack, SIGNAL(triggered()), SLOT(back()));
	connect(_ui->actionGo_Down, SIGNAL(triggered()), SLOT(down()));
	connect(_ui->actionCreateDirectory, SIGNAL(triggered()), SLOT(createDirectory()));
	connect(_ui->actionUploadDirectory, SIGNAL(triggered()), SLOT(uploadDirectories()));
	connect(_ui->actionUpload_Album, SIGNAL(triggered()), SLOT(uploadAlbum()));
	connect(_ui->actionUpload, SIGNAL(triggered()), SLOT(uploadFiles()));
	connect(_ui->actionRename, SIGNAL(triggered()), SLOT(renameFile()));
	connect(_ui->actionDownload, SIGNAL(triggered()), SLOT(downloadFiles()));
	connect(_ui->actionDelete, SIGNAL(triggered()), SLOT(deleteFiles()));

	//fixme: find out how to specify alternative in designer
	_ui->actionBack->setShortcuts(_ui->actionBack->shortcuts() << QKeySequence("Alt+Up") << QKeySequence("Esc"));
	_ui->actionGo_Down->setShortcuts(_ui->actionGo_Down->shortcuts() << QKeySequence("Alt+Down") << QKeySequence("Enter"));
	_ui->actionRename->setShortcuts(_ui->actionRename->shortcuts() << QKeySequence("F3"));
}

MainWindow::~MainWindow()
{
	delete _ui;
}

void MainWindow::showEvent(QShowEvent *)
{
	if (!_device)
	{
		_device = mtp::Device::Find();
		if (!_device)
		{
			QMessageBox::critical(this, tr("No MTP device found"), tr("No MTP device found"));
			return;
		}

		qDebug() << "device found, opening session...";
		mtp::SessionPtr session;
		static const int MaxAttempts = 3;
		for(int attempt = 0; attempt < MaxAttempts; ++attempt)
		{
			try
			{
				session = _device->OpenSession(1);
				mtp::msg::DeviceInfo di = session->GetDeviceInfo();
				qDebug() << "device info" << fromUtf8(di.Manufacturer) << " " << fromUtf8(di.Model);
				break;
			}
			catch(const mtp::usb::TimeoutException &ex)
			{
				qDebug() << "timed out getting device info: " << ex.what() << ", retrying...";
				if (attempt + 1 == MaxAttempts)
				{
					QMessageBox::critical(this, tr("MTP"), tr("MTP device does not respond"));
					return;
				}
			}
		}

		_objectModel->setSession(session);
		qDebug() << "session opened, starting";
		_proxyModel->setSourceModel(_objectModel);
	}
}

QModelIndex MainWindow::mapIndex(const QModelIndex &index)
{
	return _proxyModel->mapToSource(index);
}

void MainWindow::onActivated ( const QModelIndex & index )
{
	if (_objectModel->enter(mapIndex(index).row()))
		_history.push_back(_objectModel->parentObjectId());
}

void MainWindow::onSelectionChanged()
{
	QModelIndexList rows = _ui->listView->selectionModel()->selectedRows();
	_ui->actionDelete->setEnabled(!rows.empty());
	_ui->actionDownload->setEnabled(!rows.empty());
	_ui->actionRename->setEnabled(rows.size() == 1);
	_ui->actionGo_Down->setEnabled(rows.size() == 1);
}

void MainWindow::downloadFiles()
{
	QItemSelectionModel *selection =_ui->listView->selectionModel();
	QModelIndexList rows = selection->selectedRows();

	QList<quint32> objects;
	for(QModelIndex row : rows)
	{
		row = mapIndex(row);
		objects.push_back(_objectModel->objectIdAt(row.row()));
	}
	downloadFiles(objects);
}

void MainWindow::renameFile()
{
	QItemSelectionModel *selection =_ui->listView->selectionModel();
	QModelIndexList rows = selection->selectedRows();
	if (rows.empty())
		return;

	QModelIndex row = mapIndex(rows.at(0));
	RenameDialog d(_objectModel->data(row).toString(), this);
	int r = d.exec();
	if (r)
		_objectModel->rename(row.row(), d.name());
}

void MainWindow::deleteFiles()
{
	QItemSelectionModel *selection =_ui->listView->selectionModel();
	QModelIndexList rows = selection->selectedRows();
	int r = QMessageBox::question(this,
		tr("Deleting file(s)"),
		tr("Are you sure?"),
		QMessageBox::Yes | QMessageBox::No,
		QMessageBox::No
	);
	if (r != QMessageBox::Yes)
		return;

	MtpObjectList objects;
	for(QModelIndex row : rows)
	{
		row = mapIndex(row);
		objects.push_back(_objectModel->objectIdAt(row.row()));
	}
	_objectModel->deleteObjects(objects);
}

void MainWindow::showContextMenu ( const QPoint & pos )
{
	QItemSelectionModel *selection =_ui->listView->selectionModel();
	QModelIndexList rows = selection->selectedRows();

	QMenu menu(this);
	menu.addAction(_ui->actionCreateDirectory);
	menu.addAction(_ui->actionRename);
	menu.addAction(_ui->actionDownload);
	menu.addAction(_ui->actionDelete);
	menu.exec(_ui->listView->mapToGlobal(pos));
}

void MainWindow::back()
{
	if (_history.empty())
		return;
	_history.pop_back();
	mtp::u32 oid = _history.empty()? mtp::Session::Root: _history.back();
	_objectModel->setParent(oid);
}

void MainWindow::down()
{
	if (_objectModel->enter(mapIndex(_ui->listView->currentIndex()).row()))
		_history.push_back(_objectModel->parentObjectId());
}

void MainWindow::createDirectory()
{
	CreateDirectoryDialog d(this);
	if (d.exec() && !d.name().isEmpty())
		_objectModel->createDirectory(d.name(), false);
}

void MainWindow::uploadFiles(const QStringList &files)
{
	if (files.isEmpty())
		return;

	qDebug() << "uploadFiles " << files;
	_proxyModel->setSourceModel(NULL);
	ProgressDialog progressDialog(this);
	progressDialog.setModal(true);
	progressDialog.setValue(0);

	connect(_uploader, SIGNAL(uploadProgress(float)), &progressDialog, SLOT(setValue(float)));
	connect(_uploader, SIGNAL(uploadSpeed(qint64)), &progressDialog, SLOT(setSpeed(qint64)));
	connect(_uploader, SIGNAL(uploadStarted(QString)), &progressDialog, SLOT(setFilename(QString)));
	connect(_uploader, SIGNAL(finished()), &progressDialog, SLOT(accept()));
	_uploader->upload(files);

	progressDialog.exec();

	_objectModel->moveToThread(QApplication::instance()->thread());
	_proxyModel->setSourceModel(_objectModel);
}

void MainWindow::downloadFiles(const QList<quint32> &objects)
{
	if (objects.isEmpty())
		return;

	QString path = QFileDialog::getExistingDirectory(this, tr("Enter destination directory"));
	if (path.isEmpty())
		return;

	qDebug() << "downloading to " << path;
	ProgressDialog progressDialog(this);
	progressDialog.show();

	connect(_uploader, SIGNAL(uploadProgress(float)), &progressDialog, SLOT(setValue(float)));
	connect(_uploader, SIGNAL(uploadSpeed(qint64)), &progressDialog, SLOT(setSpeed(qint64)));
	connect(_uploader, SIGNAL(uploadStarted(QString)), &progressDialog, SLOT(setFilename(QString)));
	connect(_uploader, SIGNAL(finished()), &progressDialog, SLOT(accept()));
	_uploader->download(path, objects);

	progressDialog.exec();
}

void MainWindow::uploadFiles()
{
	QFileDialog d(this);

	QSettings settings;
	{
		QVariant ld = settings.value("the-latest-directory");
		if (ld.isValid())
			d.setDirectory(ld.toString());
	}

	d.setAcceptMode(QFileDialog::AcceptOpen);
	d.setFileMode(QFileDialog::ExistingFiles);
	d.setOption(QFileDialog::ShowDirsOnly, false);
	d.exec();

	settings.setValue("the-latest-directory", d.directory().absolutePath());

	uploadFiles(d.selectedFiles());
}

void MainWindow::uploadDirectories()
{
	QSettings settings;
	QString dirPath;
	{
		QVariant ld = settings.value("the-latest-directory");
		if (ld.isValid())
			dirPath = ld.toString();
	}

	dirPath = QFileDialog::getExistingDirectory(this, "Upload Directories", dirPath);
	if (dirPath.isEmpty())
		return;

	settings.setValue("the-latest-directory", dirPath);

	QDir dir(dirPath);
	qDebug() << "adding directory " << dir.dirName();
	mtp::u32 dirId = _objectModel->createDirectory(dir.dirName(), false);
	_objectModel->setParent(dirId);
	_history.push_back(dirId);

	QStringList files;
	for(QString file : dir.entryList(QDir::Files))
	{
		files.push_back(dir.canonicalPath() + "/" + file);
	}
	uploadFiles(files);
	back();
}

void MainWindow::uploadAlbum()
{
	QString dirPath;
	QSettings settings;
	{
		QVariant ld = settings.value("the-latest-directory");
		if (ld.isValid())
			dirPath = ld.toString();
	}

	dirPath = QFileDialog::getExistingDirectory(this, "Upload Album", dirPath);
	if (!dirPath.isEmpty()) {
		settings.setValue("the-latest-directory", dirPath);
		uploadAlbum(dirPath);
		back();
	}
}

namespace
{
	int GetScore(const QString &str_)
	{
		QString str = str_.toLower();
		int score = 0;
		if (str.contains("art"))
			score += 1;
		if (str.contains("album"))
			score += 1;
		if (str.contains("large"))
			score += 2;
		if (str.contains("small"))
			score += 1;
		if (str.contains("folder"))
			score += 1;
		return score;
	}

	bool HeuristicLess(const QString &s1, const QString &s2)
	{
		return GetScore(s1) > GetScore(s2);
	}
}

void MainWindow::uploadAlbum(QString dirPath)
{
	QDir dir(dirPath);
	qDebug() << "adding directory " << dir.dirName();

	mtp::u32 dirId = _objectModel->createDirectory(dir.dirName(), true);
	_objectModel->setParent(dirId);
	_history.push_back(dirId);

	QString cover, coverTarget;
	QStringList covers;
	{
		QStringList ext({"*.png", "*.jpg", "*.jpeg"});
		covers = dir.entryList(ext, QDir::Files);
		qSort(covers.begin(), covers.end(), &HeuristicLess);
		qDebug() << "covers" << covers;
		if (!covers.isEmpty())
			cover = covers.front();

		if (cover.endsWith(".png"))
			coverTarget = "albumart.png";
		else
			coverTarget = "albumart.jpg";

		qDebug() << "use " << cover << " as album art -> " << coverTarget;
	}

	_objectModel->uploadFile(dir.canonicalPath() + "/" + cover, coverTarget);

	QStringList files;
	for(QString file : dir.entryList(QDir::Files))
	{
		if (!covers.contains(file))
			files.push_back(dir.canonicalPath() + "/" + file);
	}
	uploadFiles(files);
}
<commit_msg>delete objectmodel before main window exits<commit_after>/*
 * Android File Transfer for Linux: MTP client for android devices
 * Copyright (C) 2015  Vladimir Menshakov

 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.

 * This program 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 General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "createdirectorydialog.h"
#include "progressdialog.h"
#include "renamedialog.h"
#include "mtpobjectsmodel.h"
#include "fileuploader.h"
#include "utils.h"
#include <mtp/usb/TimeoutException.h>
#include <QDebug>
#include <QSortFilterProxyModel>
#include <QMessageBox>
#include <QKeyEvent>
#include <QFileDialog>
#include <QSettings>
#include <QDir>

MainWindow::MainWindow(QWidget *parent) :
	QMainWindow(parent),
	_ui(new Ui::MainWindow),
	_proxyModel(new QSortFilterProxyModel),
	_objectModel(new MtpObjectsModel()),
	_uploader(new FileUploader(_objectModel, this))
{
	_ui->setupUi(this);
	setWindowIcon(QIcon(":/icons/android-file-transfer.png"));

	_ui->listView->setModel(_proxyModel);

	_proxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
	_proxyModel->sort(0);
	_proxyModel->setDynamicSortFilter(true);

	_objectModel->moveToThread(QApplication::instance()->thread());

	connect(_ui->listView->selectionModel(), SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)), SLOT(onSelectionChanged()));
	connect(_ui->listView, SIGNAL(doubleClicked(QModelIndex)), SLOT(onActivated(QModelIndex)));
	connect(_ui->listView, SIGNAL(customContextMenuRequested(QPoint)), SLOT(showContextMenu(QPoint)));
	connect(_ui->actionBack, SIGNAL(triggered()), SLOT(back()));
	connect(_ui->actionGo_Down, SIGNAL(triggered()), SLOT(down()));
	connect(_ui->actionCreateDirectory, SIGNAL(triggered()), SLOT(createDirectory()));
	connect(_ui->actionUploadDirectory, SIGNAL(triggered()), SLOT(uploadDirectories()));
	connect(_ui->actionUpload_Album, SIGNAL(triggered()), SLOT(uploadAlbum()));
	connect(_ui->actionUpload, SIGNAL(triggered()), SLOT(uploadFiles()));
	connect(_ui->actionRename, SIGNAL(triggered()), SLOT(renameFile()));
	connect(_ui->actionDownload, SIGNAL(triggered()), SLOT(downloadFiles()));
	connect(_ui->actionDelete, SIGNAL(triggered()), SLOT(deleteFiles()));

	//fixme: find out how to specify alternative in designer
	_ui->actionBack->setShortcuts(_ui->actionBack->shortcuts() << QKeySequence("Alt+Up") << QKeySequence("Esc"));
	_ui->actionGo_Down->setShortcuts(_ui->actionGo_Down->shortcuts() << QKeySequence("Alt+Down") << QKeySequence("Enter"));
	_ui->actionRename->setShortcuts(_ui->actionRename->shortcuts() << QKeySequence("F3"));
}

MainWindow::~MainWindow()
{
	_proxyModel->setSourceModel(NULL);
	delete _objectModel;
	delete _ui;
}

void MainWindow::showEvent(QShowEvent *)
{
	if (!_device)
	{
		_device = mtp::Device::Find();
		if (!_device)
		{
			QMessageBox::critical(this, tr("No MTP device found"), tr("No MTP device found"));
			return;
		}

		qDebug() << "device found, opening session...";
		mtp::SessionPtr session;
		static const int MaxAttempts = 3;
		for(int attempt = 0; attempt < MaxAttempts; ++attempt)
		{
			try
			{
				session = _device->OpenSession(1);
				mtp::msg::DeviceInfo di = session->GetDeviceInfo();
				qDebug() << "device info" << fromUtf8(di.Manufacturer) << " " << fromUtf8(di.Model);
				break;
			}
			catch(const mtp::usb::TimeoutException &ex)
			{
				qDebug() << "timed out getting device info: " << ex.what() << ", retrying...";
				if (attempt + 1 == MaxAttempts)
				{
					QMessageBox::critical(this, tr("MTP"), tr("MTP device does not respond"));
					return;
				}
			}
		}

		_objectModel->setSession(session);
		qDebug() << "session opened, starting";
		_proxyModel->setSourceModel(_objectModel);
	}
}

QModelIndex MainWindow::mapIndex(const QModelIndex &index)
{
	return _proxyModel->mapToSource(index);
}

void MainWindow::onActivated ( const QModelIndex & index )
{
	if (_objectModel->enter(mapIndex(index).row()))
		_history.push_back(_objectModel->parentObjectId());
}

void MainWindow::onSelectionChanged()
{
	QModelIndexList rows = _ui->listView->selectionModel()->selectedRows();
	_ui->actionDelete->setEnabled(!rows.empty());
	_ui->actionDownload->setEnabled(!rows.empty());
	_ui->actionRename->setEnabled(rows.size() == 1);
	_ui->actionGo_Down->setEnabled(rows.size() == 1);
}

void MainWindow::downloadFiles()
{
	QItemSelectionModel *selection =_ui->listView->selectionModel();
	QModelIndexList rows = selection->selectedRows();

	QList<quint32> objects;
	for(QModelIndex row : rows)
	{
		row = mapIndex(row);
		objects.push_back(_objectModel->objectIdAt(row.row()));
	}
	downloadFiles(objects);
}

void MainWindow::renameFile()
{
	QItemSelectionModel *selection =_ui->listView->selectionModel();
	QModelIndexList rows = selection->selectedRows();
	if (rows.empty())
		return;

	QModelIndex row = mapIndex(rows.at(0));
	RenameDialog d(_objectModel->data(row).toString(), this);
	int r = d.exec();
	if (r)
		_objectModel->rename(row.row(), d.name());
}

void MainWindow::deleteFiles()
{
	QItemSelectionModel *selection =_ui->listView->selectionModel();
	QModelIndexList rows = selection->selectedRows();
	int r = QMessageBox::question(this,
		tr("Deleting file(s)"),
		tr("Are you sure?"),
		QMessageBox::Yes | QMessageBox::No,
		QMessageBox::No
	);
	if (r != QMessageBox::Yes)
		return;

	MtpObjectList objects;
	for(QModelIndex row : rows)
	{
		row = mapIndex(row);
		objects.push_back(_objectModel->objectIdAt(row.row()));
	}
	_objectModel->deleteObjects(objects);
}

void MainWindow::showContextMenu ( const QPoint & pos )
{
	QItemSelectionModel *selection =_ui->listView->selectionModel();
	QModelIndexList rows = selection->selectedRows();

	QMenu menu(this);
	menu.addAction(_ui->actionCreateDirectory);
	menu.addAction(_ui->actionRename);
	menu.addAction(_ui->actionDownload);
	menu.addAction(_ui->actionDelete);
	menu.exec(_ui->listView->mapToGlobal(pos));
}

void MainWindow::back()
{
	if (_history.empty())
		return;
	_history.pop_back();
	mtp::u32 oid = _history.empty()? mtp::Session::Root: _history.back();
	_objectModel->setParent(oid);
}

void MainWindow::down()
{
	if (_objectModel->enter(mapIndex(_ui->listView->currentIndex()).row()))
		_history.push_back(_objectModel->parentObjectId());
}

void MainWindow::createDirectory()
{
	CreateDirectoryDialog d(this);
	if (d.exec() && !d.name().isEmpty())
		_objectModel->createDirectory(d.name(), false);
}

void MainWindow::uploadFiles(const QStringList &files)
{
	if (files.isEmpty())
		return;

	qDebug() << "uploadFiles " << files;
	_proxyModel->setSourceModel(NULL);
	ProgressDialog progressDialog(this);
	progressDialog.setModal(true);
	progressDialog.setValue(0);

	connect(_uploader, SIGNAL(uploadProgress(float)), &progressDialog, SLOT(setValue(float)));
	connect(_uploader, SIGNAL(uploadSpeed(qint64)), &progressDialog, SLOT(setSpeed(qint64)));
	connect(_uploader, SIGNAL(uploadStarted(QString)), &progressDialog, SLOT(setFilename(QString)));
	connect(_uploader, SIGNAL(finished()), &progressDialog, SLOT(accept()));
	_uploader->upload(files);

	progressDialog.exec();

	_objectModel->moveToThread(QApplication::instance()->thread());
	_proxyModel->setSourceModel(_objectModel);
}

void MainWindow::downloadFiles(const QList<quint32> &objects)
{
	if (objects.isEmpty())
		return;

	QString path = QFileDialog::getExistingDirectory(this, tr("Enter destination directory"));
	if (path.isEmpty())
		return;

	qDebug() << "downloading to " << path;
	ProgressDialog progressDialog(this);
	progressDialog.show();

	connect(_uploader, SIGNAL(uploadProgress(float)), &progressDialog, SLOT(setValue(float)));
	connect(_uploader, SIGNAL(uploadSpeed(qint64)), &progressDialog, SLOT(setSpeed(qint64)));
	connect(_uploader, SIGNAL(uploadStarted(QString)), &progressDialog, SLOT(setFilename(QString)));
	connect(_uploader, SIGNAL(finished()), &progressDialog, SLOT(accept()));
	_uploader->download(path, objects);

	progressDialog.exec();
}

void MainWindow::uploadFiles()
{
	QFileDialog d(this);

	QSettings settings;
	{
		QVariant ld = settings.value("the-latest-directory");
		if (ld.isValid())
			d.setDirectory(ld.toString());
	}

	d.setAcceptMode(QFileDialog::AcceptOpen);
	d.setFileMode(QFileDialog::ExistingFiles);
	d.setOption(QFileDialog::ShowDirsOnly, false);
	d.exec();

	settings.setValue("the-latest-directory", d.directory().absolutePath());

	uploadFiles(d.selectedFiles());
}

void MainWindow::uploadDirectories()
{
	QSettings settings;
	QString dirPath;
	{
		QVariant ld = settings.value("the-latest-directory");
		if (ld.isValid())
			dirPath = ld.toString();
	}

	dirPath = QFileDialog::getExistingDirectory(this, "Upload Directories", dirPath);
	if (dirPath.isEmpty())
		return;

	settings.setValue("the-latest-directory", dirPath);

	QDir dir(dirPath);
	qDebug() << "adding directory " << dir.dirName();
	mtp::u32 dirId = _objectModel->createDirectory(dir.dirName(), false);
	_objectModel->setParent(dirId);
	_history.push_back(dirId);

	QStringList files;
	for(QString file : dir.entryList(QDir::Files))
	{
		files.push_back(dir.canonicalPath() + "/" + file);
	}
	uploadFiles(files);
	back();
}

void MainWindow::uploadAlbum()
{
	QString dirPath;
	QSettings settings;
	{
		QVariant ld = settings.value("the-latest-directory");
		if (ld.isValid())
			dirPath = ld.toString();
	}

	dirPath = QFileDialog::getExistingDirectory(this, "Upload Album", dirPath);
	if (!dirPath.isEmpty()) {
		settings.setValue("the-latest-directory", dirPath);
		uploadAlbum(dirPath);
		back();
	}
}

namespace
{
	int GetScore(const QString &str_)
	{
		QString str = str_.toLower();
		int score = 0;
		if (str.contains("art"))
			score += 1;
		if (str.contains("album"))
			score += 1;
		if (str.contains("large"))
			score += 2;
		if (str.contains("small"))
			score += 1;
		if (str.contains("folder"))
			score += 1;
		return score;
	}

	bool HeuristicLess(const QString &s1, const QString &s2)
	{
		return GetScore(s1) > GetScore(s2);
	}
}

void MainWindow::uploadAlbum(QString dirPath)
{
	QDir dir(dirPath);
	qDebug() << "adding directory " << dir.dirName();

	mtp::u32 dirId = _objectModel->createDirectory(dir.dirName(), true);
	_objectModel->setParent(dirId);
	_history.push_back(dirId);

	QString cover, coverTarget;
	QStringList covers;
	{
		QStringList ext({"*.png", "*.jpg", "*.jpeg"});
		covers = dir.entryList(ext, QDir::Files);
		qSort(covers.begin(), covers.end(), &HeuristicLess);
		qDebug() << "covers" << covers;
		if (!covers.isEmpty())
			cover = covers.front();

		if (cover.endsWith(".png"))
			coverTarget = "albumart.png";
		else
			coverTarget = "albumart.jpg";

		qDebug() << "use " << cover << " as album art -> " << coverTarget;
	}

	_objectModel->uploadFile(dir.canonicalPath() + "/" + cover, coverTarget);

	QStringList files;
	for(QString file : dir.entryList(QDir::Files))
	{
		if (!covers.contains(file))
			files.push_back(dir.canonicalPath() + "/" + file);
	}
	uploadFiles(files);
}
<|endoftext|>


<commit_before>#include "gpgpu/import/load_kernel.hh"

#include <fstream>

#include "logging/assert.hh"
#include "util/environment.hh"

namespace jcc {
namespace {
std::string read_file(const std::string& path) {
  std::ifstream cl_file(path);

  std::string text = "";
  std::string line;
  while (std::getline(cl_file, line)) {
    text += line + "\n";
  }
  return text;
}

cl::Program read_program(const ClInfo& cl_info,
                         const std::string& path,
                         const std::string& include_path) {
  //
  // Read the source code and compile the kernel
  //
  constexpr bool BUILD = false;
  const std::string source = read_file(path);
  cl::Program program(cl_info.context, source, BUILD);

  const std::string demo_incl_path = jcc::Environment::repo_path() + "gpgpu/demos/";
  const std::string kernel_incl_path = jcc::Environment::repo_path() + "gpgpu/kernels/";
  const std::string flags =
      "-cl-std=CL2.0 -I " + demo_incl_path + " -I " + kernel_incl_path;
  program.build({cl_info.device}, flags.c_str());

  //
  // Check program build status
  //
  const auto build_status = program.getBuildInfo<CL_PROGRAM_BUILD_STATUS>(cl_info.device);
  const std::string error =
      "\n" + program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(cl_info.device);
  JASSERT_EQ(build_status, 0, error.c_str());

  return program;
}

}  // namespace

std::map<std::string, cl::Kernel> read_kernels(const ClInfo& cl_info,
                                               const std::string& path,
                                               const std::string& include_path) {
  std::map<std::string, cl::Kernel> kernels;
  auto program = read_program(cl_info, path, include_path);

  std::vector<cl::Kernel> kernels_vec;
  program.createKernels(&kernels_vec);

  for (auto& kernel : kernels_vec) {
    std::string name;
    kernel.getInfo(CL_KERNEL_FUNCTION_NAME, &name);

    // The OpenCL driver includes an extra null-terminator in the string.
    const int last_char = name.find('\0');

    if (last_char != -1) {
      kernels[name.substr(0, last_char)] = kernel;
    } else {
      kernels[name] = kernel;
    }
  }
  return kernels;
}

}  // namespace jcc
<commit_msg>-Wall -Werror for OpenCL kernels<commit_after>#include "gpgpu/import/load_kernel.hh"

#include <fstream>

#include "logging/assert.hh"
#include "util/environment.hh"

namespace jcc {
namespace {
std::string read_file(const std::string& path) {
  std::ifstream cl_file(path);

  std::string text = "";
  std::string line;
  while (std::getline(cl_file, line)) {
    text += line + "\n";
  }
  return text;
}

cl::Program read_program(const ClInfo& cl_info,
                         const std::string& path,
                         const std::string& include_path) {
  //
  // Read the source code and compile the kernel
  //
  constexpr bool BUILD = false;
  const std::string source = read_file(path);
  cl::Program program(cl_info.context, source, BUILD);

  const std::string demo_incl_path = jcc::Environment::repo_path() + "gpgpu/demos/";
  const std::string kernel_incl_path = jcc::Environment::repo_path() + "gpgpu/kernels/";
  const std::string flags =
      "-Werror -cl-std=CL2.0 -I " + demo_incl_path + " -I " + kernel_incl_path;
  program.build({cl_info.device}, flags.c_str());

  //
  // Check program build status
  //
  const auto build_status = program.getBuildInfo<CL_PROGRAM_BUILD_STATUS>(cl_info.device);
  const std::string error =
      "\n" + program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(cl_info.device);
  JASSERT_EQ(build_status, 0, error.c_str());

  return program;
}

}  // namespace

std::map<std::string, cl::Kernel> read_kernels(const ClInfo& cl_info,
                                               const std::string& path,
                                               const std::string& include_path) {
  std::map<std::string, cl::Kernel> kernels;
  auto program = read_program(cl_info, path, include_path);

  std::vector<cl::Kernel> kernels_vec;
  program.createKernels(&kernels_vec);

  for (auto& kernel : kernels_vec) {
    std::string name;
    kernel.getInfo(CL_KERNEL_FUNCTION_NAME, &name);

    // The OpenCL driver includes an extra null-terminator in the string.
    const int last_char = name.find('\0');

    if (last_char != -1) {
      kernels[name.substr(0, last_char)] = kernel;
    } else {
      kernels[name] = kernel;
    }
  }
  return kernels;
}

}  // namespace jcc
<|endoftext|>


<commit_before><commit_msg>array conf: returning default value instead of 0<commit_after><|endoftext|>


<commit_before>/// ParameterGraph.hpp
/// Shaun Harker
/// 2015-05-24

#ifndef DSGRN_PARAMETERGRAPH_HPP
#define DSGRN_PARAMETERGRAPH_HPP

#ifndef INLINE_IF_HEADER_ONLY
#define INLINE_IF_HEADER_ONLY
#endif

#include "ParameterGraph.h"

INLINE_IF_HEADER_ONLY ParameterGraph::
ParameterGraph ( void ) {
  data_ . reset ( new ParameterGraph_ );
}

INLINE_IF_HEADER_ONLY ParameterGraph::
ParameterGraph ( Network const& network, std::string const& path ) {
  assign ( network, path );
}

INLINE_IF_HEADER_ONLY void ParameterGraph::
assign ( Network const& network, std::string const& path ) {
  data_ . reset ( new ParameterGraph_ );
  data_ -> network_ = network;
  data_ -> reorderings_ = 1;
  data_ -> fixedordersize_ = 1;
  // Load the network files one by one.
  uint64_t D = data_ -> network_ . size ();
  for ( uint64_t d = 0; d < D; ++ d ) {
    uint64_t n = data_ -> network_ . inputs ( d ) . size ();
    uint64_t m = data_ -> network_ . outputs ( d ) . size ();
    data_ -> order_place_values_ . push_back ( _factorial ( m ) );
    data_ -> reorderings_ *= data_ -> order_place_values_ . back ();
    std::vector<std::vector<uint64_t>> const& logic_struct = data_ -> network_ . logic ( d );
    std::stringstream ss;
    ss << path << "/" << n <<  "_" << m;
    for ( auto const& p : logic_struct ) ss <<  "_" << p.size();
    if ( data_ -> network_ . essential ( d ) ) ss << "_E";
    ss << ".dat";
    //std::cout << "Acquiring logic data in " << ss.str() << "\n";
    std::vector<std::string> hex_codes;
    std::ifstream infile ( ss.str() );
    if ( not infile . good () ) {
      throw std::runtime_error ( "Error: Could not find logic resource " + ss.str() + ".\n");
    }
    std::string line;
    while ( std::getline ( infile, line ) ) hex_codes . push_back ( line );
    infile . close ();
    data_ -> factors_ . push_back ( hex_codes );
    data_ -> logic_place_values_ . push_back ( hex_codes . size () );
    data_ -> fixedordersize_ *= hex_codes . size ();
    //std::cout << d << ": " << hex_codes . size () << " factorial(" << m << ")=" << _factorial ( m ) << "\n";
  }
  data_ -> size_ = data_ -> fixedordersize_ * data_ -> reorderings_;
}

INLINE_IF_HEADER_ONLY uint64_t ParameterGraph::
size ( void ) const {
  return data_ -> size_;
}

INLINE_IF_HEADER_ONLY Parameter ParameterGraph::
parameter ( uint64_t index ) const {
  //std::cout << data_ -> "ParameterGraph::parameter( " << index << " )\n";
  if ( index >= size () ) {
    throw std::runtime_error ( "ParameterGraph::parameter Index out of bounds");
  }
  uint64_t logic_index = index % data_ -> fixedordersize_;
  uint64_t order_index = index / data_ -> fixedordersize_;
  //std::cout << "Logic index = " << logic_index << "\n";
  //std::cout << "Order index = " << order_index << "\n";

  uint64_t D = data_ -> network_ . size ();
  std::vector<uint64_t> logic_indices;
  for ( uint64_t d = 0; d < D; ++ d ) {
    uint64_t i = logic_index % data_ -> logic_place_values_ [ d ];
    logic_index /= data_ -> logic_place_values_ [ d ];
    logic_indices . push_back ( i );
  }
  std::vector<uint64_t> order_indices;
  for ( uint64_t d = 0; d < D; ++ d ) {
    uint64_t i = order_index % data_ -> order_place_values_ [ d ];
    order_index /= data_ -> order_place_values_ [ d ];
    order_indices . push_back ( i );
  }
  std::vector<LogicParameter> logic;
  std::vector<OrderParameter> order;
  for ( uint64_t d = 0; d < D; ++ d ) {
    uint64_t n = data_ -> network_ . inputs ( d ) . size ();
    uint64_t m = data_ -> network_ . outputs ( d ) . size ();
    std::string hex_code = data_ -> factors_ [ d ] [ logic_indices[d] ];
    LogicParameter logic_param ( n, m, hex_code );
    OrderParameter order_param ( m, order_indices[d] );
    logic . push_back ( logic_param );
    order . push_back ( order_param );
  }
  Parameter result ( logic, order, data_ -> network_ );
  return result;
}

INLINE_IF_HEADER_ONLY uint64_t ParameterGraph::
index ( Parameter const& p ) const {
//   throw std::runtime_error ( "Feature not implemented" );  // TODO

  std::vector<LogicParameter> logic = p . logic ( );
  std::vector<OrderParameter> order = p . order ( );

  /// Construct Logic indices
  std::vector<uint64_t> logic_indices;
  uint64_t D = data_ -> network_ . size ();
  for ( uint64_t d = 0; d< D; ++d ) {
      std::string hexcode = logic [ d ] . hex ( );
      /// If factors_ was a different container, we could use find instead
      /// find the hex code within factors_ for the appropriate node
      uint64_t hexsize = data_ -> factors_ [ d ] . size ( );
      for ( uint64_t i = 0; i < hexsize; ++i ) {
          if ( hexcode == data_ -> factors_ [ d ] [ i ] ) {
              logic_indices . push_back ( i );
          }
      }
  }
  // debug
  std::cout << "\nLogic indices:\n";
  for ( uint64_t d = 0; d< D; ++d ) std::cout << logic_indices[d] << " ";
  std::cout << "\n";
  // end debug

  /// Construct Order indices
  std::vector<uint64_t> order_indices;
  for ( uint64_t d = 0; d < D; ++ d ) {
      order_indices . push_back ( order[d].index() );
  }
  // debug
  std::cout << "\nOrder indices:\n";
  for ( uint64_t d = 0; d< D; ++d ) std::cout << order_indices[d] << " ";
  std::cout << "\n";
  // end debug

  // Debug
  std::cout << "\n\n";
  std::cout << "Logic_place_values : ";
  for ( uint64_t d = 0; d< D; ++d ) std::cout << data_ -> logic_place_values_[d] << " ";
  std::cout << "\n";
  std::cout << "Order_place_values : ";
  for ( uint64_t d = 0; d< D; ++d ) std::cout << data_ -> order_place_values_[d] << " ";
  std::cout << "\n";
  std::cout << "Fixed order size : " << data_ -> fixedordersize_;
  std::cout << "\n\n";
  // end debug

  /// Return : m * Q + R
  auto getInteger = []( const uint64_t &m, const uint64_t &Q, const uint64_t &R ) -> uint64_t {
      return m * Q + R;
  };

  typedef std::vector<uint64_t> Interval;
  /// Return interval of the form : [ m*n*k+m*a, m*n*k+m*a+m )
  auto getInterval = [](uint64_t &k, uint64_t &m, uint64_t &n, uint64_t &a ) -> std::vector<uint64_t>  {
      return std::vector<uint64_t> { m*n*k+m*a,m*n*k+m*a+m };
  };

  auto insideInterval = [](uint64_t &n, Interval &interval) -> bool {
    return n>=interval[0] && n<=interval[1];
  };

  // List all the subintervals for logic_index and store the potential good values for logic index
  std::cout << "\n\nList of all subintervals for logic index\n";
  std::vector<Interval> intervals; // needed just for debug
  std::vector<uint64_t> logicindexvalues;
  for ( uint64_t R = 0; R<data_->reorderings_; ++R ) {
      Interval interval = getInterval( R,
                                       data_ -> logic_place_values_[0],
                                       data_ -> logic_place_values_[1],
                                       logic_indices[1] );
      std::cout << "[ " << interval[0] << ", " << interval[1] << " ]\n";
      intervals . push_back ( interval );
      /// check for good values inside the interval
      uint64_t myvalue = getInteger(data_ -> logic_place_values_[0],
                                    R*data_ -> logic_place_values_[1]+logic_indices[1],
                                    logic_indices[0]);
      std::cout << "value=" << myvalue << " ";
      if ( insideInterval(myvalue,interval) ) {
          std::cout << "is good\n";
          logicindexvalues . push_back ( myvalue );
      } else {
          std::cout << "is bad\n";
      }
  }
  // List all the subintervals for order_index and store the potential good values for order index

  return 0;

}

INLINE_IF_HEADER_ONLY std::vector<uint64_t> ParameterGraph::
adjacencies ( uint64_t index ) const {
  throw std::runtime_error ( "Feature not implemented" );   //TODO
}

INLINE_IF_HEADER_ONLY Network const ParameterGraph::
network ( void ) const {
  return data_ -> network_;
}

INLINE_IF_HEADER_ONLY std::ostream& operator << ( std::ostream& stream, ParameterGraph const& pg ) {
  stream <<  "(ParameterGraph: "<< pg.size() << " parameters, "
         << pg.network().size() << " nodes)";
  return stream;
}

INLINE_IF_HEADER_ONLY uint64_t ParameterGraph::
fixedordersize ( void ) const {
  return data_ -> fixedordersize_;
}

INLINE_IF_HEADER_ONLY uint64_t ParameterGraph::
reorderings ( void ) const {
  return data_ -> reorderings_;
}

INLINE_IF_HEADER_ONLY uint64_t ParameterGraph::
_factorial ( uint64_t m ) const {
  static const std::vector<uint64_t> table =
    { 1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880};
  if ( m < 10 ) return table [ m ]; else return m * _factorial ( m - 1 );
}

#endif
<commit_msg>[WIP] code clean up<commit_after>/// ParameterGraph.hpp
/// Shaun Harker
/// 2015-05-24

#ifndef DSGRN_PARAMETERGRAPH_HPP
#define DSGRN_PARAMETERGRAPH_HPP

#ifndef INLINE_IF_HEADER_ONLY
#define INLINE_IF_HEADER_ONLY
#endif

#include "ParameterGraph.h"

INLINE_IF_HEADER_ONLY ParameterGraph::
ParameterGraph ( void ) {
  data_ . reset ( new ParameterGraph_ );
}

INLINE_IF_HEADER_ONLY ParameterGraph::
ParameterGraph ( Network const& network, std::string const& path ) {
  assign ( network, path );
}

INLINE_IF_HEADER_ONLY void ParameterGraph::
assign ( Network const& network, std::string const& path ) {
  data_ . reset ( new ParameterGraph_ );
  data_ -> network_ = network;
  data_ -> reorderings_ = 1;
  data_ -> fixedordersize_ = 1;
  // Load the network files one by one.
  uint64_t D = data_ -> network_ . size ();
  for ( uint64_t d = 0; d < D; ++ d ) {
    uint64_t n = data_ -> network_ . inputs ( d ) . size ();
    uint64_t m = data_ -> network_ . outputs ( d ) . size ();
    data_ -> order_place_values_ . push_back ( _factorial ( m ) );
    data_ -> reorderings_ *= data_ -> order_place_values_ . back ();
    std::vector<std::vector<uint64_t>> const& logic_struct = data_ -> network_ . logic ( d );
    std::stringstream ss;
    ss << path << "/" << n <<  "_" << m;
    for ( auto const& p : logic_struct ) ss <<  "_" << p.size();
    if ( data_ -> network_ . essential ( d ) ) ss << "_E";
    ss << ".dat";
    //std::cout << "Acquiring logic data in " << ss.str() << "\n";
    std::vector<std::string> hex_codes;
    std::ifstream infile ( ss.str() );
    if ( not infile . good () ) {
      throw std::runtime_error ( "Error: Could not find logic resource " + ss.str() + ".\n");
    }
    std::string line;
    while ( std::getline ( infile, line ) ) hex_codes . push_back ( line );
    infile . close ();
    data_ -> factors_ . push_back ( hex_codes );
    data_ -> logic_place_values_ . push_back ( hex_codes . size () );
    data_ -> fixedordersize_ *= hex_codes . size ();
    //std::cout << d << ": " << hex_codes . size () << " factorial(" << m << ")=" << _factorial ( m ) << "\n";
  }
  data_ -> size_ = data_ -> fixedordersize_ * data_ -> reorderings_;
}

INLINE_IF_HEADER_ONLY uint64_t ParameterGraph::
size ( void ) const {
  return data_ -> size_;
}

INLINE_IF_HEADER_ONLY Parameter ParameterGraph::
parameter ( uint64_t index ) const {
  //std::cout << data_ -> "ParameterGraph::parameter( " << index << " )\n";
  if ( index >= size () ) {
    throw std::runtime_error ( "ParameterGraph::parameter Index out of bounds");
  }
  uint64_t logic_index = index % data_ -> fixedordersize_;
  uint64_t order_index = index / data_ -> fixedordersize_;
  //std::cout << "Logic index = " << logic_index << "\n";
  //std::cout << "Order index = " << order_index << "\n";

  uint64_t D = data_ -> network_ . size ();
  std::vector<uint64_t> logic_indices;
  for ( uint64_t d = 0; d < D; ++ d ) {
    uint64_t i = logic_index % data_ -> logic_place_values_ [ d ];
    logic_index /= data_ -> logic_place_values_ [ d ];
    logic_indices . push_back ( i );
  }
  std::vector<uint64_t> order_indices;
  for ( uint64_t d = 0; d < D; ++ d ) {
    uint64_t i = order_index % data_ -> order_place_values_ [ d ];
    order_index /= data_ -> order_place_values_ [ d ];
    order_indices . push_back ( i );
  }
  std::vector<LogicParameter> logic;
  std::vector<OrderParameter> order;
  for ( uint64_t d = 0; d < D; ++ d ) {
    uint64_t n = data_ -> network_ . inputs ( d ) . size ();
    uint64_t m = data_ -> network_ . outputs ( d ) . size ();
    std::string hex_code = data_ -> factors_ [ d ] [ logic_indices[d] ];
    LogicParameter logic_param ( n, m, hex_code );
    OrderParameter order_param ( m, order_indices[d] );
    logic . push_back ( logic_param );
    order . push_back ( order_param );
  }
  Parameter result ( logic, order, data_ -> network_ );
  return result;
}

INLINE_IF_HEADER_ONLY uint64_t ParameterGraph::
index ( Parameter const& p ) const {
//   throw std::runtime_error ( "Feature not implemented" );  // TODO

  std::vector<LogicParameter> logic = p . logic ( );
  std::vector<OrderParameter> order = p . order ( );

  /// Construct Logic indices
  std::vector<uint64_t> logic_indices;
  uint64_t D = data_ -> network_ . size ();
  for ( uint64_t d = 0; d< D; ++d ) {
      std::string hexcode = logic [ d ] . hex ( );
      /// If factors_ was a different container, we could use find instead
      /// find the hex code within factors_ for the appropriate node
      uint64_t hexsize = data_ -> factors_ [ d ] . size ( );
      for ( uint64_t i = 0; i < hexsize; ++i ) {
          if ( hexcode == data_ -> factors_ [ d ] [ i ] ) {
              logic_indices . push_back ( i );
          }
      }
  }
  // debug
  std::cout << "\nLogic indices:\n";
  for ( uint64_t d = 0; d< D; ++d ) std::cout << logic_indices[d] << " ";
  std::cout << "\n";
  // end debug

  /// Construct Order indices
  std::vector<uint64_t> order_indices;
  for ( uint64_t d = 0; d < D; ++ d ) {
      order_indices . push_back ( order[d].index() );
  }
  // debug
  std::cout << "\nOrder indices:\n";
  for ( uint64_t d = 0; d< D; ++d ) std::cout << order_indices[d] << " ";
  std::cout << "\n";
  // end debug

  // Debug
  std::cout << "\n\n";
  std::cout << "Logic_place_values : ";
  for ( uint64_t d = 0; d< D; ++d ) std::cout << data_ -> logic_place_values_[d] << " ";
  std::cout << "\n";
  std::cout << "Order_place_values : ";
  for ( uint64_t d = 0; d< D; ++d ) std::cout << data_ -> order_place_values_[d] << " ";
  std::cout << "\n";
  std::cout << "Fixed order size : " << data_ -> fixedordersize_;
  std::cout << "\n\n";
  // end debug

  /// Return : m * Q + R
  auto getInteger = []( const uint64_t &m, const uint64_t &Q, const uint64_t &R ) -> uint64_t {
      return m * Q + R;
  };

  typedef std::vector<uint64_t> Interval;

  /// Return interval of the form : [ m*n*k+m*a, m*n*k+m*a+m )
  auto getInterval = [](uint64_t &k, uint64_t &m, uint64_t &n, uint64_t &a ) -> Interval  {
      return Interval { m*n*k+m*a,m*n*k+m*a+m };
  };

  auto insideInterval = [](uint64_t &n, Interval &interval) -> bool {
    return n>=interval[0] && n<=interval[1];
  };

  // List all the subintervals for logic_index and store the potential good values for logic index
  std::cout << "\n\nList of all subintervals for logic index\n";
  std::vector<Interval> intervals; // needed just for debug
  std::vector<uint64_t> logicindexvalues;
  for ( uint64_t R = 0; R<data_->reorderings_; ++R ) {
      Interval interval = getInterval( R,
                                       data_ -> logic_place_values_[0],
                                       data_ -> logic_place_values_[1],
                                       logic_indices[1] );
      std::cout << "[ " << interval[0] << ", " << interval[1] << " ]\n";
      intervals . push_back ( interval );
      /// check for good values inside the interval
      uint64_t myvalue = getInteger(data_ -> logic_place_values_[0],
                                    R*data_ -> logic_place_values_[1]+logic_indices[1],
                                    logic_indices[0]);
      std::cout << "value=" << myvalue << " ";
      if ( insideInterval(myvalue,interval) ) {
          std::cout << "is good\n";
          logicindexvalues . push_back ( myvalue );
      } else {
          std::cout << "is bad\n";
      }
  }
  // List all the subintervals for order_index and store the potential good values for order index

  return 0;

}

INLINE_IF_HEADER_ONLY std::vector<uint64_t> ParameterGraph::
adjacencies ( uint64_t index ) const {
  throw std::runtime_error ( "Feature not implemented" );   //TODO
}

INLINE_IF_HEADER_ONLY Network const ParameterGraph::
network ( void ) const {
  return data_ -> network_;
}

INLINE_IF_HEADER_ONLY std::ostream& operator << ( std::ostream& stream, ParameterGraph const& pg ) {
  stream <<  "(ParameterGraph: "<< pg.size() << " parameters, "
         << pg.network().size() << " nodes)";
  return stream;
}

INLINE_IF_HEADER_ONLY uint64_t ParameterGraph::
fixedordersize ( void ) const {
  return data_ -> fixedordersize_;
}

INLINE_IF_HEADER_ONLY uint64_t ParameterGraph::
reorderings ( void ) const {
  return data_ -> reorderings_;
}

INLINE_IF_HEADER_ONLY uint64_t ParameterGraph::
_factorial ( uint64_t m ) const {
  static const std::vector<uint64_t> table =
    { 1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880};
  if ( m < 10 ) return table [ m ]; else return m * _factorial ( m - 1 );
}

#endif
<|endoftext|>


<commit_before>#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/objdetect/objdetect.hpp"
#include <opencv2/opencv.hpp>

#include <iostream>
#include <iomanip>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <time.h>
#include <math.h>

using namespace std;
using namespace cv;
RNG rng(12345);
int main(int argc, char *argv[])
{
    VideoCapture image(argv[1]);
    string filename = argv[1];
    auto pos = filename.rfind('/');
    if (pos != std::string::npos)
    {
        filename.erase(0, pos + 1);
    }
    string output_dir = argv[2];
    Vec3b red = Vec3b(0,0,255);
    float dx = .17;
    float dy = .17;
    float ds[5] = {.83, .91, 1.0, 1.10, 1.21};
    string dir_name = "";
    Mat original;
    Mat copy;
    Mat final;
    image >> original;
    int expand = original.rows * dx / 2;
    for (int is = 0; is < 5; is++)
    {
        for (int ix = 0; ix < 3; ix++)
        {
            for (int iy = 0; iy < 3; iy++)
            {
                original.copyTo(copy);
                original.copyTo(final);
                dir_name = to_string(is*9 + ix*3 + iy);
                Rect ROI = Rect(0,0,copy.cols,copy.rows);
                if (ix == 0)
                {
                    copyMakeBorder(copy, copy, 0, 0, 0, expand, BORDER_CONSTANT, Scalar(0,0,255));
                    ROI = Rect(Point(expand,0), Point(copy.cols, ROI.br().y));
                }
                if (ix == 2)
                {
                    copyMakeBorder(copy, copy, 0, 0, expand, 0, BORDER_CONSTANT, Scalar(0,0,255));
                }
                if (iy == 0)
                {
                    copyMakeBorder(copy, copy, 0, expand, 0, 0, BORDER_CONSTANT, Scalar(0,0,255));
                    ROI = Rect(Point(ROI.tl().x, expand), Point(ROI.br().x, copy.rows));
                }
                if (iy == 2)
                {
                    copyMakeBorder(copy, copy, expand, 0, 0, 0, BORDER_CONSTANT, Scalar(0,0,255));
                }
                Mat copy1;
                copy1 = copy(ROI).clone();
                Mat copy2;
                if (is < 2)
                {
                    int resize_val = (copy1.rows - copy1.rows * sqrt(ds[is]));
                    copyMakeBorder(copy1, copy1, resize_val, resize_val, resize_val, resize_val, BORDER_CONSTANT, Scalar(0,0,255));
                    resize(copy1, final, final.size(), 0, 0, INTER_NEAREST);
                }
                else if (is > 2)
                {
                    int resize_val = (copy1.rows * sqrt(ds[is]) - copy1.rows);
                    ROI = Rect(Point(resize_val, resize_val), Point(copy1.cols - resize_val, copy1.rows - resize_val));
                    copy2 = copy1(ROI).clone();
                    resize(copy2, final, final.size(), 0, 0, INTER_NEAREST);
                }
                else
                {
                    copy1.copyTo(final);
                }
                string write_file = output_dir + "/" + dir_name + "/" + filename;
                for(int i = 0; i < final.rows; i++)
                {
                    for(int j = 0; j < final.cols; j++)
                    {
                        if(final.at<Vec3b>(i,j) == red)
                        {
                            final.at<Vec3b>(i,j) = Vec3b(rng.uniform(0,255), rng.uniform(0,255), rng.uniform(0,255));
                        }
                    }
                }
                //imshow("Final", final);
                bool truth = imwrite(write_file, final);
                if(truth == false)
                {
                    cout << "Error! Could not write file." << endl;
                }
                //waitKey(1000);
            }
        }
    }
}
<commit_msg>Read from PNG file, create dirs if not there<commit_after>#include <opencv2/opencv.hpp>

#include <iostream>
#include <iomanip>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <time.h>
#include <math.h>

using namespace std;
using namespace cv;
RNG rng(12345);
int main(int argc, char *argv[])
{
    string filename = argv[1];
    auto pos = filename.rfind('/');
    if (pos != std::string::npos)
    {
        filename.erase(0, pos + 1);
    }
    string output_dir = argv[2];
    Vec3b red = Vec3b(0,0,255);
    float dx = .17;
    float dy = .17;
    float ds[5] = {.83, .91, 1.0, 1.10, 1.21};
    string dir_name = "";
    Mat original = imread(argv[1], CV_LOAD_IMAGE_COLOR);
    Mat copy;
    Mat final;
    int expand = original.rows * dx / 2;
    for (int is = 0; is < 5; is++)
    {
        for (int ix = 0; ix < 3; ix++)
        {
            for (int iy = 0; iy < 3; iy++)
            {
                original.copyTo(copy);
                original.copyTo(final);
                dir_name = to_string(is*9 + ix*3 + iy);
                Rect ROI = Rect(0,0,copy.cols,copy.rows);
                if (ix == 0)
                {
                    copyMakeBorder(copy, copy, 0, 0, 0, expand, BORDER_CONSTANT, Scalar(0,0,255));
                    ROI = Rect(Point(expand,0), Point(copy.cols, ROI.br().y));
                }
                if (ix == 2)
                {
                    copyMakeBorder(copy, copy, 0, 0, expand, 0, BORDER_CONSTANT, Scalar(0,0,255));
                }
                if (iy == 0)
                {
                    copyMakeBorder(copy, copy, 0, expand, 0, 0, BORDER_CONSTANT, Scalar(0,0,255));
                    ROI = Rect(Point(ROI.tl().x, expand), Point(ROI.br().x, copy.rows));
                }
                if (iy == 2)
                {
                    copyMakeBorder(copy, copy, expand, 0, 0, 0, BORDER_CONSTANT, Scalar(0,0,255));
                }
                Mat copy1;
                copy1 = copy(ROI).clone();
                Mat copy2;
                if (is < 2)
                {
                    int resize_val = (copy1.rows - copy1.rows * sqrt(ds[is]));
                    copyMakeBorder(copy1, copy1, resize_val, resize_val, resize_val, resize_val, BORDER_CONSTANT, Scalar(0,0,255));
                    resize(copy1, final, final.size(), 0, 0, INTER_NEAREST);
                }
                else if (is > 2)
                {
                    int resize_val = (copy1.rows * sqrt(ds[is]) - copy1.rows);
                    ROI = Rect(Point(resize_val, resize_val), Point(copy1.cols - resize_val, copy1.rows - resize_val));
                    copy2 = copy1(ROI).clone();
                    resize(copy2, final, final.size(), 0, 0, INTER_NEAREST);
                }
                else
                {
                    copy1.copyTo(final);
                }
				if (mkdir((output_dir+"/"+dir_name).c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH))
				{
					if (errno != EEXIST)
					{
						cerr << "Could not create " << (output_dir+"/"+dir_name).c_str() << ":";
						perror("");
					}
				}

                string write_file = output_dir + "/" + dir_name + "/" + filename;
                for(int i = 0; i < final.rows; i++)
                {
                    for(int j = 0; j < final.cols; j++)
                    {
                        if(final.at<Vec3b>(i,j) == red)
                        {
                            final.at<Vec3b>(i,j) = Vec3b(rng.uniform(0,255), rng.uniform(0,255), rng.uniform(0,255));
                        }
                    }
                }
                //imshow("Final", final);
				resize (final, final, Size(24,24));
                bool truth = imwrite(write_file, final);
                if(truth == false)
                {
                    cout << "Error! Could not write file "<<  write_file << endl;
                }
                //waitKey(1000);
            }
        }
    }
}
<|endoftext|>


<commit_before>#ifndef ALEPH_TOPOLOGY_IO_GRAPHML_HH__
#define ALEPH_TOPOLOGY_IO_GRAPHML_HH__

#include <aleph/config/TinyXML2.hh>

#include <aleph/utilities/String.hh>

#ifdef ALEPH_WITH_TINYXML2
  #include <tinyxml2.h>
#endif

#include <algorithm>

namespace aleph
{

namespace topology
{

namespace io
{

/**
  @class GraphMLReader
  @brief Parses files in GraphML format

  This is a simple reader for graphs in GraphML format. Only a basic subset of
  the specification is supported, viz. reading nodes and edges, and extracting
  user-specified data.
*/

class GraphMLReader
{
public:

  /**
    Default dictionary type used by this class. This is a convenience
    declaration that shortens the code.
  */

  using Dictionary = std::map<std::string, std::string>;

  /**
    Reads a simplicial complex from a file, using the default maximum
    functor for weight assignment. If you want to change the functor,
    please refer to the overloaded variant of this method.

    @param filename Input filename
    @param  K       Simplicial complex

    @see operator()( const std::string&, SimplicialComplex& )
  */

  template <class SimplicialComplex> void operator()( const std::string& filename, SimplicialComplex& K )
  {
    using Simplex    = typename SimplicialComplex::ValueType;
    using DataType   = typename Simplex::DataType;

    this->operator()( filename, K, [] ( DataType a, DataType b ) { return std::max(a,b); } );
  }

  /**
    Reads a simplicial complex from a file while supporting arbitrary
    functors for weight assignment. The functor needs to support this
    interface:

    \code{.cpp}
    using SimplexType = typename SimplicialComplex::ValueType;
    using DataType    = typename Simplex::DataType;

    DataType Functor::operator()( DataType a, DataType b )
    {
      // Do something with a and b. Typically, this would be calculating
      // either the minimum or the maximum...
      return std::max(a, b);
    }
    \endcode

    Please refer to the documentation of SimplicialComplexReader::operator()( const std::string& SimplicialComplex&, Functor )
    for more details.
  */

  template <class SimplicialComplex, class Functor> void operator()( const std::string& filename, SimplicialComplex& K, Functor f )
  {
    _graph = {};

    _nodes.clear();
    _edges.clear();

    #ifdef ALEPH_WITH_TINYXML2
      using namespace tinyxml2;

      XMLDocument document;
      document.LoadFile( filename.c_str() );

      auto root        = document.FirstChild();
      auto graphml     = root->NextSiblingElement( "graphml" );

      // 1. Read optional information about keys in the graph ----------

      {
        auto key = graphml->FirstChildElement( "key" );
        while( key )
        {
          auto id   = key->Attribute( "id" );
          auto name = key->Attribute( "attr.name" );
          auto type = key->Attribute( "for" );

          // It makes sense to switch these two items because we use the
          // name, e.g. 'weight', to look up the ID, e.g. 'id0'.
          if( std::string( type ) == "node" )
            _graph.nodeKeys[name] = id;
          else if( std::string( type ) == "edge" )
            _graph.edgeKeys[name] = id;
          else
            throw std::runtime_error( "Attribute must belong to either nodes or edges" );

          key = key->NextSiblingElement( "key" );
        }
      }

      // 2. Start parsing the graph ------------------------------------

      auto graph = graphml->FirstChildElement( "graph" );
      if( !graph )
        throw std::runtime_error( "GraphML file has to contain at least one graph" );

      // Check whether the graph is directed or not. Note that this does
      // not have any influence on the parsing process for now.
      auto edgedefault = graph->Attribute( "edgedefault" );
      if( edgedefault && std::string( edgedefault ) == "directed" )
        _graph.isDirected = true;
      else
        _graph.isDirected = false;

      auto current = graph->FirstChildElement();

      while( current )
      {
        std::string name = current->Name();
        if( name == "node" )
          parseNode( current );
        else if( name == "edge" )
          parseEdge( current );
        else
        {
          // Ignoring *unknown* elements for now, because they could not
          // possibly harm the extraction process.
        }

        current = current->NextSiblingElement();
      }
    #endif

    // 3. Create simplicial complex ----------------------------------
    //
    // This works regardless of the presence of an XML parsing library,
    // even though the resulting complex may of course be empty.

    using Simplex    = typename SimplicialComplex::ValueType;
    using DataType   = typename Simplex::DataType;
    using VertexType = typename Simplex::VertexType;

    std::vector<Simplex> simplices;
    simplices.reserve( _nodes.size() + _edges.size() );

    auto id_to_index_map = id_to_index<VertexType>();

    // Ensures that the ordering of nodes follows the ordering of their
    // IDs, which simplifies the lookup of source and target nodes when
    // processing edges.
    std::sort( _nodes.begin(), _nodes.end(),
      [&id_to_index_map] ( const Node& u, const Node& v )
      {
        return id_to_index_map.at( u.id ) < id_to_index_map.at( v.id );
      }
    );

    using namespace aleph::utilities;

    for( auto&& node : _nodes )
    {
      auto vertex = id_to_index_map.at( node.id );
      auto weight = DataType();

      if( _readNodeWeights && not _nodeWeightAttribute.empty() )
      {
        if( _graph.nodeKeys.find( _nodeWeightAttribute ) != _graph.nodeKeys.end() )
        {
          bool success = false;
          auto data    = node.dict.at( _graph.nodeKeys.at( _nodeWeightAttribute ) );
          weight       = convert<DataType>( data, success );

          if( !success )
            throw std::runtime_error( "Unable to convert node weight to data type" );
        }
      }

      simplices.push_back( Simplex( vertex, weight ) );
    }

    for( auto&& edge : _edges )
    {
      auto u      = id_to_index_map.at( edge.source );
      auto v      = id_to_index_map.at( edge.target );
      auto weight = DataType();

      if( _readEdgeWeights && not _edgeWeightAttribute.empty() )
      {
        if( _graph.edgeKeys.find( _edgeWeightAttribute ) != _graph.edgeKeys.end() )
        {
          bool success = false;
          auto data    = edge.dict.at( _graph.edgeKeys.at( _edgeWeightAttribute ) );
          weight       = convert<DataType>( data, success );

          if( !success )
            throw std::runtime_error( "Unable to convert edge weight to data type" );
        }
      }

      // Use the node weights to assign a weight to the edge. Even
      // though nodes have been parsed at this point already, some
      // information has to be looked up again here.
      else if( _readNodeWeights && not _nodeWeightAttribute.empty() )
      {
        if( _graph.nodeKeys.find( _nodeWeightAttribute ) != _graph.nodeKeys.end() )
        {
          auto iu = id_to_index_map.at( edge.source );
          auto iv = id_to_index_map.at( edge.target );
          auto du = _nodes.at( iu ).dict.at( _graph.nodeKeys.at( _edgeWeightAttribute ) );
          auto dv = _nodes.at( iv ).dict.at( _graph.nodeKeys.at( _nodeWeightAttribute ) );

          // There is no need to check the success of the conversion
          // because we already processed the nodes before. Failures
          // to convert the data type have already been processed at
          // this point.
          auto wu = convert<DataType>( du );
          auto wv = convert<DataType>( dv );

          weight = f(wu, wv);
        }
      }

      simplices.push_back( Simplex( {u,v}, weight ) );
    }
  }

  /** Retrieves attribute names for the node attributes. */
  std::vector<std::string> getNodeAttributeNames() const
  {
    std::set<std::string> names;

    for( auto&& node : _nodes )
    {
      for( auto&& pair : node.dict )
        names.insert( pair.first );
    }

    return { names.begin(), names.end() };
  }

  /** Retrieves attribute names for the edge attributes */
  std::vector<std::string> getEdgeAttributeNames() const
  {
    std::set<std::string> names;

    for( auto&& edge : _edges )
    {
      for( auto&& pair : edge.dict )
        names.insert( pair.first );
    }

    return { names.begin(), names.end() };
  }

  /**
    Returns a map that maps a node ID to an index. It corresponds
    to the order in which node IDs were allocated. It is *always*
    zero-indexed.
  */

  template <class VertexType> std::map<std::string, VertexType> id_to_index() const noexcept
  {
    std::set<std::string> nodeIDs;
    for( auto&& node : _nodes )
      nodeIDs.insert( node.id );

    std::map<std::string, VertexType> result;

    for( auto&& node : _nodes )
      result[ node.id ] = static_cast<VertexType>( std::distance( nodeIDs.begin(), nodeIDs.find( node.id ) ) );

    return result;
  }

  void setReadNodeWeights( bool value = true ) noexcept           { _readNodeWeights = value; }
  void setReadEdgeWeights( bool value = true ) noexcept           { _readEdgeWeights = value; }

  bool readNodeWeights() const noexcept                           { return _readNodeWeights; }
  bool readEdgeWeights() const noexcept                           { return _readEdgeWeights; }

  void setNodeWeightAttribute( const std::string& name ) noexcept { _nodeWeightAttribute = name; }
  void setEdgeWeightAttribute( const std::string& name ) noexcept { _edgeWeightAttribute = name; }

  const std::string& nodeWeightAttribute() const noexcept         { return _nodeWeightAttribute; }
  const std::string& edgeWeightAttribute() const noexcept         { return _edgeWeightAttribute; }

private:

  #ifdef ALEPH_WITH_TINYXML2

    void parseNode( tinyxml2::XMLElement* element )
    {
      auto name = element->Name();
      auto id   = element->Attribute( "id" );

      if( std::string( name ) != "node" )
        throw std::runtime_error( "Unexpected element for node parsing" );

      if( !id )
        throw std::runtime_error( "Node element must specify ID" );

      Node node;
      node.id = id;

      // Parse additional details of the node, even though they may not
      // be used in the creation of a simplicial complex.
      parseData( element, node.dict );

      _nodes.push_back( node );
    }

    void parseEdge( tinyxml2::XMLElement* element )
    {
      auto name   = element->Name();
      auto id     = element->Attribute( "id" );
      auto source = element->Attribute( "source" );
      auto target = element->Attribute( "target" );

      if( std::string( name ) != "edge" )
        throw std::runtime_error( "Unexpected element for edge parsing" );

      if( !id )
        throw std::runtime_error( "Edge element must specify ID" );

      if( !source || !target )
        throw std::runtime_error( "Edge element must specify both source and target" );

      Edge edge;
      edge.source = source;
      edge.target = target;

      // Parse additional details of the edge, even though they may not
      // be used in the creation of a simplicial complex.
      parseData( element, edge.dict );
    }

    void parseData( tinyxml2::XMLElement* element, Dictionary& dict )
    {
      auto child = element->FirstChildElement();
      while( child )
      {
        std::string name = child->Name();
        if( name == "data" )
        {
          auto key   = child->Attribute( "key" );
          auto value = child->GetText();

          dict[key] = value;
        }

        child = child->NextSiblingElement();
      }
    }

  #endif

  /**
    Auxiliary function for creating a numerical ID out of a parsed ID.
    In case non-numerical IDs are being used in the source file, this
    function ensures that internal IDs *always* start with a zero. If,
    however, numerical IDs are being used, they are converted as-is.
  */

  static std::size_t getID( const std::set<std::string>& ids, const std::string& id )
  {
    // Try to be smart: If the node ID can be converted into the
    // vertex type, we use the converted number instead.
    try
    {
      auto convertedID = std::stoll( id );
      return static_cast<std::size_t>( convertedID );
    }
    catch( std::out_of_range& e )
    {
      throw;
    }
    catch( std::invalid_argument& )
    {
      return static_cast<std::size_t>( std::distance( ids.begin(), ids.find( id ) ) );
    }
  };

  /** Describes a parsed graph along with all of its attributes */
  struct Graph
  {
    bool isDirected;

    // This maps all key IDs to their corresponding names, which is how
    // they are stored for nodes and edges.
    Dictionary nodeKeys;
    Dictionary edgeKeys;
  };

  /** Describes a parsed node along with all of its attributes */
  struct Node
  {
    std::string id;

    Dictionary dict; // all remaining attributes
  };

  /** Describes a parsed edge along with all of its attributes */
  struct Edge
  {
    std::string source; // source node ID
    std::string target; // target node ID

    Dictionary dict; // all remaining attributes
  };

  // Attributes --------------------------------------------------------

  bool _readEdgeWeights = true;
  bool _readNodeWeights = true;

  std::string _edgeWeightAttribute = "weight"; // default attribute for node weight extraction
  std::string _nodeWeightAttribute = "weight"; // default attribute for edge weight extraction

  // Local storage -----------------------------------------------------
  //
  // Variables in this section contain the result of the last parsing
  // process. This is useful when clients are querying attributes.

  Graph _graph;

  std::vector<Node> _nodes;
  std::vector<Edge> _edges;
};

} // namespace io

} // namespace topology

} // namespace aleph

#endif
<commit_msg>Creating simplicial complex<commit_after>#ifndef ALEPH_TOPOLOGY_IO_GRAPHML_HH__
#define ALEPH_TOPOLOGY_IO_GRAPHML_HH__

#include <aleph/config/TinyXML2.hh>

#include <aleph/utilities/String.hh>

#ifdef ALEPH_WITH_TINYXML2
  #include <tinyxml2.h>
#endif

#include <algorithm>
#include <string>

namespace aleph
{

namespace topology
{

namespace io
{

/**
  @class GraphMLReader
  @brief Parses files in GraphML format

  This is a simple reader for graphs in GraphML format. Only a basic subset of
  the specification is supported, viz. reading nodes and edges, and extracting
  user-specified data.
*/

class GraphMLReader
{
public:

  /**
    Default dictionary type used by this class. This is a convenience
    declaration that shortens the code.
  */

  using Dictionary = std::map<std::string, std::string>;

  /**
    Reads a simplicial complex from a file, using the default maximum
    functor for weight assignment. If you want to change the functor,
    please refer to the overloaded variant of this method.

    @param filename Input filename
    @param  K       Simplicial complex

    @see operator()( const std::string&, SimplicialComplex& )
  */

  template <class SimplicialComplex> void operator()( const std::string& filename, SimplicialComplex& K )
  {
    using Simplex    = typename SimplicialComplex::ValueType;
    using DataType   = typename Simplex::DataType;

    this->operator()( filename, K, [] ( DataType a, DataType b ) { return std::max(a,b); } );
  }

  /**
    Reads a simplicial complex from a file while supporting arbitrary
    functors for weight assignment. The functor needs to support this
    interface:

    \code{.cpp}
    using SimplexType = typename SimplicialComplex::ValueType;
    using DataType    = typename Simplex::DataType;

    DataType Functor::operator()( DataType a, DataType b )
    {
      // Do something with a and b. Typically, this would be calculating
      // either the minimum or the maximum...
      return std::max(a, b);
    }
    \endcode

    Please refer to the documentation of SimplicialComplexReader::operator()( const std::string& SimplicialComplex&, Functor )
    for more details.
  */

  template <class SimplicialComplex, class Functor> void operator()( const std::string& filename, SimplicialComplex& K, Functor f )
  {
    _graph = {};

    _nodes.clear();
    _edges.clear();

    #ifdef ALEPH_WITH_TINYXML2
      using namespace tinyxml2;

      XMLDocument document;
      document.LoadFile( filename.c_str() );

      auto root        = document.FirstChild();
      auto graphml     = root->NextSiblingElement( "graphml" );

      // 1. Read optional information about keys in the graph ----------

      {
        auto key = graphml->FirstChildElement( "key" );
        while( key )
        {
          auto id   = key->Attribute( "id" );
          auto name = key->Attribute( "attr.name" );
          auto type = key->Attribute( "for" );

          // It makes sense to switch these two items because we use the
          // name, e.g. 'weight', to look up the ID, e.g. 'id0'.
          if( std::string( type ) == "node" )
            _graph.nodeKeys[name] = id;
          else if( std::string( type ) == "edge" )
            _graph.edgeKeys[name] = id;
          else
            throw std::runtime_error( "Attribute must belong to either nodes or edges" );

          key = key->NextSiblingElement( "key" );
        }
      }

      // 2. Start parsing the graph ------------------------------------

      auto graph = graphml->FirstChildElement( "graph" );
      if( !graph )
        throw std::runtime_error( "GraphML file has to contain at least one graph" );

      // Check whether the graph is directed or not. Note that this does
      // not have any influence on the parsing process for now.
      auto edgedefault = graph->Attribute( "edgedefault" );
      if( edgedefault && std::string( edgedefault ) == "directed" )
        _graph.isDirected = true;
      else
        _graph.isDirected = false;

      auto current = graph->FirstChildElement();

      while( current )
      {
        std::string name = current->Name();
        if( name == "node" )
          parseNode( current );
        else if( name == "edge" )
          parseEdge( current );
        else
        {
          // Ignoring *unknown* elements for now, because they could not
          // possibly harm the extraction process.
        }

        current = current->NextSiblingElement();
      }
    #endif

    // 3. Create simplicial complex ----------------------------------
    //
    // This works regardless of the presence of an XML parsing library,
    // even though the resulting complex may of course be empty.

    using Simplex    = typename SimplicialComplex::ValueType;
    using DataType   = typename Simplex::DataType;
    using VertexType = typename Simplex::VertexType;

    std::vector<Simplex> simplices;
    simplices.reserve( _nodes.size() + _edges.size() );

    auto id_to_index_map = id_to_index<VertexType>();

    // Ensures that the ordering of nodes follows the ordering of their
    // IDs, which simplifies the lookup of source and target nodes when
    // processing edges.
    std::sort( _nodes.begin(), _nodes.end(),
      [&id_to_index_map] ( const Node& u, const Node& v )
      {
        return id_to_index_map.at( u.id ) < id_to_index_map.at( v.id );
      }
    );

    using namespace aleph::utilities;

    for( auto&& node : _nodes )
    {
      auto vertex = id_to_index_map.at( node.id );
      auto weight = DataType();

      if( _readNodeWeights && not _nodeWeightAttribute.empty() )
      {
        if( _graph.nodeKeys.find( _nodeWeightAttribute ) != _graph.nodeKeys.end() )
        {
          bool success = false;
          auto data    = node.dict.at( _graph.nodeKeys.at( _nodeWeightAttribute ) );
          weight       = convert<DataType>( data, success );

          if( !success )
            throw std::runtime_error( "Unable to convert node weight to data type" );
        }
      }

      simplices.push_back( Simplex( vertex, weight ) );
    }

    for( auto&& edge : _edges )
    {
      auto u      = id_to_index_map.at( edge.source );
      auto v      = id_to_index_map.at( edge.target );
      auto weight = DataType();

      if( _readEdgeWeights && not _edgeWeightAttribute.empty() )
      {
        if( _graph.edgeKeys.find( _edgeWeightAttribute ) != _graph.edgeKeys.end() )
        {
          bool success = false;
          auto data    = edge.dict.at( _graph.edgeKeys.at( _edgeWeightAttribute ) );
          weight       = convert<DataType>( data, success );

          if( !success )
            throw std::runtime_error( "Unable to convert edge weight to data type" );
        }
      }

      // Use the node weights to assign a weight to the edge. Even
      // though nodes have been parsed at this point already, some
      // information has to be looked up again here.
      else if( _readNodeWeights && not _nodeWeightAttribute.empty() )
      {
        if( _graph.nodeKeys.find( _nodeWeightAttribute ) != _graph.nodeKeys.end() )
        {
          auto iu = id_to_index_map.at( edge.source );
          auto iv = id_to_index_map.at( edge.target );
          auto du = _nodes.at( iu ).dict.at( _graph.nodeKeys.at( _edgeWeightAttribute ) );
          auto dv = _nodes.at( iv ).dict.at( _graph.nodeKeys.at( _nodeWeightAttribute ) );

          // There is no need to check the success of the conversion
          // because we already processed the nodes before. Failures
          // to convert the data type have already been processed at
          // this point.
          auto wu = convert<DataType>( du );
          auto wv = convert<DataType>( dv );

          weight = f(wu, wv);
        }
      }

      simplices.push_back( Simplex( {u,v}, weight ) );
    }

    K = SimplicialComplex( simplices.begin(), simplices.end() );
  }

  /** Retrieves attribute names for the node attributes. */
  std::vector<std::string> getNodeAttributeNames() const
  {
    std::set<std::string> names;

    for( auto&& node : _nodes )
    {
      for( auto&& pair : node.dict )
        names.insert( pair.first );
    }

    return { names.begin(), names.end() };
  }

  /** Retrieves attribute names for the edge attributes */
  std::vector<std::string> getEdgeAttributeNames() const
  {
    std::set<std::string> names;

    for( auto&& edge : _edges )
    {
      for( auto&& pair : edge.dict )
        names.insert( pair.first );
    }

    return { names.begin(), names.end() };
  }

  /**
    Returns a map that maps a node ID to an index. It corresponds
    to the order in which node IDs were allocated. It is *always*
    zero-indexed.
  */

  template <class VertexType> std::map<std::string, VertexType> id_to_index() const noexcept
  {
    std::set<std::string> nodeIDs;
    for( auto&& node : _nodes )
      nodeIDs.insert( node.id );

    std::map<std::string, VertexType> result;

    for( auto&& node : _nodes )
      result[ node.id ] = static_cast<VertexType>( std::distance( nodeIDs.begin(), nodeIDs.find( node.id ) ) );

    return result;
  }

  void setReadNodeWeights( bool value = true ) noexcept           { _readNodeWeights = value; }
  void setReadEdgeWeights( bool value = true ) noexcept           { _readEdgeWeights = value; }

  bool readNodeWeights() const noexcept                           { return _readNodeWeights; }
  bool readEdgeWeights() const noexcept                           { return _readEdgeWeights; }

  void setNodeWeightAttribute( const std::string& name ) noexcept { _nodeWeightAttribute = name; }
  void setEdgeWeightAttribute( const std::string& name ) noexcept { _edgeWeightAttribute = name; }

  const std::string& nodeWeightAttribute() const noexcept         { return _nodeWeightAttribute; }
  const std::string& edgeWeightAttribute() const noexcept         { return _edgeWeightAttribute; }

private:

  #ifdef ALEPH_WITH_TINYXML2

    void parseNode( tinyxml2::XMLElement* element )
    {
      auto name = element->Name();
      auto id   = element->Attribute( "id" );

      if( std::string( name ) != "node" )
        throw std::runtime_error( "Unexpected element for node parsing" );

      if( !id )
        throw std::runtime_error( "Node element must specify ID" );

      Node node;
      node.id = id;

      // Parse additional details of the node, even though they may not
      // be used in the creation of a simplicial complex.
      parseData( element, node.dict );

      _nodes.push_back( node );
    }

    void parseEdge( tinyxml2::XMLElement* element )
    {
      auto name   = element->Name();
      auto id     = element->Attribute( "id" );
      auto source = element->Attribute( "source" );
      auto target = element->Attribute( "target" );

      if( std::string( name ) != "edge" )
        throw std::runtime_error( "Unexpected element for edge parsing" );

      if( !id )
        throw std::runtime_error( "Edge element must specify ID" );

      if( !source || !target )
        throw std::runtime_error( "Edge element must specify both source and target" );

      Edge edge;
      edge.source = source;
      edge.target = target;

      // Parse additional details of the edge, even though they may not
      // be used in the creation of a simplicial complex.
      parseData( element, edge.dict );
    }

    void parseData( tinyxml2::XMLElement* element, Dictionary& dict )
    {
      auto child = element->FirstChildElement();
      while( child )
      {
        std::string name = child->Name();
        if( name == "data" )
        {
          auto key   = child->Attribute( "key" );
          auto value = child->GetText();

          dict[key] = value;
        }

        child = child->NextSiblingElement();
      }
    }

  #endif

  /**
    Auxiliary function for creating a numerical ID out of a parsed ID.
    In case non-numerical IDs are being used in the source file, this
    function ensures that internal IDs *always* start with a zero. If,
    however, numerical IDs are being used, they are converted as-is.
  */

  static std::size_t getID( const std::set<std::string>& ids, const std::string& id )
  {
    // Try to be smart: If the node ID can be converted into the
    // vertex type, we use the converted number instead.
    try
    {
      auto convertedID = std::stoll( id );
      return static_cast<std::size_t>( convertedID );
    }
    catch( std::out_of_range& e )
    {
      throw;
    }
    catch( std::invalid_argument& )
    {
      return static_cast<std::size_t>( std::distance( ids.begin(), ids.find( id ) ) );
    }
  };

  /** Describes a parsed graph along with all of its attributes */
  struct Graph
  {
    bool isDirected;

    // This maps all key IDs to their corresponding names, which is how
    // they are stored for nodes and edges.
    Dictionary nodeKeys;
    Dictionary edgeKeys;
  };

  /** Describes a parsed node along with all of its attributes */
  struct Node
  {
    std::string id;

    Dictionary dict; // all remaining attributes
  };

  /** Describes a parsed edge along with all of its attributes */
  struct Edge
  {
    std::string source; // source node ID
    std::string target; // target node ID

    Dictionary dict; // all remaining attributes
  };

  // Attributes --------------------------------------------------------

  bool _readEdgeWeights = true;
  bool _readNodeWeights = true;

  std::string _edgeWeightAttribute = "weight"; // default attribute for node weight extraction
  std::string _nodeWeightAttribute = "weight"; // default attribute for edge weight extraction

  // Local storage -----------------------------------------------------
  //
  // Variables in this section contain the result of the last parsing
  // process. This is useful when clients are querying attributes.

  Graph _graph;

  std::vector<Node> _nodes;
  std::vector<Edge> _edges;
};

} // namespace io

} // namespace topology

} // namespace aleph

#endif
<|endoftext|>


<commit_before>/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program 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 General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

/* Write some debug info */

#include "mysql_priv.h"
#include "sql_select.h"
#include <hash.h>
#include <thr_alarm.h>

/* Intern key cache variables */
extern "C" pthread_mutex_t THR_LOCK_keycache;

#ifndef DBUG_OFF

void
print_where(COND *cond,const char *info)
{
  if (cond)
  {
    char buff[256];
    String str(buff,(uint32) sizeof(buff), default_charset_info);
    str.length(0);
    cond->print(&str);
    str.append('\0');
    DBUG_LOCK_FILE;
    (void) fprintf(DBUG_FILE,"\nWHERE:(%s) ",info);
    (void) fputs(str.ptr(),DBUG_FILE);
    (void) fputc('\n',DBUG_FILE);
    DBUG_UNLOCK_FILE;
  }
}

	/* This is for debugging purposes */

extern HASH open_cache;
extern TABLE *unused_tables;

void print_cached_tables(void)
{
  uint idx,count,unused;
  TABLE *start_link,*lnk;

  VOID(pthread_mutex_lock(&LOCK_open));
  puts("DB             Table                            Version  Thread  L.thread  Open");

  for (idx=unused=0 ; idx < open_cache.records ; idx++)
  {
    TABLE *entry=(TABLE*) hash_element(&open_cache,idx);
    printf("%-14.14s %-32s%6ld%8ld%10ld%6d\n",
	   entry->table_cache_key,entry->real_name,entry->version,
	   entry->in_use ? entry->in_use->thread_id : 0L,
	   entry->in_use ? entry->in_use->dbug_thread_id : 0L,
	   entry->db_stat ? 1 : 0);
    if (!entry->in_use)
      unused++;
  }
  count=0;
  if ((start_link=lnk=unused_tables))
  {
    do
    {
      if (lnk != lnk->next->prev || lnk != lnk->prev->next)
      {
	printf("unused_links isn't linked properly\n");
	return;
      }
    } while (count++ < open_cache.records && (lnk=lnk->next) != start_link);
    if (lnk != start_link)
    {
      printf("Unused_links aren't connected\n");
    }
  }
  if (count != unused)
    printf("Unused_links (%d) doesn't match open_cache: %d\n", count,unused);
  printf("\nCurrent refresh version: %ld\n",refresh_version);
  if (hash_check(&open_cache))
    printf("Error: File hash table is corrupted\n");
  fflush(stdout);
  VOID(pthread_mutex_unlock(&LOCK_open));
  return;
}

void TEST_filesort(SORT_FIELD *sortorder,uint s_length)
{
  char buff[256],buff2[256];
  String str(buff,sizeof(buff),default_charset_info);
  String out(buff2,sizeof(buff2),default_charset_info);
  const char *sep;
  DBUG_ENTER("TEST_filesort");

  out.length(0);
  for (sep=""; s_length-- ; sortorder++, sep=" ")
  {
    out.append(sep);
    if (sortorder->reverse)
      out.append('-');
    if (sortorder->field)
    {
      if (sortorder->field->table_name)
      {
	out.append(sortorder->field->table_name);
	out.append('.');
      }
      out.append(sortorder->field->field_name ? sortorder->field->field_name:
		 "tmp_table_column");
    }
    else
    {
      str.length(0);
      sortorder->item->print(&str);
      out.append(str);
    }
  }
  out.append('\0');				// Purify doesn't like c_ptr()
  DBUG_LOCK_FILE;
  VOID(fputs("\nInfo about FILESORT\n",DBUG_FILE));
  fprintf(DBUG_FILE,"Sortorder: %s\n",out.ptr());
  DBUG_UNLOCK_FILE;
  DBUG_VOID_RETURN;
}

void
TEST_join(JOIN *join)
{
  uint i,ref;
  DBUG_ENTER("TEST_join");

  DBUG_LOCK_FILE;
  VOID(fputs("\nInfo about JOIN\n",DBUG_FILE));
  for (i=0 ; i < join->tables ; i++)
  {
    JOIN_TAB *tab=join->join_tab+i;
    TABLE *form=tab->table;
    fprintf(DBUG_FILE,"%-16.16s  type: %-7s  q_keys: %4d  refs: %d  key: %d  len: %d\n",
	    form->table_name,
	    join_type_str[tab->type],
	    tab->keys,
	    tab->ref.key_parts,
	    tab->ref.key,
	    tab->ref.key_length);
    if (tab->select)
    {
      if (tab->use_quick == 2)
	fprintf(DBUG_FILE,
		"                  quick select checked for each record (keys: %d)\n",
		(int) tab->select->quick_keys);
      else if (tab->select->quick)
	fprintf(DBUG_FILE,"                  quick select used on key %s, length: %d\n",
		form->key_info[tab->select->quick->index].name,
		tab->select->quick->max_used_key_length);
      else
	VOID(fputs("                  select used\n",DBUG_FILE));
    }
    if (tab->ref.key_parts)
    {
      VOID(fputs("                  refs: ",DBUG_FILE));
      for (ref=0 ; ref < tab->ref.key_parts ; ref++)
      {
	Item *item=tab->ref.items[ref];
	fprintf(DBUG_FILE,"%s  ", item->full_name());
      }
      VOID(fputc('\n',DBUG_FILE));
    }
  }
  DBUG_UNLOCK_FILE;
  DBUG_VOID_RETURN;
}

#endif

void mysql_print_status(THD *thd)
{
  char current_dir[FN_REFLEN];
  printf("\nStatus information:\n\n");
  my_getwd(current_dir, sizeof(current_dir),MYF(0));
  printf("Current dir: %s\n", current_dir);
  if (thd)
    thd->proc_info="locks";
  thr_print_locks();				// Write some debug info
#ifndef DBUG_OFF
  if (thd)
    thd->proc_info="table cache";
  print_cached_tables();
#endif
  /* Print key cache status */
  if (thd)
    thd->proc_info="key cache";
  pthread_mutex_lock(&THR_LOCK_keycache);
  printf("key_cache status:\n\
blocks used:%10lu\n\
not flushed:%10lu\n\
w_requests: %10lu\n\
writes:     %10lu\n\
r_requests: %10lu\n\
reads:      %10lu\n",
	 _my_blocks_used,_my_blocks_changed,_my_cache_w_requests,
	 _my_cache_write,_my_cache_r_requests,_my_cache_read);
  pthread_mutex_unlock(&THR_LOCK_keycache);

  if (thd)
    thd->proc_info="status";
  pthread_mutex_lock(&LOCK_status);
  printf("\nhandler status:\n\
read_key:   %10lu\n\
read_next:  %10lu\n\
read_rnd    %10lu\n\
read_first: %10lu\n\
write:      %10lu\n\
delete      %10lu\n\
update:     %10lu\n",
	 ha_read_key_count, ha_read_next_count,
	 ha_read_rnd_count, ha_read_first_count,
	 ha_write_count, ha_delete_count, ha_update_count);
  pthread_mutex_unlock(&LOCK_status);
  printf("\nTable status:\n\
Opened tables: %10lu\n\
Open tables:   %10lu\n\
Open files:    %10lu\n\
Open streams:  %10lu\n",
	 opened_tables,
	 (ulong) cached_tables(),
	 (ulong) my_file_opened,
	 (ulong) my_stream_opened);

  ALARM_INFO alarm_info;
#ifndef DONT_USE_THR_ALARM
  thr_alarm_info(&alarm_info);
  printf("\nAlarm status:\n\
Active alarms:   %u\n\
Max used alarms: %u\n\
Next alarm time: %lu\n",
	 alarm_info.active_alarms,
	 alarm_info.max_used_alarms,
	 alarm_info.next_alarm_time);
#endif
  fflush(stdout);
  if (thd)
    thd->proc_info="malloc";
  my_checkmalloc();
  TERMINATE(stdout);				// Write malloc information
  if (thd)
    thd->proc_info=0;
}
<commit_msg>Small addition to COM_DEBUG<commit_after>/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program 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 General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

/* Write some debug info */

#include "mysql_priv.h"
#include "sql_select.h"
#include <hash.h>
#include <thr_alarm.h>

/* Intern key cache variables */
extern "C" pthread_mutex_t THR_LOCK_keycache;

#ifndef DBUG_OFF

void
print_where(COND *cond,const char *info)
{
  if (cond)
  {
    char buff[256];
    String str(buff,(uint32) sizeof(buff), default_charset_info);
    str.length(0);
    cond->print(&str);
    str.append('\0');
    DBUG_LOCK_FILE;
    (void) fprintf(DBUG_FILE,"\nWHERE:(%s) ",info);
    (void) fputs(str.ptr(),DBUG_FILE);
    (void) fputc('\n',DBUG_FILE);
    DBUG_UNLOCK_FILE;
  }
}

	/* This is for debugging purposes */

extern HASH open_cache;
extern TABLE *unused_tables;

static const char *lock_descriptions[] =
{
  "No lock",
  "Low priority read lock",
  "Shared Read lock",
  "High priority read lock",
  "Read lock  without concurrent inserts",
  "Write lock that allows other writers",
  "Write lock, but allow reading",
  "Concurrent insert lock",
  "Lock Used by delayed insert",
  "Low priority write lock",
  "High priority write lock",
  "Highest priority write lock"
};

void print_cached_tables(void)
{
  uint idx,count,unused;
  TABLE *start_link,*lnk;

  VOID(pthread_mutex_lock(&LOCK_open));
  puts("DB             Table                            Version  Thread  L.thread  Open  Lock");

  for (idx=unused=0 ; idx < open_cache.records ; idx++)
  {
    TABLE *entry=(TABLE*) hash_element(&open_cache,idx);
    printf("%-14.14s %-32s%6ld%8ld%10ld%6d  %s\n",
	   entry->table_cache_key,entry->real_name,entry->version,
	   entry->in_use ? entry->in_use->thread_id : 0L,
	   entry->in_use ? entry->in_use->dbug_thread_id : 0L,
	   entry->db_stat ? 1 : 0, entry->in_use ? lock_descriptions[(int)entry->reginfo.lock_type] : "Not in use");
    if (!entry->in_use)
      unused++;
  }
  count=0;
  if ((start_link=lnk=unused_tables))
  {
    do
    {
      if (lnk != lnk->next->prev || lnk != lnk->prev->next)
      {
	printf("unused_links isn't linked properly\n");
	return;
      }
    } while (count++ < open_cache.records && (lnk=lnk->next) != start_link);
    if (lnk != start_link)
    {
      printf("Unused_links aren't connected\n");
    }
  }
  if (count != unused)
    printf("Unused_links (%d) doesn't match open_cache: %d\n", count,unused);
  printf("\nCurrent refresh version: %ld\n",refresh_version);
  if (hash_check(&open_cache))
    printf("Error: File hash table is corrupted\n");
  fflush(stdout);
  VOID(pthread_mutex_unlock(&LOCK_open));
  return;
}

void TEST_filesort(SORT_FIELD *sortorder,uint s_length)
{
  char buff[256],buff2[256];
  String str(buff,sizeof(buff),default_charset_info);
  String out(buff2,sizeof(buff2),default_charset_info);
  const char *sep;
  DBUG_ENTER("TEST_filesort");

  out.length(0);
  for (sep=""; s_length-- ; sortorder++, sep=" ")
  {
    out.append(sep);
    if (sortorder->reverse)
      out.append('-');
    if (sortorder->field)
    {
      if (sortorder->field->table_name)
      {
	out.append(sortorder->field->table_name);
	out.append('.');
      }
      out.append(sortorder->field->field_name ? sortorder->field->field_name:
		 "tmp_table_column");
    }
    else
    {
      str.length(0);
      sortorder->item->print(&str);
      out.append(str);
    }
  }
  out.append('\0');				// Purify doesn't like c_ptr()
  DBUG_LOCK_FILE;
  VOID(fputs("\nInfo about FILESORT\n",DBUG_FILE));
  fprintf(DBUG_FILE,"Sortorder: %s\n",out.ptr());
  DBUG_UNLOCK_FILE;
  DBUG_VOID_RETURN;
}

void
TEST_join(JOIN *join)
{
  uint i,ref;
  DBUG_ENTER("TEST_join");

  DBUG_LOCK_FILE;
  VOID(fputs("\nInfo about JOIN\n",DBUG_FILE));
  for (i=0 ; i < join->tables ; i++)
  {
    JOIN_TAB *tab=join->join_tab+i;
    TABLE *form=tab->table;
    fprintf(DBUG_FILE,"%-16.16s  type: %-7s  q_keys: %4d  refs: %d  key: %d  len: %d\n",
	    form->table_name,
	    join_type_str[tab->type],
	    tab->keys,
	    tab->ref.key_parts,
	    tab->ref.key,
	    tab->ref.key_length);
    if (tab->select)
    {
      if (tab->use_quick == 2)
	fprintf(DBUG_FILE,
		"                  quick select checked for each record (keys: %d)\n",
		(int) tab->select->quick_keys);
      else if (tab->select->quick)
	fprintf(DBUG_FILE,"                  quick select used on key %s, length: %d\n",
		form->key_info[tab->select->quick->index].name,
		tab->select->quick->max_used_key_length);
      else
	VOID(fputs("                  select used\n",DBUG_FILE));
    }
    if (tab->ref.key_parts)
    {
      VOID(fputs("                  refs: ",DBUG_FILE));
      for (ref=0 ; ref < tab->ref.key_parts ; ref++)
      {
	Item *item=tab->ref.items[ref];
	fprintf(DBUG_FILE,"%s  ", item->full_name());
      }
      VOID(fputc('\n',DBUG_FILE));
    }
  }
  DBUG_UNLOCK_FILE;
  DBUG_VOID_RETURN;
}

#endif

void mysql_print_status(THD *thd)
{
  char current_dir[FN_REFLEN];
  printf("\nStatus information:\n\n");
  my_getwd(current_dir, sizeof(current_dir),MYF(0));
  printf("Current dir: %s\n", current_dir);
  if (thd)
    thd->proc_info="locks";
  thr_print_locks();				// Write some debug info
#ifndef DBUG_OFF
  if (thd)
    thd->proc_info="table cache";
  print_cached_tables();
#endif
  /* Print key cache status */
  if (thd)
    thd->proc_info="key cache";
  pthread_mutex_lock(&THR_LOCK_keycache);
  printf("key_cache status:\n\
blocks used:%10lu\n\
not flushed:%10lu\n\
w_requests: %10lu\n\
writes:     %10lu\n\
r_requests: %10lu\n\
reads:      %10lu\n",
	 _my_blocks_used,_my_blocks_changed,_my_cache_w_requests,
	 _my_cache_write,_my_cache_r_requests,_my_cache_read);
  pthread_mutex_unlock(&THR_LOCK_keycache);

  if (thd)
    thd->proc_info="status";
  pthread_mutex_lock(&LOCK_status);
  printf("\nhandler status:\n\
read_key:   %10lu\n\
read_next:  %10lu\n\
read_rnd    %10lu\n\
read_first: %10lu\n\
write:      %10lu\n\
delete      %10lu\n\
update:     %10lu\n",
	 ha_read_key_count, ha_read_next_count,
	 ha_read_rnd_count, ha_read_first_count,
	 ha_write_count, ha_delete_count, ha_update_count);
  pthread_mutex_unlock(&LOCK_status);
  printf("\nTable status:\n\
Opened tables: %10lu\n\
Open tables:   %10lu\n\
Open files:    %10lu\n\
Open streams:  %10lu\n",
	 opened_tables,
	 (ulong) cached_tables(),
	 (ulong) my_file_opened,
	 (ulong) my_stream_opened);

  ALARM_INFO alarm_info;
#ifndef DONT_USE_THR_ALARM
  thr_alarm_info(&alarm_info);
  printf("\nAlarm status:\n\
Active alarms:   %u\n\
Max used alarms: %u\n\
Next alarm time: %lu\n",
	 alarm_info.active_alarms,
	 alarm_info.max_used_alarms,
	 alarm_info.next_alarm_time);
#endif
  fflush(stdout);
  if (thd)
    thd->proc_info="malloc";
  my_checkmalloc();
  TERMINATE(stdout);				// Write malloc information
  if (thd)
    thd->proc_info=0;
}
<|endoftext|>


<commit_before>/**
 * \file
 * \brief SignalsCatcher class header
 *
 * \author Copyright (C) 2015 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * \date 2015-04-16
 */

#ifndef INCLUDE_DISTORTOS_SIGNALSCATCHER_HPP_
#define INCLUDE_DISTORTOS_SIGNALSCATCHER_HPP_

#include "distortos/synchronization/SignalsCatcherControlBlock.hpp"

namespace distortos
{

namespace synchronization
{

class SignalsReceiverControlBlock;

}	// namespace synchronization

/// SignalsCatcher class is a container for synchronization::SignalsCatcherControlBlock
class SignalsCatcher
{
	friend class synchronization::SignalsReceiverControlBlock;

public:

	/// import Storage type alias from synchronization::SignalsCatcherControlBlock
	using Storage = synchronization::SignalsCatcherControlBlock::Storage;

	/**
	 * \brief SignalsCatcher's constructor
	 *
	 * \param [in] storageBegin is a pointer to first element of storage for
	 * synchronization::SignalsCatcherControlBlock::Association objects
	 * \param [in] storageEnd is a pointer to "one past the last" element of storage for
	 * synchronization::SignalsCatcherControlBlock::Association objects
	 */

	constexpr SignalsCatcher(Storage* const storageBegin, Storage* const storageEnd) :
			signalsCatcherControlBlock_{storageBegin, storageEnd}
	{

	}

	/**
	 * \brief SignalsCatcher's constructor
	 *
	 * \param N is the number of elements in \a storage array
	 *
	 * \param [in] storage is a reference to array of Storage elements
	 */

	template<size_t N>
	constexpr explicit SignalsCatcher(Storage (& storage)[N]) :
			SignalsCatcher{std::begin(storage), std::end(storage)}
	{

	}

private:

	/// contained synchronization::SignalsCatcherControlBlock object
	synchronization::SignalsCatcherControlBlock signalsCatcherControlBlock_;
};

}	// namespace distortos

#endif	// INCLUDE_DISTORTOS_SIGNALSCATCHER_HPP_
<commit_msg>SignalsCatcher: add helper constructor with std::array as argument and size of array deduced by template<commit_after>/**
 * \file
 * \brief SignalsCatcher class header
 *
 * \author Copyright (C) 2015 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * \date 2015-04-16
 */

#ifndef INCLUDE_DISTORTOS_SIGNALSCATCHER_HPP_
#define INCLUDE_DISTORTOS_SIGNALSCATCHER_HPP_

#include "distortos/synchronization/SignalsCatcherControlBlock.hpp"

#include <array>

namespace distortos
{

namespace synchronization
{

class SignalsReceiverControlBlock;

}	// namespace synchronization

/// SignalsCatcher class is a container for synchronization::SignalsCatcherControlBlock
class SignalsCatcher
{
	friend class synchronization::SignalsReceiverControlBlock;

public:

	/// import Storage type alias from synchronization::SignalsCatcherControlBlock
	using Storage = synchronization::SignalsCatcherControlBlock::Storage;

	/**
	 * \brief SignalsCatcher's constructor
	 *
	 * \param [in] storageBegin is a pointer to first element of storage for
	 * synchronization::SignalsCatcherControlBlock::Association objects
	 * \param [in] storageEnd is a pointer to "one past the last" element of storage for
	 * synchronization::SignalsCatcherControlBlock::Association objects
	 */

	constexpr SignalsCatcher(Storage* const storageBegin, Storage* const storageEnd) :
			signalsCatcherControlBlock_{storageBegin, storageEnd}
	{

	}

	/**
	 * \brief SignalsCatcher's constructor
	 *
	 * \param N is the number of elements in \a storage array
	 *
	 * \param [in] storage is a reference to array of Storage elements
	 */

	template<size_t N>
	constexpr explicit SignalsCatcher(Storage (& storage)[N]) :
			SignalsCatcher{std::begin(storage), std::end(storage)}
	{

	}

	/**
	 * \brief SignalsCatcher's constructor
	 *
	 * \param N is the number of elements in \a storage array
	 *
	 * \param [in] storage is a reference to std::array of Storage elements
	 */

	template<size_t N>
	constexpr explicit SignalsCatcher(std::array<Storage, N>& storage) :
			SignalsCatcher{storage.begin(), storage.end()}
	{

	}

private:

	/// contained synchronization::SignalsCatcherControlBlock object
	synchronization::SignalsCatcherControlBlock signalsCatcherControlBlock_;
};

}	// namespace distortos

#endif	// INCLUDE_DISTORTOS_SIGNALSCATCHER_HPP_
<|endoftext|>