text:
/*
	Copyright 2017-present Zoltan Somogyi (AI-TOOLKIT), All Rights Reserved
	You may use this file only if you agree to the software license:
	AI-TOOLKIT Open Source Software License - Version 2.1 - February 22, 2018:
	https://ai-toolkit.blogspot.com/p/ai-toolkit-open-source-software-license.html.
	Also included with the source code distribution in AI-TOOLKIT-LICENSE.txt.
*/

#include "Utility.h"

//global logging
VOICEBRIDGE_API twinLogger::TwinLoggerMT oTwinLog;

//--- Logging override for Windows version of Kaldi --------------->

//NOTE: this code replaces the Kaldi main logging meachanism with the new Kaldi Windows global twin logging mechanism
void HandleKaldiLogMessage(const kaldi::LogMessageEnvelope &envelope, const char *message)
{
	switch (envelope.severity) {
	case kaldi::LogMessageEnvelope::kInfo:
		oTwinLog(twinLogger::Info) << message;
		break;
	case kaldi::LogMessageEnvelope::kWarning:
		oTwinLog(twinLogger::Warning) << message;
		break;
	case kaldi::LogMessageEnvelope::kError:
		oTwinLog(twinLogger::Error) << message;
		break;
	case kaldi::LogMessageEnvelope::kAssertFailed:
		oTwinLog(twinLogger::Debug) << message;
		break;
	default:
		oTwinLog(twinLogger::Info) << message;  // coding error (unknown 'severity'),
	}
}

VOICEBRIDGE_API void ReplaceKaldiLogHandlerEx(bool reset)
{
	if (!reset) {
		kaldi::SetLogHandler(NULL);
	}
	else {
		kaldi::SetLogHandler(HandleKaldiLogMessage);
	}
}

//<------------------- Logging override for Windows version of Kaldi

//replaces all occurances of the 'search' string with 'replace' string in the 'subject' string and in place
VOICEBRIDGE_API void ReplaceStringInPlace(std::string& subject, const std::string& search, const std::string& replace)
{
	size_t pos = 0;
	while ((pos = subject.find(search, pos)) != std::string::npos) {
		subject.replace(pos, search.length(), replace);
		pos += replace.length();
	}
}

VOICEBRIDGE_API bool ContainsString(std::string subject, const std::string search) {
	return (subject.find(search, 0) != std::string::npos);
}

VOICEBRIDGE_API std::string GetFirstLineFromFile(std::string path)
{
	std::ifstream ifs(path);
	if (!ifs) {
		throw std::runtime_error("Error opening file " + path);
	}
	std::string line;
	std::getline(ifs, line);
	return line;
}

//-------------------------------------------------------------------------------------------------------------------

VOICEBRIDGE_API StringTable readData(std::string const path, std::string delimiter)
{
	std::ifstream ifs(path);
	if (!ifs) {
		throw std::runtime_error("Error opening file.");
	}

	StringTable table;
	std::string line;
	while (std::getline(ifs, line))	{
		std::vector<std::string> _w;
		boost::algorithm::trim(line);
		strtk::parse(line, delimiter, _w, strtk::split_options::compress_delimiters);
		table.emplace_back(_w);
	}
	return table;
}

VOICEBRIDGE_API int ReadStringTable(std::string const path, StringTable & table, std::string delimiter)
{
	try {
		table = readData(path, delimiter);
		return 0;
	}
	catch (std::exception const& e) {
		LOGTW_FATALERROR << " " << e.what() << ". (Reading file " << path << ")";
		return -1;
	}
	catch (...) {
		LOGTW_FATALERROR << " Unknown Error. (Reading file " << path << ")";
		return -1;
	}
}

VOICEBRIDGE_API int SaveStringTable(std::string const& path, StringTable & table)
{
try {
	//NOTE: ofstream write adds an '\r' in front of the '\n' automatically and some code in Kaldi crashes. To prevent this
	//		add std::ios::binary option to each ofstream to make sure that '\r' is not added!
	fs::ofstream file_(path, std::ios::binary | std::ios::out);
	if (!file_) {
		LOGTW_ERROR << " can't open output file: " << path << ".";
		return -1;
	}

	for (StringTable::const_iterator it(table.begin()), it_end(table.end()); it != it_end; ++it)
	{
		int c = 0;
		for (string_vec::const_iterator itc1(it->begin()), itc1_end(it->end()); itc1 != itc1_end; ++itc1)
		{
			if (c > 0) file_ << " "; //Separator!
			file_ << *itc1;
			c++;
		}
		file_ << '\n';
	}
	file_.flush(); file_.close();
	return 0;
}
catch (std::exception const& e) {
	LOGTW_FATALERROR << " " << e.what() << ".";
	return -1;
}
catch (...) {
	LOGTW_FATALERROR << " Unknown Error.";
	return -1;
}
}

//comparer function for StringTable short : max 2 columns sort
class StringTableSortCompare2
{
public:
	//fCol and sCol are "string" or "number"
	explicit StringTableSortCompare2(int column1, int column2, std::string fCol, std::string sCol, bool ascend1, bool ascend2)
		: m_column1(column1), m_column2(column2), fColType(fCol), sColType(sCol), m_ascend1(ascend1), m_ascend2(ascend2){}
	bool operator()(const std::vector<std::string>& lhs, const std::vector<std::string>& rhs)
	{
		//sort by column2 after sorting by column1; if column1 == column2 then makes no difference
		if (lhs[m_column1] == rhs[m_column1]) {
			if (m_ascend2) {
				if (sColType.compare("string") == 0)
					return lhs[m_column2] < rhs[m_column2];
				else if (sColType.compare("number") == 0)
					return StringToNumber<double>(lhs[m_column2].c_str()) < StringToNumber<double>(rhs[m_column2].c_str());
				else return lhs[m_column2] < rhs[m_column2];
			}
			else {
				if (sColType.compare("string") == 0)
					return lhs[m_column2] > rhs[m_column2];
				else if (sColType.compare("number") == 0)
					return StringToNumber<double>(lhs[m_column2].c_str()) > StringToNumber<double>(rhs[m_column2].c_str());
				else return lhs[m_column2] > rhs[m_column2];
			}
		}
		else {
			if (m_ascend1) {
				if (fColType.compare("string") == 0)
					return lhs[m_column1] < rhs[m_column1];
				else  if (fColType.compare("number") == 0)
					return StringToNumber<double>(lhs[m_column1].c_str()) < StringToNumber<double>(rhs[m_column1].c_str());
				else return lhs[m_column1] < rhs[m_column1];
			}
			else {
				if (fColType.compare("string") == 0)
					return lhs[m_column1] > rhs[m_column1];
				else  if (fColType.compare("number") == 0)
					return StringToNumber<double>(lhs[m_column1].c_str()) > StringToNumber<double>(rhs[m_column1].c_str());
				else return lhs[m_column1] > rhs[m_column1];
			}
		}
	}
private:
	int m_column1;
	int m_column2;
	std::string fColType;
	std::string sColType;
	bool m_ascend1;
	bool m_ascend2;
};

/*
	In place short of a StringTable by col1 and then by col2; col1 can be = col2.
	When requested bMakeUnique makes the table unique (erashes duplicate) by the first column (unique first column!)
*/
VOICEBRIDGE_API int SortStringTable(StringTable & table,
	int col1, int col2,
	std::string type1, std::string type2, bool bMakeUnique,
	bool ascend1, bool ascend2)
{
	if (table[0].size() < col1 + 1 || table[0].size() < col2 + 1)
	{
		LOGTW_ERROR << " The string table size does not much the requested sort column index.";
		return -1;
	}
	StringTableSortCompare2 sort_compare(col1, col2, type1, type2, ascend1, ascend2);
	std::sort(table.begin(), table.end(), sort_compare);

	if (bMakeUnique)
	{
		//IMPORTANT NOTE: when unique is requested we always mean unique by the first supplied column (columns[0])
		//				  and not the whole line! The whole line will be removed from the StringTable.
		int line = 0;
		StringTable::const_iterator it = table.begin();
		while ( it != table.end() ) {
			if (line == 0) { line++; ++it; continue; }
			if ((*it)[col1] == (*(it - 1))[col1]) {
				//cout << "deleting line: " << (*it)[0] << "\n";
				it = table.erase(it);
			}
			else {
				++it;
			}
		}
		//NOTE: erase() invalidates the current iterator but returns a new one to the next element
		//		which can be used further! However, if erase() is not used the iterator must be incremented!
	}

	return 0;
}

//fieldnr: zero based index of the columns!
VOICEBRIDGE_API int is_sortedonfield_and_uniqe(fs::path file, int fieldnr, bool bCheckunique, bool bShowError)
{
	StringTable table_;
	std::vector<std::string> _v;
	if (ReadStringTable(file.string(), table_) < 0) {
		LOGTW_ERROR << " fail to open: " << file.string() << ".";
		return -3;
	}
	for (StringTable::const_iterator it(table_.begin()), it_end(table_.end()); it != it_end; ++it) {
		if ((*it).size() < (fieldnr + 1)) return -1;
		_v.push_back((*it)[fieldnr]);
	}

	if (!std::is_sorted(_v.begin(), _v.end())) {
		if(bShowError)
			LOGTW_ERROR << " the file is not sorted on field nr " << (fieldnr + 1) << " in file " << file.string() << ".";
		return -2;
	}
	if (bCheckunique && !(std::unique(_v.begin(), _v.end()) == _v.end())) {
		if (bShowError)
			LOGTW_ERROR << " the file contains duplicate elements: " << file.string() << ".";
		return -1;
	}

	return 0;
}

//checks the whole table if the string s is present;
//in case bExactword is true it checks for the whole field instead of contents
VOICEBRIDGE_API bool ContainsString(StringTable table, std::string s, bool bExactword)
{
	for (StringTable::const_iterator it(table.begin()), it_end(table.end()); it != it_end; ++it) {
		for (string_vec::const_iterator itc1(it->begin()), itc1_end(it->end()); itc1 != itc1_end; ++itc1) {
			if (bExactword) {
				if (*itc1 == s) return true;
			}
			else {
				if ((*itc1).find(s) != std::string::npos) {
					return true;
				}
			}
		}
	}
	return false;
}

//element wise comparision of 2 StringTable's
VOICEBRIDGE_API bool IsTheSame(StringTable table1, StringTable table2)
{
	if (table1.size() != table2.size()) return false;
	for (int i = 0; i < table1.size(); i++) {
		if (table1[i].size() != table2[i].size()) return false;
		if (!std::equal(std::begin(table1[i]), std::end(table1[i]), std::begin(table2[i])))
			return false;
	}
	return true;
}

//-------------------------------------------------------------------------------------------------------------------

///https://stackoverflow.com/questions/311955/redirecting-cout-to-a-console-in-windows
VOICEBRIDGE_API void BindStdHandlesToConsole()
{
	// Redirect the CRT standard input, output, and error handles to the console
	freopen("CONIN$", "r", stdin);
	freopen("CONOUT$", "w", stdout);
	freopen("CONOUT$", "w", stderr);

	//Clear the error state for each of the C++ standard stream objects. We need to do this, as
	//attempts to access the standard streams before they refer to a valid target will cause the
	//iostream objects to enter an error state. In versions of Visual Studio after 2005, this seems
	//to always occur during startup regardless of whether anything has been read from or written to
	//the console or not.
	std::wcout.clear();
	std::cout.clear();
	std::wcerr.clear();
	std::cerr.clear();
	std::wcin.clear();
	std::cin.clear();
}

//converts the string to UTF-8
//Returns an empty string if fails
VOICEBRIDGE_API std::string ConvertToUTF8(std::string codepage_str)
{
	int size = MultiByteToWideChar(CP_ACP, MB_COMPOSITE, codepage_str.c_str(), (int)codepage_str.length(), nullptr, 0);
	std::wstring utf16_str(size, '\0');
	int ret = MultiByteToWideChar(CP_ACP, MB_COMPOSITE, codepage_str.c_str(), (int)codepage_str.length(), &utf16_str[0], size);
	if (ret == 0) return "";
	int utf8_size = WideCharToMultiByte(CP_UTF8, 0, utf16_str.c_str(), (int)utf16_str.length(), nullptr, 0, nullptr, nullptr);
	if (utf8_size == 0) return "";
	std::string utf8_str(utf8_size, '\0');
	int ret1 = WideCharToMultiByte(CP_UTF8, 0, utf16_str.c_str(), (int)utf16_str.length(), &utf8_str[0], utf8_size, nullptr, nullptr);
	if (ret1 == 0) return "";

	return utf8_str;
}

//returns true if the str contains characters besides space, tab, newline
bool validate_utf8_whitespaces(std::string str)
{
	std::string sallow(" \t\r\n");
	if (str.find_first_not_of(sallow) != std::string::npos)
	{
		// There's a non-space. OK!
		return true;
	}
	return false;
}

//returns a vector with the elements which are in both input vectors; it returns an empty vector if there are no the same elements in both
VOICEBRIDGE_API std::vector<std::string> instersection(std::vector<std::string> &v1, std::vector<std::string> &v2)
{
	std::vector<std::string> v3;
	sort(v1.begin(), v1.end());
	sort(v2.begin(), v2.end());
	set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(), back_inserter(v3));
	return v3;
}

//checks if two string vectors has overlap
// returns true if there is no overlap. false if there is overlap.
VOICEBRIDGE_API bool IsDisjoint(std::vector<std::string> v1, std::vector<std::string> v2)
{
	std::vector<std::string> _v = instersection(v1, v2);
	if (_v.size() > 0) {
		return false;
	}
	return true;
}

VOICEBRIDGE_API bool is_positive_int(const std::string& s)
{
	return !s.empty() && std::find_if(s.begin(),
		s.end(), [](char c) { return !std::isdigit(c); }) == s.end();
}

//Copies the complete source directory to the destination directory (files and folders). The source directory will
//not be a subdirectory but the contents is copied!
VOICEBRIDGE_API bool CopyDir(boost::filesystem::path const & source, boost::filesystem::path const & destination)
{
	try
	{
		// Check whether the function call is valid
		if (!boost::filesystem::exists(source) ||
			!boost::filesystem::is_directory(source))
		{
			LOGTW_ERROR << "Source directory " << source.string() << " does not exist or is not a directory.";
			return false;
		}

		if (boost::filesystem::exists(destination))
		{
			LOGTW_ERROR << "Destination directory " << destination.string() << " already exists.";
			return false;
		}

		// Create the destination directory
		if (!boost::filesystem::create_directory(destination))
		{
			LOGTW_ERROR << "Unable to create destination directory" << destination.string();
			return false;
		}
	}

	catch (boost::filesystem::filesystem_error const & e)
	{
		LOGTW_ERROR << e.what();
		return false;
	}

	// Iterate through the source directory
	for (boost::filesystem::directory_iterator file(source);
		file != boost::filesystem::directory_iterator();
		++file)
	{
		try
		{
			boost::filesystem::path current(file->path());
			if (boost::filesystem::is_directory(current))
			{
				// Found directory: Recursion
				if (!CopyDir(current, destination / current.filename()))
				{
					return false;
				}
			}
			else
			{
				// Found file: Copy
				boost::filesystem::copy_file(current, destination / current.filename());
			}
		}
		catch (boost::filesystem::filesystem_error const & e)
		{
			LOGTW_ERROR << e.what();
		}
	}
	return true;
}

VOICEBRIDGE_API int CreateDir(fs::path dir, bool deletecontents) {
	try {
		if (fs::exists(dir)) {
			if (deletecontents) {
				//in order to remove only the contents but no the directory:
				for (fs::directory_iterator end_dir_it, it(dir); it != end_dir_it; ++it) {
					fs::remove_all(it->path());
				}
			}
		}
		else {
			if (!fs::create_directories(dir)) {
				LOGTW_ERROR << " could not create directory " << dir.string() << ".";
				return -1;
			}
		}
	}
	catch (const std::exception&) {
		LOGTW_ERROR << " could not create directory " << dir.string() << ".";
		return -1;
	}
	return 0;
}

//[start] get directory contents ---------------------------------------------------------------------------------------------
// usage
//std::vector<std::string> exts{ ".jpg", ".png" };
//std::vector<std::string> files = getFilesInDir("/path/to/root/directory/", exts, true);

/**
* @note If extension is empty string ("") then all files are returned
* @param Path root directory
* @param extension String or vector of strings to filter - empty string returns all files - default: ""
* @param recursive Set true to scan directories recursively - default false
* @return Vector of strings with full paths
*/
VOICEBRIDGE_API std::vector<fs::path> GetFilesInDir(const fs::path &_path, const std::string &extension, const bool &recursive)
{
	std::vector<fs::path> files;
	//boost::filesystem::path dir(_path);
	if (boost::filesystem::exists(_path) && boost::filesystem::is_directory(_path)) {

		if (recursive) {
			boost::filesystem::recursive_directory_iterator it(_path);
			boost::filesystem::recursive_directory_iterator endit;
			while (it != endit) {
				if (boost::filesystem::is_regular_file(*it) && (extension == "") ? true : it->path().extension() == extension) {
					files.push_back(it->path());
				}
				++it;
			}
		}
		else {
			boost::filesystem::directory_iterator it(_path);
			boost::filesystem::directory_iterator endit;
			while (it != endit) {
				if (boost::filesystem::is_regular_file(*it) && (extension == "") ? true : it->path().extension() == extension) {
					files.push_back(it->path());
				}
				++it;
			}
		}
	}
	return files;
}

//the same as above but with several file extensions
VOICEBRIDGE_API std::vector<fs::path> GetFilesInDir(const fs::path &_path, const std::vector<std::string> &extension, const bool &recursive) {
	if (extension.size() <= 0) return GetFilesInDir(_path, "", recursive);
	std::vector<fs::path> outArray;
	for (const std::string &ext : extension) {
		std::vector<fs::path> files = GetFilesInDir(_path, ext, recursive);
		outArray.insert(outArray.end(), files.begin(), files.end());
	}
	return outArray;
}

//this version gets the directories in a given dir which correspond to the given regex
VOICEBRIDGE_API std::vector<fs::path> GetDirectories(const fs::path &_path, const std::string &rex)
{
	std::vector<fs::path> files;
	if (boost::filesystem::exists(_path) && boost::filesystem::is_directory(_path))
	{
		const boost::regex re(rex);
		boost::match_results<std::string::const_iterator> re_res;
		boost::filesystem::directory_iterator it(_path);
		boost::filesystem::directory_iterator endit;
		while (it != endit) {
			std::string dirname = (*it).path().filename().string();
			if (boost::filesystem::is_directory(*it) && (rex == "") ? true : boost::regex_match(dirname, re_res, re))
			{
				files.push_back(it->path());
			}
			++it;
		}
	}
	return files;
}

//[end] get directory contents ---------------------------------------------------------------------------------------------

std::string bool_as_text(bool b)
{
	std::stringstream converter;
	converter << b;
	return converter.str();
}

VOICEBRIDGE_API int MergeFiles(std::vector<fs::path> _in, fs::path out)
{
	try
	{
		fs::ofstream of_out(out, std::ios_base::binary | std::ios_base::out);
		if (!of_out) {
			LOGTW_ERROR << " Could not merge files because output file is not accessible.";
			return -1;
		}
		for each(fs::path p in _in)
		{
			fs::ifstream if_(p, std::ios_base::binary);
			of_out << if_.rdbuf();
		}
	}
	catch (const std::exception& ex)
	{
		LOGTW_ERROR << " Could not merge files. Reason: " << ex.what() << ".";
		return -1;
	}
	return 0;
}

//-----------------------------------------------------------------------------------------------------------

//-----------------------------------------------------------------------------------------------------------------
//	GZIP/GUNZIP Library API
//-----------------------------------------------------------------------------------------------------------------
//NOTE: boost+gzip only supports archivig 1 file! It can not zip/unzip a directory tree.
//include section for gzip:

//TODO:... not tested

#include <boost/iostreams/device/file.hpp>
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/stream.hpp>
#include <boost/iostreams/copy.hpp>
#include <boost/iostreams/filter/gzip.hpp>
namespace io = boost::iostreams;

VOICEBRIDGE_API int CompressFileGz(fs::path file)
{
	//NOTE: gzip does not work without specifying 'fs::ofstream::binary | fs::ofstream::in' for both in/out files!
	try {
		io::file_source infile(file.string(), fs::ofstream::binary | fs::ofstream::in);
		io::filtering_istream fis;
		io::gzip_compressor gzip;
		fis.push(gzip);
		fis.push(infile);
		io::file_sink outfile(file.string() + ".gz", fs::ofstream::binary | fs::ofstream::out);
		io::stream<io::file_sink> os(outfile);
		io::copy(fis, os);

	}
	catch (const std::exception& ex)
	{
		LOGTW_ERROR << ex.what();
		return -1;
	}
	return 0;
}

VOICEBRIDGE_API int DecompressFileGz(fs::path file)
{
	//NOTE: gzip does not work without specifying 'fs::ofstream::binary | fs::ofstream::in' for both in/out files!
	try {
		io::file_source infile(file.string(), fs::ofstream::binary | fs::ofstream::in);
		io::filtering_istream fis;
		io::gzip_decompressor ungzip;
		fis.push(ungzip);
		fis.push(infile);
		std::string s(file.string());
		ReplaceStringInPlace(s, ".gz", "");
		io::file_sink outfile(s, fs::ofstream::binary | fs::ofstream::out);
		io::stream<io::file_sink> os(outfile);
		boost::iostreams::copy(fis, os);
	}
	catch (const std::exception& ex)
	{
		LOGTW_ERROR << ex.what();
		return -1;
	}
	return 0;
}

//-----------------------------------------------------------------------------------------------------------------

//-----------------------------------------------------------------------------------------------------------------
//ZIP/UNZIP library API
//-----------------------------------------------------------------------------------------------------------------
#include <zipper.h>
#include <unzipper.h>

//recursive function for adding several files to a ZIP file
int AddFileToZipArchive(ziputils::zipper & zipFile, fs::path p, fs::path ziproot)
{
	if (fs::is_directory(p))
	{//directory
	 // Iterate through the source directory
		for (boost::filesystem::directory_iterator file(p); file != boost::filesystem::directory_iterator(); ++file) {
			try {
				boost::filesystem::path current(file->path());
				if (boost::filesystem::is_directory(current))
				{
					// Found directory: Recursion
					//current
					if (AddFileToZipArchive(zipFile, current, ziproot) < 0) return -1;
				}
				else
				{
					// Found file: Add to ZIP
					//current
					std::ifstream file(current.string(), std::ios::in | std::ios::binary);
					if (file.is_open())
					{
						//LOGTW_INFO << "Adding file " << current.string();
						//must add the relative path to the archive's root folder!
						std::string relpath((fs::relative(current, ziproot)).string());

						zipFile.addEntry(relpath.c_str());
						zipFile << file;
					}
				}
			}
			catch (boost::filesystem::filesystem_error const & e)
			{
				LOGTW_ERROR << e.what() << '\n';
				return -1;
			}
		}
	}
	else
	{//1 file
		std::ifstream file(p.string(), std::ios::in | std::ios::binary);
		if (file.is_open())
		{
			//LOGTW_INFO << "Adding file " << p.string();
			//must add the relative path to the archive's root folder!
			std::string relpath((fs::relative(p, ziproot)).string());

			zipFile.addEntry(relpath.c_str());
			zipFile << file;
		}
	}

	return 0;
}

//If the input is a folder it will ZIP recursively all directories and files.
//If the input is a file it will ZIP the file.
VOICEBRIDGE_API int Zip(fs::path p)
{
	if (!fs::exists(p)) {
		LOGTW_ERROR << "The file " << p.string() << " does not exist.";
		return -1;
	}

	try	{
		ziputils::zipper zipFile;
		fs::path outpath(p.parent_path() / (p.filename().stem().string() + ".zip"));

		LOGTW_INFO << "Creating archive " << outpath;

		if (fs::exists(outpath))
			zipFile.open(outpath.string().c_str(), true);
		else zipFile.open(outpath.string().c_str(), false);

		if (zipFile.isOpen()) {
			//call recursive function
			if (AddFileToZipArchive(zipFile, p, p.parent_path()) < 0) return -1;
			zipFile.close();
		}
		else {
			LOGTW_ERROR << "Failed to create archive.";
			return -1;
		}
	}
	catch (const std::exception& ex)
	{
		LOGTW_FATALERROR << ex.what();
		return -1;
	}

	return 0;
}

VOICEBRIDGE_API int UnZip(fs::path p)
{
	try	{
		ziputils::unzipper zipFile;
		zipFile.open(p.string().c_str());
		if (!fs::exists(p)) {
			LOGTW_ERROR << "The file " << p.string() << " does not exist.";
			return -1;
		}
		auto filenames = zipFile.getFilenames();

		for (auto it = filenames.begin(); it != filenames.end(); it++)
		{
			zipFile.openEntry((*it).c_str());
			//zipFile >> std::cout;

			std::string abspath((fs::absolute((*it), p.parent_path())).string());
			fs::path outpath(abspath);
			if (!fs::is_directory(outpath) && fs::exists(outpath))
			{// do not overwrite
				LOGTW_ERROR << "The file " << outpath.string() << " does exist. Please delete it first.";
				return -1;
			}
			//if directory does not exist then create it
			if (!fs::exists(outpath.parent_path())) {
				fs::create_directories(outpath.parent_path());
			}

			fs::ofstream oss(outpath);
			zipFile >> oss;
		}
	}
	catch (const std::exception& ex)
	{
		LOGTW_FATALERROR << ex.what();
		return -1;
	}

	return 0;
}
//-----------------------------------------------------------------------------------------------------------------

//-----------------------------------------------------------------------------------------------------------------
//BOOST Wildcard file actions library API
//-----------------------------------------------------------------------------------------------------------------
/*
dir: the directory in which we are searching
regex_filename: the file name including regex wildcards
IMPORTANT: must model the whole file name in the regex because boost::regex_match is used!
examples:
	//NOTE: the \ must be written as \\ because the compiler eats the first \ as escape!
	//NOTE: the first literal dot (.) must be escaped because the dot have a special meaning in regex!
	boost::regex("^(word_boundary\\.).*"))       =>      word_boundary.*
*/
VOICEBRIDGE_API void GetAllMatchingFiles(std::vector< fs::path > & all_matching_files, fs::path dir, boost::regex regex_filename)
{
	boost::filesystem::directory_iterator end_itr; // Default ctor yields past-the-end
	for (boost::filesystem::directory_iterator i(dir); i != end_itr; ++i)
	{
		// Skip if not a file
		if (!boost::filesystem::is_regular_file(i->status())) continue;

		boost::match_results<std::string::const_iterator> results;
		if( !boost::regex_match( i->path().filename().string(), results, regex_filename ) ) continue;

		// File matches, store it
		all_matching_files.push_back(i->path());
	}
}

VOICEBRIDGE_API int CopyAllMatching(fs::path dir_source, fs::path dir_destination, boost::regex regex_filename)
{
	try	{
		std::vector< fs::path > all_matching_files;
		GetAllMatchingFiles(all_matching_files, dir_source, regex_filename);
		if (all_matching_files.size() > 0) {
			for (fs::path p : all_matching_files)
				fs::copy_file(p, dir_destination / p.filename());
		}
		return 0;
	}
	catch (const std::exception& ex)
	{
		LOGTW_FATALERROR << ex.what();
		return -1;
	}
}

//NOTE: this is not made API visible because of the danger of deleting several files
int DeleteAllMatching(fs::path dir_source, boost::regex regex_filename)
{
	try {
		std::vector< fs::path > all_matching_files;
		GetAllMatchingFiles(all_matching_files, dir_source, regex_filename);
		if (all_matching_files.size() > 0) {
			for (fs::path p : all_matching_files)
				fs::remove(p);
		}
		return 0;
	}
	catch (const std::exception& ex)
	{
		LOGTW_FATALERROR << ex.what();
		return -1;
	}
}
//-----------------------------------------------------------------------------------------------------------------

/* checks if the files exist and returns -1 if one of the files do not exist, otherwise returns 0.*/
int CheckFilesExist(std::vector<fs::path> _files, bool report)
{
	for (fs::path p : _files) {
		if (!fs::exists(p))
		{
			if (report)
				LOGTW_ERROR << "Could not find " << p.string();
			return -1;
		}
	}
	return 0;
}

//-----------------------------------------------------------------------------------------------------------------
//General purpose helpers
//-----------------------------------------------------------------------------------------------------------------

/*
	Filter each line of 'in' with the 'filter' and write it to 'out'
	'filter' is a map of regex expressions as keys and the replacement string as value. By the regex selected string
	will be replaced with the 'value' in the map, and this for each key-value pair for each line.
*/
VOICEBRIDGE_API int FilterFile(fs::path in, fs::path out, std::unordered_map<std::string, std::string> filter)
{
	try
	{
		fs::ifstream ifs(in);
		if (!ifs) {
			LOGTW_ERROR << "Could not open input file " << in.string();
			return -1;
		}
		fs::ofstream ofs(out);
		if (!ofs) {
			LOGTW_ERROR << "Could not open output file " << out.string();
			return -1;
		}
		std::string line;
		while (std::getline(ifs, line)) {
			for (auto &pair : filter) {
				boost::regex rexp(pair.first);
				line = boost::regex_replace(line, rexp, pair.second);
			}
			ofs << line << "\n";
		}
	}
	catch (const std::exception& ex)
	{
		LOGTW_ERROR << "Could not filter file. Reason: " << ex.what();
		return -1;
	}
	return 0;
}

/*
	In place convert utf8 string to lower/upper case
*/
std::string ConvertToCaseUtf8(std::string & s, bool toUpper)
{
	auto ss = ConvertToUTF8(s);
	if (toUpper) {
		for (auto& c : ss)
			c = std::toupper(c);
	}
	else {
		for (auto& c : ss)
			c = std::tolower(c);
	}
	s = ss;

	return ss;
}

max_stars_repo_name: sanyaade-teachings/VoiceBridge

max_issues_repo_name: sanyaade-teachings/VoiceBridge

max_forks_repo_name: sanyaade-teachings/VoiceBridge


text:
#pragma once
#include <vector>
#include <cinttypes>
#include <boost/graph/graph_traits.hpp>
#include <memory>
#include <limits>
#include <boost/iterator/counting_iterator.hpp>
#include "detail/util/Collection.hpp"
#include "detail/StaticGraphIterators.hpp"
#include "detail/BasicGraphStructures.hpp"
#include "detail/StaticGraphPropertyMaps.hpp"
#include "detail/StaticGraphBuilder.hpp"
#include "properties.hpp"

namespace graph {

	struct StaticGraphTraversalCategory :
		public adjacency_graph_tag, public boost::adjacency_graph_tag,
		public bidirectional_graph_tag, public boost::bidirectional_graph_tag,
		public vertex_list_graph_tag, public boost::vertex_list_graph_tag
	{ };

	struct NoProperties : public Properties<> {};

	template <typename VertexProperties = NoProperties, typename EdgeProperties = NoProperties>
	class StaticGraph {
	public:
		using type = StaticGraph<VertexProperties, EdgeProperties>;

		using edge_size_type = uint32_t;
		using vertices_size_type = uint32_t;
		using edges_size_type = uint32_t;
		using degree_size_type = uint16_t;
		using vertex_descriptor = vertices_size_type;
		using directed_category = directed_tag;
		using edge_parallel_category = disallow_parallel_edge_tag;
		using traversal_category = StaticGraphTraversalCategory;

		using VertexPropertyMapType = VertexPropertyMap<VertexProperties, type>;
		using EdgePropertyMapType = EdgePropertyMap<EdgeProperties, type>;
		using vertex_bundled = VertexProperties;
		using edge_bundled = EdgeProperties;

		friend VertexPropertyMapType;
	private:

		using EdgePropertiesVecType = std::vector<EdgeProperties>;

		using StoredAdjacencyType = FancyLink<vertex_descriptor, EdgeProperties>;
		using AdjacenciesVecType = std::vector<StoredAdjacencyType>;
		using AdjacenciesVecIteratorType = typename AdjacenciesVecType::const_iterator;

		using VertexType = Vertex<AdjacenciesVecIteratorType, VertexProperties>;
		using VerticesVecType = std::vector<VertexType>;

		using AdjacenciesSeparatorsVecType = std::vector<degree_size_type>;
	public:
		using vertex_iterator = boost::counting_iterator<vertex_descriptor>;
		using adjacency_iterator = AdjacencyIterator<AdjacenciesVecIteratorType, vertex_descriptor>;
		using edge_descriptor = FancyEdgeDescriptor<typename StoredAdjacencyType::VertexType, typename StoredAdjacencyType::EdgePropertiesType>;
		using out_edge_iterator = EdgeIterator<AdjacenciesVecIteratorType, edge_descriptor, internals::EdgeDirection::Out>;
		using in_edge_iterator = EdgeIterator<AdjacenciesVecIteratorType, edge_descriptor, internals::EdgeDirection::In>;

		using InEdgeCollection = graphUtil::Collection<in_edge_iterator>;
		using OutEdgeCollection = graphUtil::Collection<out_edge_iterator>;
		using AdjacencyCollection = graphUtil::ValueCollection<adjacency_iterator, graphUtil::SortedTag>;

		using Builder = GraphBuilder<type>;
		friend Builder;

		class VertexCollection : public graphUtil::Collection<vertex_iterator> {
		public:
			VertexType operator[](const vertex_descriptor& v) const {
				if (v == this->size())
					return VertexType(this->graph.adjacencies.end());
				return this->graph.vertices[v];
			}

			explicit VertexCollection(const StaticGraph& g)
				: CollectionType(vertex_iterator(0), vertex_iterator(g.vertices.size())), graph(g) {}

		private:
			const StaticGraph& graph;
		};

        static vertex_descriptor null_vertex() {
            return std::numeric_limits<vertex_descriptor>::max();
        };

		StaticGraph()
			: edgePropertyMap(new EdgePropertyMapType()),
			  vertexPropertyMap(new VertexPropertyMapType(this)),
			  vertexCollection(nullptr) {}

		template <class PairIterator>
		StaticGraph(PairIterator begin, PairIterator end,
					vertices_size_type n, edges_size_type m = 0) : StaticGraph() {
			auto builder = new Builder(n, m);

			for (auto& it = begin; it != end; ++it) {
                EdgeProperties edgeProperties;
                edgeProperties = it->second;
				builder->AddEdge((it->first).first, (it->first).second, edgeProperties);
			}

			builder->BuildGraph(*this);

			delete builder;
		}

        StaticGraph(std::vector<std::pair<size_t, size_t>>::iterator begin,
            std::vector<std::pair<size_t, size_t>>::iterator end,
            size_t n, size_t m = 0) : StaticGraph() {
            auto builder = new Builder(n, m);

            for (auto& it = begin; it != end; ++it) {
                builder->AddEdge(it->first, it->second);
            }

            builder->BuildGraph(*this);

            delete builder;
        }

		const VertexCollection& Vertices() const {
			return *vertexCollection;
		}

		AdjacencyCollection OutAdjacencies(const vertex_descriptor& v) const {
			return AdjacencyCollection(
				adjacency_iterator(this->Vertices()[v].begin + this->edgesSeparators[v]),
				adjacency_iterator(this->Vertices()[v + 1].begin));

		}

		AdjacencyCollection InAdjacencies(const vertex_descriptor& v) const {
			return AdjacencyCollection(
				adjacency_iterator(this->Vertices()[v].begin),
				adjacency_iterator(this->Vertices()[v].begin + this->edgesSeparators[v]));
		}

		OutEdgeCollection OutEdges(const vertex_descriptor& v) const {
			return OutEdgeCollection(
				out_edge_iterator(v, this->Vertices()[v].begin + this->edgesSeparators[v]),
				out_edge_iterator(v, this->Vertices()[v + 1].begin));
		}

		InEdgeCollection InEdges(const vertex_descriptor& v) const {
			return InEdgeCollection(
				in_edge_iterator(v, this->Vertices()[v].begin),
				in_edge_iterator(v, this->Vertices()[v].begin + this->edgesSeparators[v]));
		}

		edges_size_type EdgesCount() const {
			return edgeProperties.size();
		}

		const EdgePropertyMapType& GetEdgePropertyMap() const {
			return *edgePropertyMap;
		}

		const VertexPropertyMapType& GetVertexPropertyMap() const {
			return *vertexPropertyMap;
		}

	private:
		void Initialize() {
			this->vertexCollection = std::make_unique<VertexCollection>(*this);
		}

		AdjacenciesVecType adjacencies;
		VerticesVecType vertices;
		EdgePropertiesVecType edgeProperties;
		AdjacenciesSeparatorsVecType edgesSeparators;
		std::unique_ptr<EdgePropertyMapType> edgePropertyMap;
		std::unique_ptr<VertexPropertyMapType> vertexPropertyMap;
		std::unique_ptr<VertexCollection> vertexCollection;
	};
}

// PropertyMaps
namespace graph {
#define StaticGraphType StaticGraph<VertexProperties, EdgeProperties>

	template <typename VertexProperties, typename EdgeProperties>
	struct property_map<StaticGraphType, vertex_bundle_t> {
		using type = typename StaticGraphType::VertexPropertyMapType;
	};

	template <typename VertexProperties, typename EdgeProperties>
	struct property_map<StaticGraphType, edge_bundle_t> {
		using type = typename StaticGraphType::EdgePropertyMapType;
	};

	template <typename VertexProperties, typename EdgeProperties>
	inline typename property_map<StaticGraphType, vertex_bundle_t>::type
	get(const vertex_bundle_t&, StaticGraphType& graph) {
		return graph.GetVertexPropertyMap();
	}

	template <typename VertexProperties, typename EdgeProperties>
	inline typename property_map<StaticGraphType, edge_bundle_t>::type
	get(const edge_bundle_t&, StaticGraphType& graph) {
		return graph.GetEdgePropertyMap();
	}

    template <typename Graph>
    struct VertexIndexPropertyMap{};

    template <typename VertexProperties, typename EdgeProperties>
    struct VertexIndexPropertyMap<StaticGraphType> {
        using key_type = typename graph_traits<StaticGraphType>::vertex_descriptor;
        using value_type = typename graph_traits<StaticGraphType>::vertices_size_type;
        using reference = value_type&;
        using category = boost::readable_property_map_tag;
    };

    template <typename VertexProperties, typename EdgeProperties>
    struct property_map<StaticGraphType, vertex_index_t> {
        using type = VertexIndexPropertyMap<StaticGraphType>;
    };

    template <typename VertexProperties, typename EdgeProperties>
    typename VertexIndexPropertyMap<StaticGraphType>::value_type
        get(const VertexIndexPropertyMap<StaticGraphType>& index,
        const typename VertexIndexPropertyMap<StaticGraphType>::key_type& key) {
        return key;
    };

    template<typename VertexProperties, typename EdgeProperties>
    inline typename property_map<StaticGraphType, vertex_index_t>::type
    get(const vertex_index_t&, StaticGraphType&) {
        return VertexIndexPropertyMap<StaticGraphType>();
    };

#undef StaticGraphType
}

#include "detail/StaticGraphTools.hpp"

ext: hpp

max_stars_repo_name: SkyterX/rpclass

max_issues_repo_name: SkyterX/rpclass

max_forks_repo_name: SkyterX/rpclass


text:
#pragma once

#include <boost/noncopyable.hpp>
#include <boost/fusion/support/is_sequence.hpp>
#include <boost/fusion/include/is_sequence.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/ref.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/type_traits/remove_cv.hpp>
#include <boost/fusion/algorithm/iteration/for_each.hpp>
#include <boost/mpl/for_each.hpp>
#include <boost/mpl/count.hpp>
#include <boost/fusion/container/vector/convert.hpp>
#include <boost/fusion/include/as_vector.hpp>
#include <boost/fusion/adapted/mpl.hpp>
#include <boost/fusion/include/mpl.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/cstdint.hpp>

#include <string>
#include <exception>
#include <vector>
#include <typeinfo>
#include <iostream>
#include <sstream>

#include <hdf5.h>
#ifdef H5_HAVE_PARALLEL
#include <mpi.h>
#endif

namespace hdf
{

  class DatasetExists : public std::exception
  {
  };
  class AttributeExists : public std::exception
  {
  };
  class GroupNotFound : public std::exception
  {
  };
  class DatasetNotFound : public std::exception
  {
  };
  class AttributeNotFound : public std::exception
  {
  };

  inline
  void
  output_dims(hid_t dataspace)
  {
    if (H5Sis_simple(dataspace))
    {
      std::cout << "Num dims: " << H5Sget_simple_extent_ndims(dataspace)
          << "\n";
      std::vector<hsize_t> dims(H5Sget_simple_extent_ndims(dataspace));
      H5Sget_simple_extent_dims(dataspace, &dims[0], 0);
      for (std::size_t i = 0; i < dims.size(); ++i)
        std::cout << "[" << i << "] " << dims[i] << "\n";

      std::cout << "Selected " << H5Sget_select_elem_npoints(dataspace)
          << " points\n";
    }
  }

  namespace detail
  {

    inline
    void
    check_errors()
    {
#if H5_VERS_MINOR >= 8
      H5Eprint(H5E_DEFAULT, NULL);
#else
      H5Eprint(NULL);
#endif
    }

    template<class T>
      class wrapper
      {
      };

    class Create
    {
    };

    template<typename >
      class data_type_traits;

    template<class T>
      size_t
      HDF5_datatype_size()
      {
        ///@todo! fix me for variable length datatypes/vectors/strings etc..
        size_t size = sizeof(T);
        return size;
      }

    template<class T, class Homogeneous>
      struct TypeCreatorHelper
      {
        TypeCreatorHelper(hid_t & type) :
            type(type), offset(0)
        {
          type = H5Tcreate(H5T_COMPOUND, HDF5_datatype_size<T>());
          boost::mpl::for_each<
              typename boost::fusion::result_of::as_vector<T>::type>(
              boost::ref(*this));
          assert(HDF5_datatype_size<T>() == offset);
        }

        template<class T2>
          void
          operator()(T2&) const
          {
            data_type_traits<typename boost::remove_cv<T2>::type>::insert_data_type(
                type, offset);
          }

        hid_t & type;
        mutable size_t offset;
      };

    template<class T>
      struct TypeCreatorHelper<T, boost::true_type>
      {
        TypeCreatorHelper(hid_t & type)
        {
          type =
              data_type_traits<typename boost::remove_cv<T>::type>::homogeneous_type();
        }
      };

    struct DataTypeCreator
    {
      template<class T>
        DataTypeCreator(wrapper<T>)
        {
          TypeCreatorHelper<T,
              typename data_type_traits<typename boost::remove_cv<T>::type>::is_homogeneous> t(
              type);

          dim = data_type_traits<typename boost::remove_cv<T>::type>::dimsize();
        }

      template<class T>
        DataTypeCreator(wrapper<T *>)
        {
          TypeCreatorHelper<T,
              typename data_type_traits<typename boost::remove_cv<T>::type>::is_homogeneous> t(
              type);
          dim = data_type_traits<typename boost::remove_cv<T>::type>::dimsize();
        }
      hsize_t dim;
      hid_t type;
    };

    template<typename Type>
      class data_type_traits
      {
      public:
        typedef typename boost::fusion::result_of::as_vector<Type>::type vec_type;

        typedef typename boost::is_same<
            typename boost::fusion::result_of::size<vec_type>::type,
            boost::mpl::int_<
                boost::mpl::count<vec_type,
                    typename boost::mpl::at_c<vec_type, 0>::type>::type::value> >::type is_homogeneous;

        static hid_t
        homogeneous_type()
        {
          return H5Tcopy(
              data_type_traits<typename boost::mpl::at_c<vec_type, 0>::type>::value());
        }

        static hsize_t
        dimsize()
        {
          if (is_homogeneous::value)
            return boost::mpl::count<vec_type,
                typename boost::mpl::at_c<vec_type, 0>::type>::type::value;
          else
            return 1;
        }

        static hsize_t
        num_type()
        {
          return boost::mpl::count<vec_type,
                          typename boost::mpl::at_c<vec_type, 0>::type>::type::value;
        }

        static void
        insert_data_type(hid_t t, size_t & offset)
        {
          wrapper<Type> dt;
          DataTypeCreator d(dt);
          static int i = 0;
          std::string name(typeid(Type).name());
          std::stringstream ss;
          ss << i++;
          name += ss.str();
          H5Tinsert(t, name.c_str(), offset, d.type);
          offset += HDF5_datatype_size<Type>();
          H5Tclose(d.type);
        }
      };

    template<>
      class data_type_traits<int>
      {
      public:
        typedef boost::true_type is_homogeneous;
        static hid_t
        homogeneous_type()
        {
          return H5Tcopy(value());
        }
        static hid_t
        value()
        {
          return H5T_NATIVE_INT;
        }
        static hsize_t
        dimsize()
        {
          return 1;
        }
        static hsize_t
        num_type()
        {
          return 1;
        }
        static void
        insert_data_type(hid_t t, size_t & offset)
        {
          static int i = 0;
          std::string name("int");
          std::stringstream ss;
          ss << i++;
          name += ss.str();
          H5Tinsert(t, name.c_str(), offset, value());
          offset += HDF5_datatype_size<int>();
        }
      };

    template<>
      class data_type_traits<char>
      {
      public:
        typedef boost::true_type is_homogeneous;
        static hid_t
        homogeneous_type()
        {
          return H5Tcopy(value());
        }
        static hid_t
        value()
        {
          return H5T_NATIVE_CHAR;
        }
        static hsize_t
        dimsize()
        {
          return 1;
        }
        static hsize_t
        num_type()
        {
          return 1;
        }
        static void
        insert_data_type(hid_t t, size_t & offset)
        {
          static int i = 0;
          std::string name("char");
          std::stringstream ss;
          ss << i++;
          name += ss.str();
          H5Tinsert(t, name.c_str(), offset, value());
          offset += HDF5_datatype_size<char>();
        }
      };

    template<>
      class data_type_traits<unsigned int>
      {
      public:
        typedef boost::true_type is_homogeneous;
        static hid_t
        homogeneous_type()
        {
          return H5Tcopy(value());
        }
        static hid_t
        value()
        {
          return H5T_NATIVE_UINT;
        }
        static hsize_t
        dimsize()
        {
          return 1;
        }
        static hsize_t
        num_type()
        {
          return 1;
        }
        static void
        insert_data_type(hid_t t, size_t & offset)
        {
          static int i = 0;
          std::string name("uint");
          std::stringstream ss;
          ss << i++;
          name += ss.str();
          H5Tinsert(t, name.c_str(), offset, value());
          offset += HDF5_datatype_size<unsigned int>();
        }
      };

    template<>
      class data_type_traits<long>
      {
      public:
        typedef boost::true_type is_homogeneous;
        static hid_t
        homogeneous_type()
        {
          return H5Tcopy(value());
        }
        static hid_t
        value()
        {
          return H5T_NATIVE_LONG;
        }
        static hsize_t
        dimsize()
        {
          return 1;
        }
        static hsize_t
        num_type()
        {
          return 1;
        }
        static void
        insert_data_type(hid_t t, size_t & offset)
        {
          static int i = 0;
          std::string name("uint");
          std::stringstream ss;
          ss << i++;
          name += ss.str();
          H5Tinsert(t, name.c_str(), offset, value());
          offset += HDF5_datatype_size<long>();
        }
      };

    template<>
      class data_type_traits<long long>
      {
      public:
        typedef boost::true_type is_homogeneous;
        static hid_t
        homogeneous_type()
        {
          return H5Tcopy(value());
        }
        static hid_t
        value()
        {
          return H5T_NATIVE_LLONG;
        }
        static hsize_t
        dimsize()
        {
          return 1;
        }
        static hsize_t
        num_type()
        {
          return 1;
        }
        static void
        insert_data_type(hid_t t, size_t & offset)
        {
          static int i = 0;
          std::string name("longlong");
          std::stringstream ss;
          ss << i++;
          name += ss.str();
          H5Tinsert(t, name.c_str(), offset, value());
          offset += HDF5_datatype_size<long long>();
        }
      };

    template<>
      class data_type_traits<unsigned long>
      {
      public:
        typedef boost::true_type is_homogeneous;
        static hid_t
        homogeneous_type()
        {
          return H5Tcopy(value());
        }
        static hid_t
        value()
        {
          return H5T_NATIVE_ULONG;
        }
        static hsize_t
        dimsize()
        {
          return 1;
        }
        static hsize_t
        num_type()
        {
          return 1;
        }
        static void
        insert_data_type(hid_t t, size_t & offset)
        {
          static int i = 0;
          std::string name("uint");
          std::stringstream ss;
          ss << i++;
          name += ss.str();
          H5Tinsert(t, name.c_str(), offset, value());
          offset += HDF5_datatype_size<unsigned long>();
        }
      };

    template<>
      class data_type_traits<boost::uint16_t>
      {
      public:
        typedef boost::true_type is_homogeneous;
        static hid_t
        homogeneous_type()
        {
          return H5Tcopy(value());
        }
        static hid_t
        value()
        {
          return H5T_NATIVE_UINT16;
        }
        static hsize_t
        dimsize()
        {
          return 1;
        }
        static hsize_t
        num_type()
        {
          return 1;
        }
        static void
        insert_data_type(hid_t t, size_t & offset)
        {
          static int i = 0;
          std::string name("uint16");
          std::stringstream ss;
          ss << i++;
          name += ss.str();
          H5Tinsert(t, name.c_str(), offset, value());
          offset += HDF5_datatype_size<boost::uint16_t>();
        }
      };

    template<>
      class data_type_traits<boost::int16_t>
      {
      public:
        typedef boost::true_type is_homogeneous;
        static hid_t
        homogeneous_type()
        {
          return H5Tcopy(value());
        }
        static hid_t
        value()
        {
          return H5T_NATIVE_INT16;
        }
        static hsize_t
        dimsize()
        {
          return 1;
        }
        static hsize_t
        num_type()
        {
          return 1;
        }
        static void
        insert_data_type(hid_t t, size_t & offset)
        {
          static int i = 0;
          std::string name("int16");
          std::stringstream ss;
          ss << i++;
          name += ss.str();
          H5Tinsert(t, name.c_str(), offset, value());
          offset += HDF5_datatype_size<boost::int16_t>();
        }
      };

    template<>
      class data_type_traits<float>
      {
      public:
        typedef boost::true_type is_homogeneous;
        static hid_t
        homogeneous_type()
        {
          return H5Tcopy(value());
        }
        static hid_t
        value()
        {
          return H5T_NATIVE_FLOAT;
        }
        static hsize_t
        dimsize()
        {
          return 1;
        }
        static hsize_t
        num_type()
        {
          return 1;
        }
        static void
        insert_data_type(hid_t t, size_t & offset)
        {
          static int i = 0;
          std::string name("float");
          std::stringstream ss;
          ss << i++;
          name += ss.str();
          H5Tinsert(t, name.c_str(), offset, value());
          offset += HDF5_datatype_size<float>();
        }
      };

    template<>
      class data_type_traits<double>
      {
      public:
        typedef boost::true_type is_homogeneous;
        static hid_t
        homogeneous_type()
        {
          return H5Tcopy(value());
        }
        static hid_t
        value()
        {
          return H5T_NATIVE_DOUBLE;
        }
        static hsize_t
        dimsize()
        {
          return 1;
        }
        static hsize_t
        num_type()
        {
          return 1;
        }
        static void
        insert_data_type(hid_t t, size_t & offset)
        {
          static int i = 0;
          std::string name("double");
          std::stringstream ss;
          ss << i++;
          name += ss.str();
          H5Tinsert(t, name.c_str(), offset, value());
          offset += HDF5_datatype_size<double>();
        }
      };

    class HDF5FileHolder : boost::noncopyable
    {
    public:
      HDF5FileHolder(const std::string & path)
      {
        hid_t plist_id;
        plist_id = H5Pcreate(H5P_FILE_ACCESS);

        if (H5Fis_hdf5(path.c_str()) > 0)
        {
          file = H5Fopen(path.c_str(), H5F_ACC_RDWR, plist_id);
        }
        else
        {
          file = H5Fcreate(path.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, plist_id);
        }
        H5Pclose(plist_id);
        check_errors();
      }

      HDF5FileHolder(const std::string & path, Create)
      {
        hid_t plist_id;
        plist_id = H5Pcreate(H5P_FILE_ACCESS);

        file = H5Fcreate(path.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, plist_id);

        H5Pclose(plist_id);

        check_errors();
      }

      ~HDF5FileHolder()
      {
        H5Fclose(file);
      }

      hid_t
      hid() const
      {
        return file;
      }
    private:
      hid_t file;
    };

#ifdef H5_HAVE_PARALLEL
    class HDF5ParallelFileHolder : boost::noncopyable
    {
    public:
      HDF5ParallelFileHolder(const std::string & path)
      {
        hid_t plist_id;
        plist_id = H5Pcreate(H5P_FILE_ACCESS);

        //https://wickie.hlrs.de/platforms/index.php/MPI-IO

        //H5Pset_fapl_mpiposix(plist_id, MPI_COMM_WORLD, false);
        H5Pset_fapl_mpio(plist_id, MPI_COMM_WORLD, MPI_INFO_NULL);

        if (H5Fis_hdf5(path.c_str()) > 0)
        {
          file = H5Fopen(path.c_str(), H5F_ACC_RDWR, plist_id);
        }
        else
        {
          file = H5Fcreate(path.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, plist_id);
        }
        H5Pclose(plist_id);
        check_errors();
      }

      HDF5ParallelFileHolder(const std::string & path, Create)
      {
        hid_t plist_id;
        plist_id = H5Pcreate(H5P_FILE_ACCESS);

        //https://wickie.hlrs.de/platforms/index.php/MPI-IO

        //H5Pset_fapl_mpiposix(plist_id, MPI_COMM_WORLD, false);
        H5Pset_fapl_mpio(plist_id, MPI_COMM_WORLD, MPI_INFO_NULL);

        file = H5Fcreate(path.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, plist_id);

        H5Pclose(plist_id);

        check_errors();
      }

      ~HDF5ParallelFileHolder()
      {
        H5Fclose(file);
      }

      hid_t
      hid() const
      {
        return file;
      }
    private:
      hid_t file;
    };
#endif

    class HDF5DataSpace
    {
    public:
      HDF5DataSpace(hid_t space) :
          dataspace(space)
      {
        assert(H5Iget_type(space) == H5I_DATASPACE);
      }

      HDF5DataSpace(const HDF5DataSpace & other)
      {
        dataspace = H5Scopy(other.hid());
        check_errors();
      }

      HDF5DataSpace(const std::vector<hsize_t> &dims)
      {
        dataspace = H5Screate_simple(dims.size(), &dims[0], NULL);
        check_errors();
      }

      HDF5DataSpace(const std::vector<hsize_t> &dims,
          const std::vector<hsize_t> &maxdims)
      {
        assert(dims.size() == maxdims.size() || maxdims.empty());
        if (maxdims.empty())
          dataspace = H5Screate_simple(dims.size(), &dims[0], NULL);
        else
          dataspace = H5Screate_simple(dims.size(), &dims[0], &maxdims[0]);
        check_errors();
      }

      HDF5DataSpace(const HDF5DataSpace & orig,
          const std::vector<hsize_t> & offset,
          const std::vector<hsize_t> & stride,
          const std::vector<hsize_t> & count)
      {
        dataspace = H5Scopy(orig.hid());
        if(stride.size())
        {
          assert(offset.size() == stride.size() && stride.size() == count.size());

          H5Sselect_hyperslab(dataspace, H5S_SELECT_SET, &offset[0], &stride[0],
              &count[0], NULL);
        }
        else
          H5Sselect_hyperslab(dataspace, H5S_SELECT_SET, &offset[0], NULL,
              &count[0], NULL);

        check_errors();
      }

      HDF5DataSpace(const HDF5DataSpace & orig,
          const std::vector<hsize_t> & offset,
          const std::vector<hsize_t> & stride,
          const std::vector<hsize_t> & count,
          const std::vector<hsize_t> & block)
      {
        assert(
            offset.size() == stride.size() && stride.size() == count.size() && count.size() == block.size());
        dataspace = H5Scopy(orig.hid());
        H5Sselect_hyperslab(dataspace, H5S_SELECT_SET, &offset[0], &stride[0],
            &count[0], &block[0]);
        check_errors();
      }

      ~HDF5DataSpace()
      {
        H5Sclose(dataspace);
        check_errors();
      }

      hsize_t
      getNumDimensions() const
      {
        return H5Sget_simple_extent_ndims(dataspace);
      }

      std::vector<hsize_t>
      getDimensions() const
      {
        std::vector<hsize_t> dims(getNumDimensions());
        H5Sget_simple_extent_dims(dataspace, &dims[0], 0);
        return dims;
      }

      void
      selectAll()
      {
        H5Sselect_all(hid());
      }

      void
      selectNone()
      {
        H5Sselect_none(hid());
      }

      hid_t
      hid() const
      {
        return dataspace;
      }

      template<typename Type>
      static boost::shared_ptr<HDF5DataSpace>
      selectSubset(const HDF5DataSpace & orig, const std::vector<Type> &mapping)
      {
        boost::shared_ptr<HDF5DataSpace> newSpace(new HDF5DataSpace(orig));

        hsize_t dataspaceDims = newSpace->getNumDimensions();

        std::size_t numCoords = mapping.size() * dataspaceDims;
        std::vector<hsize_t> dims = newSpace->getDimensions();
        hsize_t dim2size = 1;
        if (dataspaceDims > 1)
        {
          numCoords *= dims[1];
          dim2size = dims[1];
        }
        std::size_t numElements = numCoords / dataspaceDims;

        newSpace->elements.resize(numCoords);
        std::vector<hsize_t>::iterator j = newSpace->elements.begin();
        for (typename std::vector<Type>::const_iterator i = mapping.begin();
            i != mapping.end(); ++i)
        {
          for (hsize_t l = 0; l < dim2size; ++l)
          {
            *j = *i;
            ++j;

            for (hsize_t k = 1; k < dataspaceDims; ++k, ++j)
              *j = l;
          }

          //printf("%i %i\n",*i,*j);

        }
        /*
         for(int i=0;i<newSpace->elements.size()/dataspaceDims;++i)
         {
         printf(" %i %i \n", newSpace->elements[i*dataspaceDims],newSpace->elements[i*dataspaceDims+1]);
         }
         */
        H5Sselect_elements(newSpace->hid(), H5S_SELECT_SET, numElements,
            &newSpace->elements[0]);

        //int t = H5Sget_select_npoints(newSpace->hid());

        //printf(" dims %i %i %i %i %i %i\n", numElements,numCoords,dataspaceDims,dims[0],t,orig.getNumDimensions());

        return newSpace;
      }
    public:
      /**
       * Logically and the two slabs together
       */
      HDF5DataSpace &
      operator &(const HDF5DataSpace & other)
      {
        checkExtentsMatch(other);
        return *this;
      }

      /**
       * Logically xor the two slabs together
       */
      HDF5DataSpace &
      operator ^(const HDF5DataSpace & other)
      {

        return *this;
      }

      /**
       * Logically or the two slabs together
       */
      HDF5DataSpace &
      operator |(const HDF5DataSpace & other)
      {

        return *this;
      }

      /**
       * Logical not
       */
      HDF5DataSpace &
      operator !()
      {

        return *this;
      }

    private:
      void
      checkExtentsMatch(const HDF5DataSpace & other) const
      {
#if H5_VERS_MINOR >= 8
        htri_t r = H5Sextent_equal(hid(), other.hid());
        if (r == 0)
          throw; //Extents don't match
        if (r < 1)
          throw; //Error
#endif
      }
    private:
      hid_t dataspace;

      // Used for selections
      std::vector<hsize_t> elements;
    };

    class HDF5DataType : boost::noncopyable
    {
    public:
      template<class Type>
        HDF5DataType(wrapper<Type> t)
        {
          createType(t);
        }

      template<class Type>
        HDF5DataType(Type)
        {
          wrapper<Type> t;
          createType(t);
        }

      ~HDF5DataType()
      {
        /*status = */H5Tclose(datatype);
        check_errors();
      }

      void
      setLittleEndian()
      {
        H5Tset_order(datatype, H5T_ORDER_LE);
        check_errors();
      }

      void
      setBigEndian()
      {
        H5Tset_order(datatype, H5T_ORDER_BE);
        check_errors();
      }

      hsize_t
      getDim() const
      {
        return dim;
      }

      hid_t
      hid() const
      {
        return datatype;
      }
    private:
      template<class Type>
        void
        createType(wrapper<Type> t)
        {
          DataTypeCreator type(t);
          datatype = type.type;
          dim = type.dim;
          check_errors();
        }
    private:
      hsize_t dim;
      hid_t datatype;
    };

    class HDF5DataSet : boost::noncopyable
    {
    public:
      template<class Parent>
        HDF5DataSet(Parent & p, const std::string &name)
        {
          if (H5Lexists(p.hid(), name.c_str(), H5P_DEFAULT) != true)
          {
            throw DatasetNotFound();
          }

#if H5_VERS_MINOR >= 8
          dataset = H5Dopen(p.hid(), name.c_str(), H5P_DEFAULT);
#else
          dataset = H5Dopen(p.hid(), name.c_str());
#endif
          space.reset(new HDF5DataSpace(H5Dget_space(dataset)));

          check_errors();
        }

      template<class Parent>
        HDF5DataSet(Parent & p, const std::string name,
            const HDF5DataType &datatype, const HDF5DataSpace &dataspace)
        {
          hid_t cparms;
          if (H5Lexists(p.hid(), name.c_str(), H5P_DEFAULT) == true)
          {
            throw DatasetExists();
          }

          cparms = H5Pcreate(H5P_DATASET_CREATE);
//       //@todo: chunk the datset
//       hsize_t chunk_dims[2] = {2,2};
//       H5Pset_chunk(cparms, 2, chunk_dims);
#if H5_VERS_MINOR >= 8
          dataset = H5Dcreate(p.hid(), name.c_str(), datatype.hid(),
              dataspace.hid(), H5P_DEFAULT, cparms, H5P_DEFAULT);
#else
          dataset = H5Dcreate(p.hid(), name.c_str(), datatype.hid(), dataspace.hid(), cparms);
#endif
          H5Pclose(cparms);

          space.reset(new HDF5DataSpace(H5Dget_space(dataset)));

          check_errors();
        }

      ~HDF5DataSet()
      {
        /*status = */H5Dclose(dataset);
        check_errors();
      }

      boost::shared_ptr<HDF5DataSpace>
      getDataSpace() const
      {
        return space;
      }

      template<typename Type>
      boost::shared_ptr<HDF5DataSet>
      selectSubset(const std::vector<Type> & mapping)
      {
        boost::shared_ptr<HDF5DataSet> newDataset(new HDF5DataSet(dataset));
        newDataset->space = HDF5DataSpace::selectSubset(*space, mapping);
        return newDataset;
      }

      ///@todo: getAttribute(const char * name)

      hid_t
      hid() const
      {
        return dataset;
      }
    private:
      HDF5DataSet(hid_t d) :
          dataset(d)
      {
        assert(H5Iget_type(dataset)==H5I_DATASET);
        H5Iinc_ref(dataset);
      }
    private:
      hid_t dataset;
      boost::shared_ptr<HDF5DataSpace> space;
    };

    class HDF5Group : boost::noncopyable
    {
    public:
      template<class Parent>
        HDF5Group(Parent & p, const std::string & path, Create)
        {
#if H5_VERS_MINOR >= 8
          group = H5Gcreate(p.hid(), path.c_str(), 0, H5P_DEFAULT, H5P_DEFAULT);
#else
          group = H5Gcreate(p.hid(), path.c_str(), 0);
#endif
          if (group < 0)
            throw;
          check_errors();
        }

      template<class Parent>
        HDF5Group(Parent & p, const std::string & path, bool create)
            throw (GroupNotFound)
        {
          if (H5Lexists(p.hid(), path.c_str(), H5P_DEFAULT) || path == "/")
          {

#if H5_VERS_MINOR >= 8
            group = H5Gopen(p.hid(), path.c_str(), H5P_DEFAULT);
#else
            group = H5Gopen(p.hid(), path.c_str());
#endif
          }
          else if (create)
          {
            //Group didn't exist and we've asked to create the group
#if H5_VERS_MINOR >= 8
            group = H5Gcreate(p.hid(), path.c_str(), 0, H5P_DEFAULT,
                H5P_DEFAULT);
#else
            group = H5Gcreate(p.hid(), path.c_str(), 0);
#endif
            if (group < 0)
              throw; //Error creating group
          }
          else
          {
            throw GroupNotFound();
          }
        }

      /**
       * Create external link
       */
      template<class Parent>
        HDF5Group(Parent & p,
            const std::string & externalFile,
            const std::string & externalPath,
            const std::string & path, Create)
        {
#if H5_VERS_MINOR >= 8
          group = H5Lcreate_external(externalFile.c_str(),externalPath.c_str(),
              p.hid(), path.c_str(), H5P_DEFAULT, H5P_DEFAULT);
#else
          group = H5Lcreate_external(p.hid(), path.c_str());
#endif
          if (group < 0)
            throw;
          check_errors();
        }

      ~HDF5Group()
      {
        H5Gclose(group);
        check_errors();
      }

      hid_t
      hid() const
      {
        return group;
      }
    private:
      hid_t group;
    };

    class HDF5Attribute : boost::noncopyable
    {
    public:

      template<class Object>
        HDF5Attribute(Object & p, const std::string &name)
        {
          if (H5Aexists(p.hid(), name.c_str()) != true)
          {
            throw AttributeNotFound();
          }

          attribute = H5Aopen_name(p.hid(), name.c_str());
          check_errors();
        }

      template<class Type, class Object>
        HDF5Attribute(Object & p, const std::string &name,
            const std::vector<hsize_t>& dims,
            const std::vector<hsize_t> &maxdims, Type t)
        {
          if (H5Aexists(p.hid(), name.c_str()) == true)
          {
            throw AttributeExists();
          }

          HDF5DataSpace space(dims, maxdims);
          HDF5DataType type(t);

#if H5_VERS_MINOR >= 8
          attribute = H5Acreate(p.hid(), name.c_str(), type.hid(), space.hid(),
              H5P_DEFAULT, H5P_DEFAULT);
#else
          attribute = H5Acreate(p.hid(), name.c_str(), type.hid(), space.hid(), H5P_DEFAULT);
#endif
          check_errors();
        }

      ~HDF5Attribute()
      {
        H5Aclose(attribute);
        check_errors();
      }

      hid_t
      hid() const
      {
        return attribute;
      }
    private:
      hid_t attribute;
    };

  }

  class HDF5Traits
  {
  public:
    typedef detail::HDF5FileHolder file_handle_type;
#ifdef H5_HAVE_PARALLEL
    typedef detail::HDF5ParallelFileHolder parallel_file_handle_type;
#endif
    typedef detail::HDF5Group group_type;
    typedef detail::HDF5DataType datatype_type;
    typedef detail::HDF5DataSet dataset_type;
    typedef detail::HDF5Attribute attribute_type;
    typedef detail::HDF5DataSpace slab_type;

    static boost::shared_ptr<file_handle_type>
    open(const std::string & path, bool truncate)
    {
      if (truncate)
      {
        detail::Create c;
        return boost::shared_ptr<file_handle_type>(
            new file_handle_type(path, c));
      }
      return boost::shared_ptr<file_handle_type>(new file_handle_type(path));
    }
#ifdef H5_HAVE_PARALLEL
    static boost::shared_ptr<parallel_file_handle_type>
    parallel_open(const std::string & path, bool truncate)
    {
      if (truncate)
      {
        detail::Create c;
        return boost::shared_ptr<parallel_file_handle_type>(
            new parallel_file_handle_type(path, c));
      }
      return boost::shared_ptr<parallel_file_handle_type>(new parallel_file_handle_type(path));
    }
#endif
    template<typename FileHandle>
    static boost::shared_ptr<group_type>
    openGroup(FileHandle & f, const std::string & path, bool create)
    {
      return boost::shared_ptr<group_type>(new group_type(f, path, create));
    }

    static boost::shared_ptr<group_type>
    openGroup(group_type & f, const std::string & path, bool create)
    {
      return boost::shared_ptr<group_type>(new group_type(f, path, create));
    }

    template<typename FileHandle>
    static boost::shared_ptr<group_type>
    createGroup(FileHandle & f, const std::string & path)
    {
      return boost::shared_ptr<group_type>(
          new group_type(f, path, detail::Create()));
    }

    static boost::shared_ptr<group_type>
    createGroup(group_type & f, const std::string & path)
    {
      return boost::shared_ptr<group_type>(
          new group_type(f, path, detail::Create()));
    }

    static boost::shared_ptr<group_type>
    createExternalLink(group_type & f,
        const std::string & externalFile,
        const std::string & externalPath,
        const std::string & path)
    {
      return boost::shared_ptr<group_type>(
          new group_type(f,externalFile,
              externalPath, path, detail::Create()));
    }

    template<typename FileHandle>
    static boost::shared_ptr<dataset_type>
    openDataSet(FileHandle & f, const std::string & path)
    {
      return boost::shared_ptr<dataset_type>(new dataset_type(f, path));
    }

    static boost::shared_ptr<dataset_type>
    openDataSet(group_type & f, const std::string & path)
    {
      return boost::shared_ptr<dataset_type>(new dataset_type(f, path));
    }

    template<class Type>
      static boost::shared_ptr<attribute_type>
      createAttribute(group_type & g, const std::string & name,
          const std::vector<hsize_t> &dims, const std::vector<hsize_t> &maxdims)
      {
        return boost::shared_ptr<attribute_type>(
            new attribute_type(g, name, dims, maxdims, Type()));
      }

    template<class Type>
      static boost::shared_ptr<attribute_type>
      createAttribute(dataset_type & g, const std::string & name,
          const std::vector<hsize_t> &dims, const std::vector<hsize_t> &maxdims)
      {
        return boost::shared_ptr<attribute_type>(
            new attribute_type(g, name, dims, maxdims, Type()));
      }

    static boost::shared_ptr<attribute_type>
    openAttribute(group_type & g, const std::string & name)
    {
      return boost::shared_ptr<attribute_type>(new attribute_type(g, name));
    }

    static boost::shared_ptr<attribute_type>
    openAttribute(dataset_type & g, const std::string & name)
    {
      return boost::shared_ptr<attribute_type>(new attribute_type(g, name));
    }

    template<class Type,typename FileHandle>
      static boost::shared_ptr<dataset_type>
      createDataSet(FileHandle & f, const std::string & path,
          const detail::HDF5DataSpace & space)
      {
        detail::HDF5DataType type((detail::wrapper<Type>()));
        return boost::shared_ptr<dataset_type>(
            new dataset_type(f, path, type, space));
      }

    template<typename Type>
      static boost::shared_ptr<dataset_type>
      createDataSet(group_type & f, const std::string & path,
          const detail::HDF5DataSpace &space)
      {
        detail::wrapper<Type> t;
        detail::HDF5DataType datatype(t);
        // Note DataSpace assumes that datatype is of dim 1
        // This is incorrect for homogeneous complex types
        // We should create new dataspace to account for dimension
        if(datatype.getDim() > 1)
        {
          std::vector<hsize_t> dims(2,space.getDimensions()[0]);
          dims[1] = datatype.getDim();
          detail::HDF5DataSpace filespace(dims);
          return boost::shared_ptr<dataset_type>(
              new dataset_type(f, path, datatype, filespace));
        }
        else
        {
          return boost::shared_ptr<dataset_type>(
              new dataset_type(f, path, datatype, space));
        }
      }

    template<typename Type>
      static void
      write_attribute(const attribute_type & attribute, const Type & data)
      {
        detail::wrapper<Type> t;
        detail::HDF5DataType datatype(t);
        H5Awrite(attribute.hid(), datatype.hid(), &data);
      }

    template<typename Type>
      static void
      write_attribute(const attribute_type & attribute,
          const std::vector<Type> & data)
      {
        detail::wrapper<Type> t;
        detail::HDF5DataType memdatatype(t);
        H5Awrite(attribute.hid(), memdatatype.hid(), &data);
      }

/*    struct T{
      int a; float b;
    };
*/
    template<typename Type>
      static void
      write_dataset(const dataset_type & dataset,
          const std::vector<Type> & data)
      {
        std::vector<hsize_t> d = getDims(data);
        detail::HDF5DataSpace memorySpace(d);
        detail::wrapper<Type> t;
        detail::HDF5DataType memdatatype(t);
/*
        if(d.size()==1){
          T tt[2];
          tt[0].a = 1; tt[0].b = 2;
          tt[1].a = 3; tt[1].b = 4;

          herr_t status = H5Dwrite(dataset.hid(), memdatatype.hid(), memorySpace.hid(), H5S_ALL,
              H5P_DEFAULT, &data[0]);
          assert(status == 0);
        }
        else
*/
        {
          herr_t status = H5Dwrite(dataset.hid(), memdatatype.hid(), memorySpace.hid(), H5S_ALL,
              H5P_DEFAULT, &data[0]);
          assert(status == 0);
        }
      }
#ifdef H5_HAVE_PARALLEL
    template<typename Type>
    static void
    write_parallel_dataset(const dataset_type & dataset, const std::vector<Type> & data)
    {
      hid_t plist_id;
      plist_id = H5Pcreate(H5P_DATASET_XFER);
      H5Pset_dxpl_mpio(plist_id, H5FD_MPIO_COLLECTIVE);

      std::vector<hsize_t> d = getDims(data);
      detail::HDF5DataSpace memorySpace(d);
      detail::wrapper<Type> t;
      detail::HDF5DataType memdatatype(t);
      H5Dwrite(dataset.hid(), memdatatype.hid(), memorySpace.hid(), H5S_ALL, plist_id, &data[0]);
    }
#endif
    template<typename Type>
      static void
      write_dataset(const dataset_type & dataset, const Type * data,
          const detail::HDF5DataSpace &memorySpace)
      {
        detail::wrapper<Type> t;
        detail::HDF5DataType memdatatype(t);
        boost::shared_ptr<detail::HDF5DataSpace> fileSpace = dataset.getDataSpace();

        H5Dwrite(dataset.hid(), memdatatype.hid(), memorySpace.hid(), fileSpace->hid(),
            H5P_DEFAULT, data);
        //H5Sclose(fileSpace);
      }
#ifdef H5_HAVE_PARALLEL
    template<typename Type>
      static void
      write_parallel_dataset(const dataset_type & dataset, const Type * data,
          const detail::HDF5DataSpace &memorySpace)
      {
        hid_t plist_id;
        plist_id = H5Pcreate(H5P_DATASET_XFER);
        H5Pset_dxpl_mpio(plist_id, H5FD_MPIO_COLLECTIVE);

        detail::wrapper<Type> t;
        detail::HDF5DataType memdatatype(t);
        boost::shared_ptr<detail::HDF5DataSpace> fileSpace = dataset.getDataSpace();

        H5Dwrite(dataset.hid(), memdatatype.hid(), memorySpace.hid(), fileSpace->hid(),
            plist_id, data);
        //H5Sclose(fileSpace);
      }
#endif
    template<typename Type>
      static void
      write_dataset(const dataset_type & dataset, const Type * data,
          const detail::HDF5DataSpace &memorySpace,
          const detail::HDF5DataSpace &fileSpace)
      {
        detail::wrapper<Type> t;
        detail::HDF5DataType memdatatype(t);
        //hid_t fileSpace = H5Dget_space(dataset.hid());
        H5Dwrite(dataset.hid(), memdatatype.hid(), memorySpace.hid(), fileSpace.hid(),
            H5P_DEFAULT, data);
        //H5Sclose(fileSpace);
      }
#ifdef H5_HAVE_PARALLEL
    template<typename Type>
      static void
      write_parallel_dataset(const dataset_type & dataset, const Type * data,
          const detail::HDF5DataSpace &memorySpace,
          const detail::HDF5DataSpace &fileSpace)
      {
        hid_t plist_id;
        plist_id = H5Pcreate(H5P_DATASET_XFER);
        H5Pset_dxpl_mpio(plist_id, H5FD_MPIO_COLLECTIVE);

        detail::wrapper<Type> t;
        detail::HDF5DataType memdatatype(t);
        //hid_t fileSpace = H5Dget_space(dataset.hid());
        H5Dwrite(dataset.hid(), memdatatype.hid(), memorySpace.hid(), fileSpace.hid(),
            plist_id, data);
        //H5Sclose(fileSpace);
      }
#endif
    template<typename Type>
      static void
      read_attribute(const attribute_type & attribute, Type & data)
      {
        detail::wrapper<Type> t;
        detail::HDF5DataType datatype(t);
        H5Aread(attribute.hid(), datatype.hid(), &data);
      }

    template<typename Type>
      static void
      read_dataset(const dataset_type & dataset, std::vector<Type> & data)
      {
        boost::shared_ptr<detail::HDF5DataSpace> fileSpace =
            dataset.getDataSpace();
        if (data.empty())
        {
          hsize_t sel = H5Sget_select_npoints(fileSpace->hid());

          /*
          std::vector<hsize_t> dims = fileSpace->getDimensions();
          std::size_t size = dims[0];
          for (int i = 1; i < dims.size(); ++i)
            size *= dims[i];
          assert(sel != size);
          */
          data.resize(sel);
        }
        std::vector<hsize_t> d(1, data.size());
        detail::HDF5DataSpace memorySpace(d);
        detail::wrapper<Type> t;
        detail::HDF5DataType datatype(t);
        H5Dread(dataset.hid(), datatype.hid(), memorySpace.hid(),
            fileSpace->hid(), H5P_DEFAULT, &data[0]);
      }

    template<typename Type>
      static void
      read_dataset(const dataset_type & dataset, Type * data,
          const detail::HDF5DataSpace & memorySpace)
      {
        boost::shared_ptr<detail::HDF5DataSpace> fileSpace =
            dataset.getDataSpace();
        detail::wrapper<Type> t;
        detail::HDF5DataType datatype(t);

//       output_dims(memorySpace.hid());
//       output_dims(fileSpace->hid());
        H5Dread(dataset.hid(), datatype.hid(), memorySpace.hid(),
            fileSpace->hid(), H5P_DEFAULT, data);
      }

    template<typename Type>
      static void
      read_dataset(const dataset_type & dataset, Type * data,
          const detail::HDF5DataSpace & memorySpace,
          const detail::HDF5DataSpace &fileSpace)
      {
        detail::wrapper<Type> t;
        detail::HDF5DataType datatype(t);

//       output_dims(memorySpace.hid());
//       output_dims(fileSpace->hid());
        H5Dread(dataset.hid(), datatype.hid(), memorySpace.hid(),
            fileSpace.hid(), H5P_DEFAULT, data);
      }
#ifdef H5_HAVE_PARALLEL
    template<typename Type>
      static void
      read_parallel_dataset(const dataset_type & dataset, Type * data,
          const detail::HDF5DataSpace & memorySpace)
      {
        hid_t plist_id;
        plist_id = H5Pcreate(H5P_DATASET_XFER);
        H5Pset_dxpl_mpio(plist_id, H5FD_MPIO_COLLECTIVE);

        boost::shared_ptr<detail::HDF5DataSpace> fileSpace =
            dataset.getDataSpace();
        detail::wrapper<Type> t;
        detail::HDF5DataType datatype(t);

//       output_dims(memorySpace.hid());
//       output_dims(fileSpace->hid());
        H5Dread(dataset.hid(), datatype.hid(), memorySpace.hid(),
            fileSpace->hid(), plist_id, data);
      }

    template<typename Type>
      static void
      read_parallel_dataset(const dataset_type & dataset, Type * data,
          const detail::HDF5DataSpace & memorySpace,
          const detail::HDF5DataSpace & fileSpace)
      {
        hid_t plist_id;
        plist_id = H5Pcreate(H5P_DATASET_XFER);
        H5Pset_dxpl_mpio(plist_id, H5FD_MPIO_COLLECTIVE);

        detail::wrapper<Type> t;
        detail::HDF5DataType datatype(t);

        //output_dims(memorySpace.hid());
        //output_dims(fileSpace.hid());
        H5Dread(dataset.hid(), datatype.hid(), memorySpace.hid(),
            fileSpace.hid(), plist_id, data);
      }
#endif
    template<typename Type>
      static void
      read_dataset(const dataset_type & dataset, Type & data)
      {
        boost::shared_ptr<detail::HDF5DataSpace> fileSpace =
            dataset.getDataSpace();
        detail::wrapper<Type> t;
        detail::HDF5DataType datatype(t);
        H5Dread(dataset.hid(), datatype.hid(), fileSpace->hid(),
            fileSpace->hid(), H5P_DEFAULT, data);
      }

    template<typename HID>
      static void
      deleteDataset(HID & h, const std::string & path)
      {
        H5Ldelete(h.hid(), path.c_str(), H5P_DEFAULT);
      }

    template<typename Type>
      static std::vector<hsize_t>
      getDims(const std::vector<Type> & t)
      {
        //if( detail::data_type_traits<Type>::is_homogeneous::value)
        {
          std::vector<hsize_t> dims(2, detail::data_type_traits<Type>::dimsize());
          dims[0] = t.size();
          return dims;
        }/*
        else
        {
          std::vector<hsize_t> dims(1);//2, detail::data_type_traits<Type>::num_type());
          dims[0] = t.size();
          return dims;
        }*/

      }
  };
}

max_stars_repo_name: zCFD/foamTozCFD

max_issues_repo_name: zCFD/foamTozCFD

max_forks_repo_name: zCFD/foamTozCFD