<commit_before>#include "simlib/file_manip.hh"
#include "simlib/call_in_destructor.hh"
#include "simlib/directory.hh"
#include "simlib/file_descriptor.hh"
#include "simlib/file_path.hh"
#include "simlib/inplace_buff.hh"
#include "simlib/random.hh"
#include "simlib/repeating.hh"

#include <cstddef>
#include <cstdio>
#include <fcntl.h>
#include <linux/limits.h>
#include <new>
#include <sys/stat.h>
#include <unistd.h>
#include <utility>

using std::array;
using std::string;

int mkdir_r(string path, mode_t mode) noexcept {
	if (path.size() >= PATH_MAX) {
		errno = ENAMETOOLONG;
		return -1;
	}

	// Add ending slash (if not exists)
	if (path.empty() || path.back() != '/') {
		path += '/';
	}

	size_t end = 1; // If there is a leading slash, it will be omitted
	while (end < path.size()) {
		while (path[end] != '/') {
			++end;
		}

		path[end] = '\0'; // Separate subpath
		if (mkdir(path.data(), mode) == -1 && errno != EEXIST) {
			return -1;
		}

		path[end++] = '/';
	}

	return 0;
}

/**
 * @brief Removes recursively directory @p path relative to a directory
 *   file descriptor @p dirfd
 *
 * @param dirfd directory file descriptor
 * @param path directory pathname (relative to @p dirfd)
 *
 * @return 0 on success, -1 on error
 *
 * @errors The same that occur for fstatat64(2), openat(2), unlinkat(2),
 *   fdopendir(3)
 */
static int __remove_rat(int dirfd, FilePath path) noexcept {
	int fd =
	   openat(dirfd, path, O_RDONLY | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
	if (fd == -1) {
		return unlinkat(dirfd, path, 0);
	}

	DIR* dir = fdopendir(fd);
	if (dir == nullptr) {
		close(fd);
		return unlinkat(dirfd, path, AT_REMOVEDIR);
	}

	int ec = 0;
	int rc = 0;
	for_each_dir_component(
	   dir,
	   [&](dirent* file) -> repeating {
#ifdef _DIRENT_HAVE_D_TYPE
		   if (file->d_type == DT_DIR || file->d_type == DT_UNKNOWN) {
#endif
			   if (__remove_rat(fd, file->d_name)) {
				   ec = errno;
				   rc = -1;
				   return stop_repeating;
			   }
#ifdef _DIRENT_HAVE_D_TYPE
		   } else if (unlinkat(fd, file->d_name, 0)) {
			   ec = errno;
			   rc = -1;
			   return stop_repeating;
		   }
#endif

		   return continue_repeating;
	   },
	   [&] {
		   ec = errno;
		   rc = -1;
	   });

	(void)closedir(dir);

	if (rc == -1) {
		errno = ec;
		return -1;
	}

	return unlinkat(dirfd, path, AT_REMOVEDIR);
}

int remove_rat(int dirfd, FilePath path) noexcept {
	return __remove_rat(dirfd, path);
}

int remove_dir_contents_at(int dirfd, FilePath pathname) noexcept {
	int fd =
	   openat(dirfd, pathname, O_RDONLY | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
	if (fd == -1) {
		return -1;
	}

	DIR* dir = fdopendir(fd);
	if (dir == nullptr) {
		int ec = errno;
		close(fd);
		errno = ec;
		return -1;
	}

	int ec = 0;
	int rc = 0;
	for_each_dir_component(
	   dir,
	   [&](dirent* file) -> repeating {
#ifdef _DIRENT_HAVE_D_TYPE
		   if (file->d_type == DT_DIR || file->d_type == DT_UNKNOWN) {
#endif
			   if (__remove_rat(fd, file->d_name)) {
				   ec = errno;
				   rc = -1;
				   return stop_repeating;
			   }
#ifdef _DIRENT_HAVE_D_TYPE
		   } else if (unlinkat(fd, file->d_name, 0)) {
			   ec = errno;
			   rc = -1;
			   return stop_repeating;
		   }
#endif

		   return continue_repeating;
	   },
	   [&] {
		   ec = errno;
		   rc = -1;
	   });

	(void)closedir(dir);

	if (rc == -1) {
		errno = ec;
	}

	return rc;
}

int create_subdirectories(FilePath file) noexcept {
	StringView path(file);
	path.remove_trailing([](char c) { return (c != '/'); });
	if (path.empty()) {
		return 0;
	}

	return mkdir_r(path.to_string());
}

int blast(int infd, int outfd) noexcept {
	array<char, 65536> buff{};
	ssize_t len = 0;
	ssize_t written = 0;
	while (len = read(infd, buff.data(), buff.size()),
	       len > 0 || (len == -1 && errno == EINTR))
	{
		ssize_t pos = 0;
		while (pos < len) {
			written = write(outfd, buff.data() + pos, len - pos);
			if (written > 0) {
				pos += written;
			} else if (errno != EINTR) {
				return -1;
			}
		}
	}

	if (len == -1) {
		return -1;
	}

	return 0;
}

int copyat_using_rename(int src_dirfd, FilePath src, int dest_dirfd,
                        FilePath dest, mode_t mode) noexcept {
	FileDescriptor src_fd{openat(src_dirfd, src, O_RDONLY | O_CLOEXEC)};
	if (not src_fd.is_open()) {
		return -1;
	}

	try {
		constexpr uint suffix_len = 10;
		InplaceBuff<PATH_MAX> tmp_dest{std::in_place, dest, '.'};
		tmp_dest.resize(tmp_dest.size + suffix_len + 1); // +1 for trailing '\0'
		--tmp_dest.size;
		FileDescriptor dest_fd;
		for (size_t try_num = 0; try_num < 128; ++try_num) {
			for (size_t i = tmp_dest.size - suffix_len; i < tmp_dest.size; ++i)
			{
				tmp_dest[i] = get_random('a', 'z');
			}

			dest_fd = openat(dest_dirfd, tmp_dest.to_cstr().data(),
			                 O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode);
			if (dest_fd.is_open()) {
				break;
			}
			if (errno == EEXIST) {
				continue;
			}
			return -1; // Other error occurred
		}

		CallInDtor tmp_dest_remover = [&] {
			(void)unlinkat(dest_dirfd, tmp_dest.to_cstr().data(), 0);
		};

		if (blast(src_fd, dest_fd)) {
			return -1;
		}
		if (renameat(dest_dirfd, tmp_dest.to_cstr().data(), dest_dirfd, dest)) {
			return -1;
		}
		// Success
		tmp_dest_remover.cancel();
		return 0;
	} catch (...) {
		errno = ENOMEM;
		return -1;
	}
}

int copyat(int src_dirfd, FilePath src, int dest_dirfd, FilePath dest,
           mode_t mode) noexcept {
	constexpr auto open_flags = O_WRONLY | O_TRUNC | O_CLOEXEC;
	FileDescriptor out(
	   openat(dest_dirfd, dest, open_flags | O_CREAT | O_EXCL, mode));
	bool file_created = true;
	if (not out.is_open() and errno == EEXIST) {
		file_created = false;
		out = openat(dest_dirfd, dest, open_flags);
	}
	if (not out.is_open()) {
		if (errno != ETXTBSY) {
			return -1;
		}
		return copyat_using_rename(src_dirfd, src, dest_dirfd, dest, mode);
	}

	FileDescriptor in(openat(src_dirfd, src, O_RDONLY | O_CLOEXEC));
	if (not in.is_open()) {
		return -1;
	}
	if (blast(in, out)) {
		return -1;
	}

	if (not file_created) {
		off64_t offset = lseek64(out, 0, SEEK_CUR);
		if (offset == static_cast<decltype(offset)>(-1)) {
			return -1;
		}
		if (ftruncate64(out, offset)) {
			return -1;
		}
		if (fchmod(out, mode)) {
			return -1;
		}
	}
	return 0;
}

int copyat_using_rename(int src_dirfd, FilePath src, int dest_dirfd,
                        FilePath dest) noexcept {
	struct stat64 sb {};
	if (fstatat64(src_dirfd, src, &sb, 0)) {
		return -1;
	}
	return copyat_using_rename(src_dirfd, src, dest_dirfd, dest, sb.st_mode);
}

int copyat(int src_dirfd, FilePath src, int dest_dirfd,
           FilePath dest) noexcept {
	struct stat64 sb {};
	if (fstatat64(src_dirfd, src, &sb, 0)) {
		return -1;
	}

	return copyat(src_dirfd, src, dest_dirfd, dest, sb.st_mode);
}

/**
 * @brief Copies directory @p src to @p dest relative to the directory file
 *   descriptors
 *
 * @param src_dirfd directory file descriptor
 * @param src source directory (relative to @p src_dirfd)
 * @param dest_dirfd directory file descriptor
 * @param dest destination directory (relative to @p dest_dirfd)
 *
 * @return 0 on success, -1 on error
 *
 * @errors The same that occur for fstat64(2), openat(2), fdopendir(3),
 *   mkdirat(2), copyat()
 */
static int __copy_rat(int src_dirfd, FilePath src, int dest_dirfd,
                      FilePath dest) noexcept {
	int src_fd = openat(src_dirfd, src, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
	if (src_fd == -1) {
		if (errno == ENOTDIR) {
			return copyat(src_dirfd, src, dest_dirfd, dest);
		}

		return -1;
	}

	// Do not use src permissions
	mkdirat(dest_dirfd, dest, S_0755);

	int dest_fd = openat(dest_dirfd, dest, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
	if (dest_fd == -1) {
		close(src_fd);
		return -1;
	}

	DIR* src_dir = fdopendir(src_fd);
	if (src_dir == nullptr) {
		close(src_fd);
		close(dest_fd);
		return -1;
	}

	int ec = 0;
	int rc = 0;
	for_each_dir_component(
	   src_dir,
	   [&](dirent* file) -> repeating {
#ifdef _DIRENT_HAVE_D_TYPE
		   if (file->d_type == DT_DIR || file->d_type == DT_UNKNOWN) {
#endif
			   if (__copy_rat(src_fd, file->d_name, dest_fd, file->d_name)) {
				   ec = errno;
				   rc = -1;
				   return stop_repeating;
			   }

#ifdef _DIRENT_HAVE_D_TYPE
		   } else {
			   if (copyat(src_fd, file->d_name, dest_fd, file->d_name)) {
				   ec = errno;
				   rc = -1;
				   return stop_repeating;
			   }
		   }
#endif

		   return continue_repeating;
	   },
	   [&] {
		   ec = errno;
		   rc = -1;
	   });

	closedir(src_dir);
	close(dest_fd);

	if (rc == -1) {
		errno = ec;
	}

	return rc;
}

int copy_rat(int src_dirfd, FilePath src, int dest_dirfd,
             FilePath dest) noexcept {
	struct stat64 sb {};
	if (fstatat64(src_dirfd, src, &sb, 0) == -1) {
		return -1;
	}

	if (S_ISDIR(sb.st_mode)) {
		return __copy_rat(src_dirfd, src, dest_dirfd, dest);
	}

	return copyat(src_dirfd, src, dest_dirfd, dest, sb.st_mode & ACCESSPERMS);
}

int copy_r(FilePath src, FilePath dest, bool create_subdirs) noexcept {
	if (create_subdirs and create_subdirectories(CStringView(dest)) == -1) {
		return -1;
	}

	return copy_rat(AT_FDCWD, src, AT_FDCWD, dest);
}

int move(FilePath oldpath, FilePath newpath, bool create_subdirs) noexcept {
	if (create_subdirs and create_subdirectories(CStringView(newpath)) == -1) {
		return -1;
	}

	if (rename(oldpath, newpath) == -1) {
		if (errno == EXDEV && copy_r(oldpath, newpath, false) == 0) {
			return remove_r(oldpath);
		}

		return -1;
	}

	return 0;
}

int create_file(FilePath pathname, mode_t mode) noexcept {
	int fd = open(pathname, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, mode);
	if (fd == -1) {
		return -1;
	}

	return close(fd);
}
<commit_msg>file_manip.hh: copy_using_rename() fixed potential race condition that may lead to ETXTBSY<commit_after>#include "simlib/file_manip.hh"
#include "simlib/call_in_destructor.hh"
#include "simlib/directory.hh"
#include "simlib/file_descriptor.hh"
#include "simlib/file_path.hh"
#include "simlib/inplace_buff.hh"
#include "simlib/random.hh"
#include "simlib/repeating.hh"

#include <cstddef>
#include <cstdio>
#include <fcntl.h>
#include <linux/limits.h>
#include <new>
#include <sys/stat.h>
#include <unistd.h>
#include <utility>

using std::array;
using std::string;

int mkdir_r(string path, mode_t mode) noexcept {
	if (path.size() >= PATH_MAX) {
		errno = ENAMETOOLONG;
		return -1;
	}

	// Add ending slash (if not exists)
	if (path.empty() || path.back() != '/') {
		path += '/';
	}

	size_t end = 1; // If there is a leading slash, it will be omitted
	while (end < path.size()) {
		while (path[end] != '/') {
			++end;
		}

		path[end] = '\0'; // Separate subpath
		if (mkdir(path.data(), mode) == -1 && errno != EEXIST) {
			return -1;
		}

		path[end++] = '/';
	}

	return 0;
}

/**
 * @brief Removes recursively directory @p path relative to a directory
 *   file descriptor @p dirfd
 *
 * @param dirfd directory file descriptor
 * @param path directory pathname (relative to @p dirfd)
 *
 * @return 0 on success, -1 on error
 *
 * @errors The same that occur for fstatat64(2), openat(2), unlinkat(2),
 *   fdopendir(3)
 */
static int __remove_rat(int dirfd, FilePath path) noexcept {
	int fd =
	   openat(dirfd, path, O_RDONLY | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
	if (fd == -1) {
		return unlinkat(dirfd, path, 0);
	}

	DIR* dir = fdopendir(fd);
	if (dir == nullptr) {
		close(fd);
		return unlinkat(dirfd, path, AT_REMOVEDIR);
	}

	int ec = 0;
	int rc = 0;
	for_each_dir_component(
	   dir,
	   [&](dirent* file) -> repeating {
#ifdef _DIRENT_HAVE_D_TYPE
		   if (file->d_type == DT_DIR || file->d_type == DT_UNKNOWN) {
#endif
			   if (__remove_rat(fd, file->d_name)) {
				   ec = errno;
				   rc = -1;
				   return stop_repeating;
			   }
#ifdef _DIRENT_HAVE_D_TYPE
		   } else if (unlinkat(fd, file->d_name, 0)) {
			   ec = errno;
			   rc = -1;
			   return stop_repeating;
		   }
#endif

		   return continue_repeating;
	   },
	   [&] {
		   ec = errno;
		   rc = -1;
	   });

	(void)closedir(dir);

	if (rc == -1) {
		errno = ec;
		return -1;
	}

	return unlinkat(dirfd, path, AT_REMOVEDIR);
}

int remove_rat(int dirfd, FilePath path) noexcept {
	return __remove_rat(dirfd, path);
}

int remove_dir_contents_at(int dirfd, FilePath pathname) noexcept {
	int fd =
	   openat(dirfd, pathname, O_RDONLY | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
	if (fd == -1) {
		return -1;
	}

	DIR* dir = fdopendir(fd);
	if (dir == nullptr) {
		int ec = errno;
		close(fd);
		errno = ec;
		return -1;
	}

	int ec = 0;
	int rc = 0;
	for_each_dir_component(
	   dir,
	   [&](dirent* file) -> repeating {
#ifdef _DIRENT_HAVE_D_TYPE
		   if (file->d_type == DT_DIR || file->d_type == DT_UNKNOWN) {
#endif
			   if (__remove_rat(fd, file->d_name)) {
				   ec = errno;
				   rc = -1;
				   return stop_repeating;
			   }
#ifdef _DIRENT_HAVE_D_TYPE
		   } else if (unlinkat(fd, file->d_name, 0)) {
			   ec = errno;
			   rc = -1;
			   return stop_repeating;
		   }
#endif

		   return continue_repeating;
	   },
	   [&] {
		   ec = errno;
		   rc = -1;
	   });

	(void)closedir(dir);

	if (rc == -1) {
		errno = ec;
	}

	return rc;
}

int create_subdirectories(FilePath file) noexcept {
	StringView path(file);
	path.remove_trailing([](char c) { return (c != '/'); });
	if (path.empty()) {
		return 0;
	}

	return mkdir_r(path.to_string());
}

int blast(int infd, int outfd) noexcept {
	array<char, 65536> buff{};
	ssize_t len = 0;
	ssize_t written = 0;
	while (len = read(infd, buff.data(), buff.size()),
	       len > 0 || (len == -1 && errno == EINTR))
	{
		ssize_t pos = 0;
		while (pos < len) {
			written = write(outfd, buff.data() + pos, len - pos);
			if (written > 0) {
				pos += written;
			} else if (errno != EINTR) {
				return -1;
			}
		}
	}

	if (len == -1) {
		return -1;
	}

	return 0;
}

int copyat_using_rename(int src_dirfd, FilePath src, int dest_dirfd,
                        FilePath dest, mode_t mode) noexcept {
	FileDescriptor src_fd{openat(src_dirfd, src, O_RDONLY | O_CLOEXEC)};
	if (not src_fd.is_open()) {
		return -1;
	}

	try {
		constexpr uint suffix_len = 10;
		InplaceBuff<PATH_MAX> tmp_dest{std::in_place, dest, '.'};
		tmp_dest.resize(tmp_dest.size + suffix_len + 1); // +1 for trailing '\0'
		--tmp_dest.size;
		FileDescriptor dest_fd;
		for (size_t try_num = 0; try_num < 128; ++try_num) {
			for (size_t i = tmp_dest.size - suffix_len; i < tmp_dest.size; ++i)
			{
				tmp_dest[i] = get_random('a', 'z');
			}

			dest_fd = openat(dest_dirfd, tmp_dest.to_cstr().data(),
			                 O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode);
			if (dest_fd.is_open()) {
				break;
			}
			if (errno == EEXIST) {
				continue;
			}
			return -1; // Other error occurred
		}

		CallInDtor tmp_dest_remover = [&] {
			(void)unlinkat(dest_dirfd, tmp_dest.to_cstr().data(), 0);
		};

		if (blast(src_fd, dest_fd)) {
			return -1;
		}
		(void)dest_fd.close(); // Close file descriptor before renaming to avoid
		                       // racy ETXTBSY if someone will try execute it
		                       // before we close dest_fd
		if (renameat(dest_dirfd, tmp_dest.to_cstr().data(), dest_dirfd, dest)) {
			return -1;
		}
		// Success
		tmp_dest_remover.cancel();
		return 0;
	} catch (...) {
		errno = ENOMEM;
		return -1;
	}
}

int copyat(int src_dirfd, FilePath src, int dest_dirfd, FilePath dest,
           mode_t mode) noexcept {
	constexpr auto open_flags = O_WRONLY | O_TRUNC | O_CLOEXEC;
	FileDescriptor out(
	   openat(dest_dirfd, dest, open_flags | O_CREAT | O_EXCL, mode));
	bool file_created = true;
	if (not out.is_open() and errno == EEXIST) {
		file_created = false;
		out = openat(dest_dirfd, dest, open_flags);
	}
	if (not out.is_open()) {
		if (errno != ETXTBSY) {
			return -1;
		}
		return copyat_using_rename(src_dirfd, src, dest_dirfd, dest, mode);
	}

	FileDescriptor in(openat(src_dirfd, src, O_RDONLY | O_CLOEXEC));
	if (not in.is_open()) {
		return -1;
	}
	if (blast(in, out)) {
		return -1;
	}

	if (not file_created) {
		off64_t offset = lseek64(out, 0, SEEK_CUR);
		if (offset == static_cast<decltype(offset)>(-1)) {
			return -1;
		}
		if (ftruncate64(out, offset)) {
			return -1;
		}
		if (fchmod(out, mode)) {
			return -1;
		}
	}
	return 0;
}

int copyat_using_rename(int src_dirfd, FilePath src, int dest_dirfd,
                        FilePath dest) noexcept {
	struct stat64 sb {};
	if (fstatat64(src_dirfd, src, &sb, 0)) {
		return -1;
	}
	return copyat_using_rename(src_dirfd, src, dest_dirfd, dest, sb.st_mode);
}

int copyat(int src_dirfd, FilePath src, int dest_dirfd,
           FilePath dest) noexcept {
	struct stat64 sb {};
	if (fstatat64(src_dirfd, src, &sb, 0)) {
		return -1;
	}

	return copyat(src_dirfd, src, dest_dirfd, dest, sb.st_mode);
}

/**
 * @brief Copies directory @p src to @p dest relative to the directory file
 *   descriptors
 *
 * @param src_dirfd directory file descriptor
 * @param src source directory (relative to @p src_dirfd)
 * @param dest_dirfd directory file descriptor
 * @param dest destination directory (relative to @p dest_dirfd)
 *
 * @return 0 on success, -1 on error
 *
 * @errors The same that occur for fstat64(2), openat(2), fdopendir(3),
 *   mkdirat(2), copyat()
 */
static int __copy_rat(int src_dirfd, FilePath src, int dest_dirfd,
                      FilePath dest) noexcept {
	int src_fd = openat(src_dirfd, src, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
	if (src_fd == -1) {
		if (errno == ENOTDIR) {
			return copyat(src_dirfd, src, dest_dirfd, dest);
		}

		return -1;
	}

	// Do not use src permissions
	mkdirat(dest_dirfd, dest, S_0755);

	int dest_fd = openat(dest_dirfd, dest, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
	if (dest_fd == -1) {
		close(src_fd);
		return -1;
	}

	DIR* src_dir = fdopendir(src_fd);
	if (src_dir == nullptr) {
		close(src_fd);
		close(dest_fd);
		return -1;
	}

	int ec = 0;
	int rc = 0;
	for_each_dir_component(
	   src_dir,
	   [&](dirent* file) -> repeating {
#ifdef _DIRENT_HAVE_D_TYPE
		   if (file->d_type == DT_DIR || file->d_type == DT_UNKNOWN) {
#endif
			   if (__copy_rat(src_fd, file->d_name, dest_fd, file->d_name)) {
				   ec = errno;
				   rc = -1;
				   return stop_repeating;
			   }

#ifdef _DIRENT_HAVE_D_TYPE
		   } else {
			   if (copyat(src_fd, file->d_name, dest_fd, file->d_name)) {
				   ec = errno;
				   rc = -1;
				   return stop_repeating;
			   }
		   }
#endif

		   return continue_repeating;
	   },
	   [&] {
		   ec = errno;
		   rc = -1;
	   });

	closedir(src_dir);
	close(dest_fd);

	if (rc == -1) {
		errno = ec;
	}

	return rc;
}

int copy_rat(int src_dirfd, FilePath src, int dest_dirfd,
             FilePath dest) noexcept {
	struct stat64 sb {};
	if (fstatat64(src_dirfd, src, &sb, 0) == -1) {
		return -1;
	}

	if (S_ISDIR(sb.st_mode)) {
		return __copy_rat(src_dirfd, src, dest_dirfd, dest);
	}

	return copyat(src_dirfd, src, dest_dirfd, dest, sb.st_mode & ACCESSPERMS);
}

int copy_r(FilePath src, FilePath dest, bool create_subdirs) noexcept {
	if (create_subdirs and create_subdirectories(CStringView(dest)) == -1) {
		return -1;
	}

	return copy_rat(AT_FDCWD, src, AT_FDCWD, dest);
}

int move(FilePath oldpath, FilePath newpath, bool create_subdirs) noexcept {
	if (create_subdirs and create_subdirectories(CStringView(newpath)) == -1) {
		return -1;
	}

	if (rename(oldpath, newpath) == -1) {
		if (errno == EXDEV && copy_r(oldpath, newpath, false) == 0) {
			return remove_r(oldpath);
		}

		return -1;
	}

	return 0;
}

int create_file(FilePath pathname, mode_t mode) noexcept {
	int fd = open(pathname, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, mode);
	if (fd == -1) {
		return -1;
	}

	return close(fd);
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2006, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include <boost/version.hpp>
#include <boost/bind.hpp>
#include "libtorrent/pch.hpp"
#include "libtorrent/assert.hpp"
#include "libtorrent/file_pool.hpp"
#include "libtorrent/error_code.hpp"

namespace libtorrent
{
	boost::shared_ptr<file> file_pool::open_file(void* st, std::string const& p
		, int m, error_code& ec)
	{
		TORRENT_ASSERT(st != 0);
		TORRENT_ASSERT(is_complete(p));
		TORRENT_ASSERT((m & file::rw_mask) == file::read_only
			|| (m & file::rw_mask) == file::read_write);
		mutex::scoped_lock l(m_mutex);
		file_set::iterator i = m_files.find(p);
		if (i != m_files.end())
		{
			lru_file_entry& e = i->second;
			e.last_use = time_now();

			if (e.key != st && ((e.mode & file::rw_mask) != file::read_only
				|| (m & file::rw_mask) != file::read_only))
			{
				// this means that another instance of the storage
				// is using the exact same file.
#if BOOST_VERSION >= 103500
				ec = errors::file_collision;
#endif
				return boost::shared_ptr<file>();
			}

			e.key = st;
			// if we asked for a file in write mode,
			// and the cached file is is not opened in
			// write mode, re-open it
			if ((((e.mode & file::rw_mask) != file::read_write)
				&& ((m & file::rw_mask) == file::read_write))
				|| (e.mode & file::no_buffer) != (m & file::no_buffer))
			{
				// close the file before we open it with
				// the new read/write privilages
				TORRENT_ASSERT(e.file_ptr.unique());
				e.file_ptr->close();
				if (!e.file_ptr->open(p, m, ec))
				{
					m_files.erase(i);
					return boost::shared_ptr<file>();
				}
#ifdef TORRENT_WINDOWS
// file prio is supported on vista and up
#if _WIN32_WINNT >= 0x0600
				if (m_low_prio_io)
				{
					FILE_IO_PRIORITY_HINT_INFO priorityHint;
					priorityHint.PriorityHint = IoPriorityHintLow;
					result = SetFileInformationByHandle(e.file_ptr->native_handle(),
						FileIoPriorityHintInfo, &priorityHint, sizeof(PriorityHint));
				}
#endif
#endif
				TORRENT_ASSERT(e.file_ptr->is_open());
				e.mode = m;
			}
			TORRENT_ASSERT((e.mode & file::no_buffer) == (m & file::no_buffer));
			return e.file_ptr;
		}
		// the file is not in our cache
		if ((int)m_files.size() >= m_size)
		{
			// the file cache is at its maximum size, close
			// the least recently used (lru) file from it
			remove_oldest();
		}
		lru_file_entry e;
		e.file_ptr.reset(new (std::nothrow)file);
		if (!e.file_ptr)
		{
			ec = error_code(ENOMEM, get_posix_category());
			return e.file_ptr;
		}
		if (!e.file_ptr->open(p, m, ec))
			return boost::shared_ptr<file>();
		e.mode = m;
		e.key = st;
		m_files.insert(std::make_pair(p, e));
		TORRENT_ASSERT(e.file_ptr->is_open());
		return e.file_ptr;
	}

	void file_pool::remove_oldest()
	{
		file_set::iterator i = std::min_element(m_files.begin(), m_files.end()
			, boost::bind(&lru_file_entry::last_use, boost::bind(&file_set::value_type::second, _1))
				< boost::bind(&lru_file_entry::last_use, boost::bind(&file_set::value_type::second, _2)));
		if (i == m_files.end()) return;
		m_files.erase(i);
	}

	void file_pool::release(std::string const& p)
	{
		mutex::scoped_lock l(m_mutex);

		file_set::iterator i = m_files.find(p);
		if (i != m_files.end()) m_files.erase(i);
	}

	// closes files belonging to the specified
	// storage. If 0 is passed, all files are closed
	void file_pool::release(void* st)
	{
		mutex::scoped_lock l(m_mutex);
		if (st == 0)
		{
			m_files.clear();
			return;
		}

		for (file_set::iterator i = m_files.begin();
			i != m_files.end();)
		{
			if (i->second.key == st)
				m_files.erase(i++);
			else
				++i;
		}
	}

	void file_pool::resize(int size)
	{
		TORRENT_ASSERT(size > 0);
		if (size == m_size) return;
		mutex::scoped_lock l(m_mutex);
		m_size = size;
		if (int(m_files.size()) <= m_size) return;

		// close the least recently used files
		while (int(m_files.size()) > m_size)
			remove_oldest();
	}

}
<commit_msg>fix windows build<commit_after>/*

Copyright (c) 2006, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include <boost/version.hpp>
#include <boost/bind.hpp>
#include "libtorrent/pch.hpp"
#include "libtorrent/assert.hpp"
#include "libtorrent/file_pool.hpp"
#include "libtorrent/error_code.hpp"

namespace libtorrent
{
	boost::shared_ptr<file> file_pool::open_file(void* st, std::string const& p
		, int m, error_code& ec)
	{
		TORRENT_ASSERT(st != 0);
		TORRENT_ASSERT(is_complete(p));
		TORRENT_ASSERT((m & file::rw_mask) == file::read_only
			|| (m & file::rw_mask) == file::read_write);
		mutex::scoped_lock l(m_mutex);
		file_set::iterator i = m_files.find(p);
		if (i != m_files.end())
		{
			lru_file_entry& e = i->second;
			e.last_use = time_now();

			if (e.key != st && ((e.mode & file::rw_mask) != file::read_only
				|| (m & file::rw_mask) != file::read_only))
			{
				// this means that another instance of the storage
				// is using the exact same file.
#if BOOST_VERSION >= 103500
				ec = errors::file_collision;
#endif
				return boost::shared_ptr<file>();
			}

			e.key = st;
			// if we asked for a file in write mode,
			// and the cached file is is not opened in
			// write mode, re-open it
			if ((((e.mode & file::rw_mask) != file::read_write)
				&& ((m & file::rw_mask) == file::read_write))
				|| (e.mode & file::no_buffer) != (m & file::no_buffer))
			{
				// close the file before we open it with
				// the new read/write privilages
				TORRENT_ASSERT(e.file_ptr.unique());
				e.file_ptr->close();
				if (!e.file_ptr->open(p, m, ec))
				{
					m_files.erase(i);
					return boost::shared_ptr<file>();
				}
#ifdef TORRENT_WINDOWS
// file prio is supported on vista and up
#if _WIN32_WINNT >= 0x0600
				if (m_low_prio_io)
				{
					FILE_IO_PRIORITY_HINT_INFO priorityHint;
					priorityHint.PriorityHint = IoPriorityHintLow;
					SetFileInformationByHandle(e.file_ptr->native_handle(),
						FileIoPriorityHintInfo, &priorityHint, sizeof(PriorityHint));
				}
#endif
#endif
				TORRENT_ASSERT(e.file_ptr->is_open());
				e.mode = m;
			}
			TORRENT_ASSERT((e.mode & file::no_buffer) == (m & file::no_buffer));
			return e.file_ptr;
		}
		// the file is not in our cache
		if ((int)m_files.size() >= m_size)
		{
			// the file cache is at its maximum size, close
			// the least recently used (lru) file from it
			remove_oldest();
		}
		lru_file_entry e;
		e.file_ptr.reset(new (std::nothrow)file);
		if (!e.file_ptr)
		{
			ec = error_code(ENOMEM, get_posix_category());
			return e.file_ptr;
		}
		if (!e.file_ptr->open(p, m, ec))
			return boost::shared_ptr<file>();
		e.mode = m;
		e.key = st;
		m_files.insert(std::make_pair(p, e));
		TORRENT_ASSERT(e.file_ptr->is_open());
		return e.file_ptr;
	}

	void file_pool::remove_oldest()
	{
		file_set::iterator i = std::min_element(m_files.begin(), m_files.end()
			, boost::bind(&lru_file_entry::last_use, boost::bind(&file_set::value_type::second, _1))
				< boost::bind(&lru_file_entry::last_use, boost::bind(&file_set::value_type::second, _2)));
		if (i == m_files.end()) return;
		m_files.erase(i);
	}

	void file_pool::release(std::string const& p)
	{
		mutex::scoped_lock l(m_mutex);

		file_set::iterator i = m_files.find(p);
		if (i != m_files.end()) m_files.erase(i);
	}

	// closes files belonging to the specified
	// storage. If 0 is passed, all files are closed
	void file_pool::release(void* st)
	{
		mutex::scoped_lock l(m_mutex);
		if (st == 0)
		{
			m_files.clear();
			return;
		}

		for (file_set::iterator i = m_files.begin();
			i != m_files.end();)
		{
			if (i->second.key == st)
				m_files.erase(i++);
			else
				++i;
		}
	}

	void file_pool::resize(int size)
	{
		TORRENT_ASSERT(size > 0);
		if (size == m_size) return;
		mutex::scoped_lock l(m_mutex);
		m_size = size;
		if (int(m_files.size()) <= m_size) return;

		// close the least recently used files
		while (int(m_files.size()) > m_size)
			remove_oldest();
	}

}
<|endoftext|>


<commit_before>// Copyright (C) 2016 Jonathan Müller <jonathanmueller.dev@gmail.com>
// This file is subject to the license terms in the LICENSE file
// found in the top-level directory of this distribution.

#ifndef TYPE_SAFE_ASSERT_HPP_INCLUDED
#define TYPE_SAFE_ASSERT_HPP_INCLUDED

#include <debug-assert/debug_assert.hpp>

#ifndef TYPE_SAFE_ENABLE_ASSERTIONS
#define TYPE_SAFE_ENABLE_ASSERTIONS 1
#endif

namespace type_safe
{
    struct assert_handler : debug_assert::set_level<TYPE_SAFE_ENABLE_ASSERTIONS>,
                            debug_assert::default_handler
    {
    };

    template <typename Return>
    constexpr Return constexpr_assert(bool condition, debug_assert::source_location loc,
                                      const char* message)
    {
// dear user,
// if an error message points you to this function
// you're using a constexpr function with an assertion where the assertion failed
#if TYPE_SAFE_ENABLE_ASSERTIONS
        return condition ? Return() : (assert_handler{}.handle(loc, "", message), Return());
#else
        return Return();
#endif
    }
} // namespace type_safe

#endif // TYPE_SAFE_ASSERT_HPP_INCLUDED`
<commit_msg>Fix `constexpr_assert()` so that it aborts<commit_after>// Copyright (C) 2016 Jonathan Müller <jonathanmueller.dev@gmail.com>
// This file is subject to the license terms in the LICENSE file
// found in the top-level directory of this distribution.

#ifndef TYPE_SAFE_ASSERT_HPP_INCLUDED
#define TYPE_SAFE_ASSERT_HPP_INCLUDED

#include <debug-assert/debug_assert.hpp>

#ifndef TYPE_SAFE_ENABLE_ASSERTIONS
#define TYPE_SAFE_ENABLE_ASSERTIONS 1
#endif

namespace type_safe
{
    struct assert_handler : debug_assert::set_level<TYPE_SAFE_ENABLE_ASSERTIONS>,
                            debug_assert::default_handler
    {
    };

    template <typename Return>
    constexpr Return constexpr_assert(bool condition, debug_assert::source_location loc,
                                      const char* message)
    {
// dear user,
// if an error message points you to this function
// you're using a constexpr function with an assertion where the assertion failed
#if TYPE_SAFE_ENABLE_ASSERTIONS
        return condition ? Return() :
                           (assert_handler{}.handle(loc, "", message), std::abort(), Return());
#else
        return Return();
#endif
    }
} // namespace type_safe

#endif // TYPE_SAFE_ASSERT_HPP_INCLUDED`
<|endoftext|>


<commit_before>#include "flow.h"
#include "Scene.h"
#include "Transition.h"
#include "DebugActor.h"
#include "core/oxygine.h"

namespace oxygine
{
    bool checkQuit();

    namespace flow
    {
        spActor _touchBlocker;

        Vector2 _blockedTouchPosition(0, 0);
        bool _wasTouchBlocked = false;
        bool _wasBackBlocked = false;

        Flow Flow::instance;

        void init()
        {
            _touchBlocker = new Actor;
            _touchBlocker->setName("Scene::_touchBlocker");
            _touchBlocker->setPosition(-10000, -10000);
            _touchBlocker->setSize(20000, 20000);
            _touchBlocker->setPriority(10000);
            _touchBlocker->setName("touchBlocker");

            Flow::instance.init();
        }

        void free()
        {
            _touchBlocker->detach();
            _touchBlocker = 0;
            Flow::instance.free();
        }

        Flow::Flow()
        {
            _transition = false;
            _back = false;
        }

        void Flow::init()
        {
        }

        void Flow::free()
        {
            _trans = 0;
            _current = 0;
            _next = 0;
            scenes.clear();
            scenes2show.clear();
        }

        void Flow::show(spScene scene, const resultCallback& cb)
        {
            if (scenes.empty())
            {
                scenes.push_back(scene);
                scene->entering();
                scene->preShowing();
                scene->_holder->attachTo(getStage());
                scene->postShowing();
                scene->_resultCB = cb;
                return;
            }

            auto p = std::find(scenes.begin(), scenes.end(), scene);
            if (p != scenes.end())
            {
                log::error("you can't show scene '%s', it is already in the list", scene->getName().c_str());
                OX_ASSERT(p == scenes.end());
                return;
            }

            scene->_resultCB = cb;
            scenes2show.push_back(scene);

            checkShow();
        }

        void Flow::blockedTouch(Event* ev)
        {
            TouchEvent* event = safeCast<TouchEvent*>(ev);
            _blockedTouchPosition = event->getPointer()->getPosition();
            _wasTouchBlocked = true;
        }

        void Flow::phaseBegin(spScene current, spScene next, bool back)
        {
            _back = back;
            _current = current;
            _next = next;

            _transition = true;

            if (next && !_back)
                next->entering();

            if (!_back || !current->_dialog)
                next->preShowing();

            if ((next->_dialog && _back) || !next->_dialog)
                current->preHiding();

            if (!back)
                current->sceneShown(next);

            _trans = next->runTransition(this, current, back);

            getStage()->addChild(_touchBlocker);
            _wasTouchBlocked = false;
            _wasBackBlocked = false;
            getStage()->addEventListener(TouchEvent::CLICK, CLOSURE(this, &Flow::blockedTouch));
        }

        void Flow::phaseEnd()
        {
            _transition = false;

            spScene current = _current;
            spScene next = _next;

            _current = 0;
            _next = 0;

            if ((next->_dialog && _back) || !next->_dialog)
            {
                current->_holder->detach();
                current->postHiding();
            }

            getStage()->insertChildBefore(_touchBlocker, next->getHolder());

            if (!_back || !current->_dialog)
                next->postShowing();

            if (_back)
                next->sceneHidden(current);

            getStage()->removeEventListener(TouchEvent::CLICK, CLOSURE(this, &Flow::blockedTouch));

            if (current->_done)
            {
                current->leaving();
                if (current->_resultCB)
                {
                    current->_resultCB(&current->_finishEvent);
                    current->_resultCB = resultCallback();
                    current->_finishEvent = SceneEvent();
                }
            }

            if (current->_remove)
            {
                OX_ASSERT(next->_dialog == false);
                std::vector<spScene>::iterator i = std::find(scenes.begin(), scenes.end(), current);
                OX_ASSERT(i != scenes.end());
                scenes.erase(i);
            }

            if (_wasTouchBlocked)
            {
                log::messageln("send  blocked touch");
                TouchEvent click(TouchEvent::CLICK, true, _blockedTouchPosition);
                getStage()->handleEvent(&click);
                _wasTouchBlocked = false;
            }
        }

        void Flow::checkDone()
        {
            spScene current = scenes.back();
            if (current->_done)
            {
                scenes.pop_back();
                if (!scenes.empty())
                {
                    spScene prev = scenes.back();
                    phaseBegin(current, prev, true);
                }
            }
        }

        void Flow::checkShow()
        {
            if (scenes.back()->_done)
                return;

            if (_transition)
                return;

            spScene next = scenes2show.front();
            scenes2show.erase(scenes2show.begin());

            spScene current = scenes.back();

            if (current->_dialog)
            {
                OX_ASSERT(next->_dialog && "you can't show fullscreen scene on top of dialog");
                OX_ASSERT(!current->_remove && "you can't remove dialog from flow");
            }

            scenes.push_back(next);
            phaseBegin(current, next, false);

        }

        void Flow::update()
        {
            if (scenes.empty() && scenes2show.empty())
                return;

            if (DebugActor::instance)
            {
                std::string str;
                for (size_t i = 0; i < scenes.size(); ++i)
                {
                    str += scenes[i]->getName();
                    str += "-> ";
                }
                if (!str.empty())
                {
                    str.pop_back();
                    str.pop_back();
                    str.pop_back();
                    str += "\n";
                    DebugActor::addDebugString(str.c_str());
                }
            }

            bool quit = checkQuit();
            static bool quitLast = false;
            if (quit && !quitLast)
            {
                _wasBackBlocked = true;
            }
            quitLast = quit;

            if (_transition)
            {
                if (_current->_transitionDone || (_trans && _trans->_done))
                    phaseEnd();

                return;
            }

            checkDone();
            if (!scenes2show.empty())
                checkShow();

            if (_transition)
                return;

            if (!scenes.empty())
            {
                spScene current = scenes.back();

                if (_wasBackBlocked)
                {
                    _wasBackBlocked = false;

                    Event ev(Scene::EVENT_BACK);
                    current->dispatchEvent(&ev);
                    checkDone();
                }
                else
                {
                    current->update();
                }
            }

            if (scenes.empty())
                core::requestQuit();
        }

        void update()
        {
            Flow::instance.update();
        }

        void show(spScene s, const resultCallback& cb, Flow* f)
        {
            if (!f)
                f = &Flow::instance;

            f->show(s, cb);
        }
    }
}
<commit_msg>minor<commit_after>#include "flow.h"
#include "Scene.h"
#include "Transition.h"
#include "DebugActor.h"
#include "core/oxygine.h"

namespace oxygine
{
    bool checkQuit();

    namespace flow
    {
        spActor _touchBlocker;

        Vector2 _blockedTouchPosition(0, 0);
        bool _wasTouchBlocked = false;
        bool _wasBackBlocked = false;

        Flow Flow::instance;

        void init()
        {
            _touchBlocker = new Actor;
            _touchBlocker->setName("Scene::_touchBlocker");
            _touchBlocker->setPosition(-10000, -10000);
            _touchBlocker->setSize(20000, 20000);
            _touchBlocker->setPriority(10000);
            _touchBlocker->setName("touchBlocker");

            Flow::instance.init();
        }

        void free()
        {
            _touchBlocker->detach();
            _touchBlocker = 0;
            Flow::instance.free();
        }

        Flow::Flow()
        {
            _transition = false;
            _back = false;
        }

        void Flow::init()
        {
        }

        void Flow::free()
        {
            _trans = 0;
            _current = 0;
            _next = 0;
            scenes.clear();
            scenes2show.clear();
        }

        void Flow::show(spScene scene, const resultCallback& cb)
        {
            if (scenes.empty())
            {
                scenes.push_back(scene);
                scene->entering();
                scene->preShowing();
                scene->_holder->attachTo(getStage());
                scene->postShowing();
                scene->_resultCB = cb;
                return;
            }

            auto p = std::find(scenes.begin(), scenes.end(), scene);
            if (p != scenes.end())
            {
                log::error("you can't show scene '%s', it is already in the list", scene->getName().c_str());
                OX_ASSERT(p == scenes.end());
                return;
            }

            scene->_resultCB = cb;
            scenes2show.push_back(scene);

            checkShow();
        }

        void Flow::blockedTouch(Event* ev)
        {
            TouchEvent* event = safeCast<TouchEvent*>(ev);
            _blockedTouchPosition = event->getPointer()->getPosition();
            _wasTouchBlocked = true;
        }

        void Flow::phaseBegin(spScene current, spScene next, bool back)
        {
            _back = back;
            _current = current;
            _next = next;

            _transition = true;

            if (next && !_back)
                next->entering();

            if (!_back || !current->_dialog)
                next->preShowing();

            if ((next->_dialog && _back) || !next->_dialog)
                current->preHiding();

            if (!back)
                current->sceneShown(next);

            _trans = next->runTransition(this, current, back);

            getStage()->addChild(_touchBlocker);
            _wasTouchBlocked = false;
            _wasBackBlocked = false;
            getStage()->addEventListener(TouchEvent::CLICK, CLOSURE(this, &Flow::blockedTouch));
        }

        void Flow::phaseEnd()
        {
            _transition = false;

            spScene current = _current;
            spScene next = _next;

            _current = 0;
            _next = 0;

            if ((next->_dialog && _back) || !next->_dialog)
            {
                current->_holder->detach();
                current->postHiding();
            }

            getStage()->insertChildBefore(_touchBlocker, next->getHolder());

            if (!_back || !current->_dialog)
                next->postShowing();

            if (_back)
                next->sceneHidden(current);

            getStage()->removeEventListener(TouchEvent::CLICK, CLOSURE(this, &Flow::blockedTouch));

            if (current->_done)
            {
                current->leaving();
                if (current->_resultCB)
                {
                    current->_resultCB(&current->_finishEvent);
                    current->_resultCB = resultCallback();
                    current->_finishEvent = SceneEvent();
                }
            }

            if (current->_remove)
            {
                OX_ASSERT(next->_dialog == false);
                std::vector<spScene>::iterator i = std::find(scenes.begin(), scenes.end(), current);
                OX_ASSERT(i != scenes.end());
                scenes.erase(i);
            }

            if (_wasTouchBlocked)
            {
                log::messageln("send  blocked touch");
                TouchEvent click(TouchEvent::CLICK, true, _blockedTouchPosition);
                getStage()->handleEvent(&click);
                _wasTouchBlocked = false;
            }
        }

        void Flow::checkDone()
        {
            spScene current = scenes.back();
            if (current->_done)
            {
                scenes.pop_back();
                if (!scenes.empty())
                {
                    spScene prev = scenes.back();
                    phaseBegin(current, prev, true);
                }
            }
        }

        void Flow::checkShow()
        {
            if (scenes.back()->_done)
                return;

            if (_transition)
                return;

            spScene next = scenes2show.front();
            scenes2show.erase(scenes2show.begin());

            spScene current = scenes.back();

            if (current->_dialog)
            {
                OX_ASSERT(next->_dialog && "you can't show fullscreen scene on top of dialog");
                OX_ASSERT(!current->_remove && "you can't remove dialog from flow");
            }

            scenes.push_back(next);
            phaseBegin(current, next, false);

        }

        void Flow::update()
        {
            if (scenes.empty() && scenes2show.empty())
                return;

            if (DebugActor::instance)
            {
                std::string str;
                for (size_t i = 0; i < scenes.size(); ++i)
                {
                    str += scenes[i]->getName();
                    str += "-> ";
                }
                if (!str.empty())
                {
                    str.pop_back();
                    str.pop_back();
                    str.pop_back();
                    DebugActor::addDebugString(str.c_str());
                }
            }

            bool quit = checkQuit();
            static bool quitLast = false;
            if (quit && !quitLast)
            {
                _wasBackBlocked = true;
            }
            quitLast = quit;

            if (_transition)
            {
                if (_current->_transitionDone || (_trans && _trans->_done))
                    phaseEnd();

                return;
            }

            checkDone();
            if (!scenes2show.empty())
                checkShow();

            if (_transition)
                return;

            if (!scenes.empty())
            {
                spScene current = scenes.back();

                if (_wasBackBlocked)
                {
                    _wasBackBlocked = false;

                    Event ev(Scene::EVENT_BACK);
                    current->dispatchEvent(&ev);
                    checkDone();
                }
                else
                {
                    current->update();
                }
            }

            if (scenes.empty())
                core::requestQuit();
        }

        void update()
        {
            Flow::instance.update();
        }

        void show(spScene s, const resultCallback& cb, Flow* f)
        {
            if (!f)
                f = &Flow::instance;

            f->show(s, cb);
        }
    }
}
<|endoftext|>


<commit_before>//----------------------------------------------------------------------------
/// \file config_tree.hpp
/// \author Serge Aleynikov
//----------------------------------------------------------------------------
/// Defines config_tree, config_path, and config_error classes for
/// ease of configuration management.
//----------------------------------------------------------------------------
// Copyright (C) 2010 Serge Aleynikov <saleyn@gmail.com>
// Created: 2010-06-21
//----------------------------------------------------------------------------
/*
***** BEGIN LICENSE BLOCK *****

This file is a part of utxx open-source project.

Copyright (C) 2010 Serge Aleynikov <saleyn@gmail.com>

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

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

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

***** END LICENSE BLOCK *****
*/

#ifndef _UTXX_CONFIG_TREE_HPP_
#define _UTXX_CONFIG_TREE_HPP_

#include <utxx/variant_tree.hpp>

namespace utxx {

    /// Container for storing configuration data.
    typedef variant_tree            config_tree;
    typedef tree_path               config_path;

    typedef variant_tree_error      config_error;
    typedef variant_tree_bad_data   config_bad_data;
    typedef variant_tree_bad_path   config_bad_path;

} // namespace utxx

#endif // _UTXX_CONFIG_TREE_HPP_

<commit_msg>Add UTXX_THROW_CONFIG_ERROR<commit_after>//----------------------------------------------------------------------------
/// \file config_tree.hpp
/// \author Serge Aleynikov
//----------------------------------------------------------------------------
/// Defines config_tree, config_path, and config_error classes for
/// ease of configuration management.
//----------------------------------------------------------------------------
// Copyright (C) 2010 Serge Aleynikov <saleyn@gmail.com>
// Created: 2010-06-21
//----------------------------------------------------------------------------
/*
***** BEGIN LICENSE BLOCK *****

This file is a part of utxx open-source project.

Copyright (C) 2010 Serge Aleynikov <saleyn@gmail.com>

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

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

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

***** END LICENSE BLOCK *****
*/

#pragma once

#include <utxx/variant_tree.hpp>

/// Throw utxx::config_error exception with current source location information
#define UTXX_THROW_CONFIG_ERROR(...) \
    UTXX_SRC_THROW(utxx::config_error, UTXX_SRC, ##__VA_ARGS__)
/// Throw utxx::config_error exception with current source location and cached fun name
#define UTXX_THROWX_CONFIG_ERROR(...) \
    UTXX_SRC_THROW(utxx::config_error, UTXX_SRCX, ##__VA_ARGS__)

namespace utxx {

    /// Container for storing configuration data.
    using config_tree       = variant_tree;
    using config_path       = tree_path;

    using config_error      = variant_tree_error;
    using config_bad_data   = variant_tree_bad_data;
    using config_bad_path   = variant_tree_bad_path;

} // namespace utxx<|endoftext|>


<commit_before>#ifndef FORMATION_HPP
#define FORMATION_HPP 1

#include <QString>
#include <map>

#include "structures.hpp"
#include "singleton.hpp"
#include "manager.hpp"
#include "uvmanager.hpp"

#include <iostream>

#define CUM CategorieUVManager::getInstance()
#define UVM UvManager::getInstance()

//! Classe des Formations
class Formation : public BaseItem {

  public:

    Formation(const QString& abbr, const QString& n)
        : BaseItem(abbr), longName(n), parent(0), nbLignes(0), nbColonnes(0),
          minCredits(0), minNbUvRecommended(0) {}

    inline const QString& getLongName() const { return longName; }
    inline const Formation* getParent() const { return parent; }
    inline const std::map<CategorieUV, int>& getRequirements() const { return requirements; }
    inline unsigned int getLignesTSH() const { return nbLignes; }
    inline unsigned int getColonnesTSH() const { return nbColonnes; }

    inline void setLongName(const QString &l) { longName = l; }
    inline void setRequirements(const QString &c, unsigned int n) {
        //Vérifie si la catégorie existe
        CategorieUV cat = CUM->getItem(c);
        requirements[cat] = n;
    }

    inline void setLignesTSH(unsigned int l) { nbLignes = l; }
    inline void setColonnesTSH(unsigned int c) { nbColonnes = c; }

  protected:
    QString longName;

    //! Formation parente, vide si pas de parent
    Formation* parent;

    //! Minimums de crédits requis par catégories
    std::map<CategorieUV, int> requirements;

    //! UVs dont la validation est nécessaire
    std::vector<Uv> compulsory;

    //! UVs dont la validation est recommandée
    std::vector<Uv> recommended;

    //! Nombre de lignes présentes dans le tableau TSH
    unsigned int nbLignes;

    //! Nombre de colonnes présentes dans le tableau TSH
    unsigned int nbColonnes;

    //! Nombre minimum de crédits à valider toutes catégories confondues
    unsigned int minCredits;

    //! Nombre minimum d’UV à valider dans les UVs recommandées
    unsigned int minNbUvRecommended;

};

typedef Singleton<Manager<Formation>> FormationManager;

#endif // FORMATION_HPP
<commit_msg>Modification de la gestion des parents de Formations et gestion des erreurs améliorées<commit_after>#ifndef FORMATION_HPP
#define FORMATION_HPP 1

#include <QString>
#include <map>

#include "structures.hpp"
#include "singleton.hpp"
#include "manager.hpp"
#include "uvmanager.hpp"

#include <iostream>

class Formation;
typedef Singleton<Manager<Formation>> FormationManager;

#define CUM CategorieUVManager::getInstance()
#define UVM UvManager::getInstance()
#define FM FormationManager::getInstance()

//! Classe des Formations
class Formation : public BaseItem {

  public:

    Formation(const QString& abbr, const QString& n)
        : BaseItem(abbr), longName(n), parent(""), nbLignes(0), nbColonnes(0),
          minCredits(0), minNbUvRecommended(0) {}

    inline const QString& getLongName() const { return longName; }
    inline bool hasParent() const { return parent != ""; }

    //! Retourne le parent de la formation, lève une exception s’il n’existe pas
    inline const Formation& getParent() const { return FM->getItem(parent); }

    inline const std::map<CategorieUV, int>& getRequirements() const { return requirements; }
    inline unsigned int getLignesTSH() const { return nbLignes; }
    inline unsigned int getColonnesTSH() const { return nbColonnes; }

    inline bool hasChildren() const {
        std::vector<Formation> formations = FM->iterator();
        for(auto it=formations.begin(); it!=formations.end(); it++) {
            if (it->hasParent() && (it->getParent() == *this)) {
                return true;
            }
        }
        return false;
    }

    inline void setLongName(const QString &l) { longName = l; }
    inline void setRequirements(const QString &c, unsigned int n) {
        //Vérifie si la catégorie existe
        CategorieUV cat("", "");
        try {
            cat = CUM->getItem(c);
        } catch (Exception) {
            return;
        }

        requirements[cat] = n;
    }

    inline void setParent(const QString& p) {
        //On vérifie que le parent existe
        try {
            FM->getItem(p);
        } catch (Exception) {
            return;
        }

        parent = p;
    }
    inline void setLignesTSH(unsigned int l) { nbLignes = l; }
    inline void setColonnesTSH(unsigned int c) { nbColonnes = c; }

  protected:
    QString longName;

    //! Formation parente, vide si pas de parent
    QString parent;

    //! Minimums de crédits requis par catégories
    std::map<CategorieUV, int> requirements;

    //! UVs dont la validation est nécessaire
    std::vector<Uv> compulsory;

    //! UVs dont la validation est recommandée
    std::vector<Uv> recommended;

    //! Nombre de lignes présentes dans le tableau TSH
    unsigned int nbLignes;

    //! Nombre de colonnes présentes dans le tableau TSH
    unsigned int nbColonnes;

    //! Nombre minimum de crédits à valider toutes catégories confondues
    unsigned int minCredits;

    //! Nombre minimum d’UV à valider dans les UVs recommandées
    unsigned int minNbUvRecommended;

};

#endif // FORMATION_HPP
<|endoftext|>


<commit_before>#include "Game.hpp"

#include "GameState.hpp"

#include <SFML/Window.hpp>

#include <thread>
#include <chrono>
#include <memory>

using namespace falksalt;

Game::Game(int*, char**)
	: m_logger(om::Logger::get("Game"))
{
	m_logger << "Initialized." << std::endl;

	m_stateStack.push(std::make_shared<GameState>());
}

Game::~Game()
{
}

void Game::start()
{
	m_logger << "Starting game loop." << std::endl;
	m_stop = false;

	m_lastTick = std::chrono::system_clock::now();

	while(!m_stop)
	{
		sf::Event event;
		while(m_renderer.getWindow().pollEvent(event))
		{
			if(event.type == sf::Event::Closed)
				stop();
			//else if(event.type == sf::Event::Resized)
			//	m_renderer.resize(event.size.width, event.size.height);
		}

		// TODO: Perhaps use double instead of float? Seems a bit flakey
		// at high frame rates.
		m_stateStack.update(getAndUpdateDelta());

		m_renderer.beginRender();
		m_stateStack.render(m_renderer);
		m_renderer.finishRender();

		std::this_thread::sleep_for(std::chrono::milliseconds(1));
	}
	m_logger << "Game loop stopped." << std::endl;
}

void Game::stop()
{
	m_stop = true;
}

void Game::update()
{
}

// Updates the m_lastTick field and returns the time delta in seconds.
float Game::getAndUpdateDelta()
{
	auto now = std::chrono::system_clock::now();
	auto delta = std::chrono::duration_cast<std::chrono::milliseconds>
		(now - m_lastTick);

	m_lastTick = now;
	return delta.count() / 1000.f;
}

<commit_msg>Fixed delta timer resolution problem<commit_after>#include "Game.hpp"

#include "GameState.hpp"

#include <SFML/Window.hpp>

#include <thread>
#include <chrono>
#include <memory>

using namespace falksalt;

Game::Game(int*, char**)
	: m_logger(om::Logger::get("Game"))
{
	m_logger << "Initialized." << std::endl;

	m_stateStack.push(std::make_shared<GameState>());
}

Game::~Game()
{
}

void Game::start()
{
	m_logger << "Starting game loop." << std::endl;
	m_stop = false;

	m_lastTick = std::chrono::system_clock::now();

	while(!m_stop)
	{
		sf::Event event;
		while(m_renderer.getWindow().pollEvent(event))
		{
			if(event.type == sf::Event::Closed)
				stop();
			//else if(event.type == sf::Event::Resized)
			//	m_renderer.resize(event.size.width, event.size.height);
		}

		// TODO: Perhaps use double instead of float? Seems a bit flakey
		// at high frame rates.
		m_stateStack.update(getAndUpdateDelta());

		m_renderer.beginRender();
		m_stateStack.render(m_renderer);
		m_renderer.finishRender();

		std::this_thread::sleep_for(std::chrono::milliseconds(1));
	}
	m_logger << "Game loop stopped." << std::endl;
}

void Game::stop()
{
	m_stop = true;
}

void Game::update()
{
}

// Updates the m_lastTick field and returns the time delta in seconds.
float Game::getAndUpdateDelta()
{
	auto now = std::chrono::system_clock::now();
	auto delta = std::chrono::duration_cast<std::chrono::microseconds>
		(now - m_lastTick);

	m_lastTick = now;
	return delta.count() / 1000000.f;
}

<|endoftext|>


<commit_before>#include "generator.h"

int main(int argc, char * argv[]){

  if (argc < 4){
    std::cout << "Usage:\n" << argv[0] << "<number_of_instances> <number_of_tasks> <max_time> " << endl;
    exit(0);
  }
  int quantity, max_time, n;
  string filename = "";
  max_time = atoi(argv[3]);
  quantity = atoi(argv[1]);
  n = atoi(argv[2]);
  for (int i = 0; i < quantity; i++){
  	Instance I;
  	I.generate_instance(n, max_time ,i, false);
  	filename = "file_" + std::to_string(i) + ".txt";
  	I.dump_instance(filename);
  }
  //Instance I;
  //I.read_instance("file_0.txt");
  return 0;
}<commit_msg>Logical change in generator<commit_after>#include "generator.h"

int main(int argc, char * argv[]){

  if (argc != 4){
    std::cout << "Usage:\n" << argv[0] << "<number_of_instances> <number_of_tasks> <max_time> " << endl;
    exit(0);
  }
  int quantity, max_time, n;
  string filename = "";
  max_time = atoi(argv[3]);
  quantity = atoi(argv[1]);
  n = atoi(argv[2]);
  for (int i = 0; i < quantity; i++){
  	Instance I;
  	I.generate_instance(n, max_time ,i, false);
  	filename = "file_" + std::to_string(i) + ".txt";
  	I.dump_instance(filename);
  }
  //Instance I;
  //I.read_instance("file_0.txt");
  return 0;
}
<|endoftext|>


<commit_before>#ifndef JARNGREIPR_FORCEFIELD_GENERATOR
#define JARNGREIPR_FORCEFIELD_GENERATOR
#include <jarngreipr/model/Bead.hpp>
#include <extlib/toml/toml.hpp>

namespace jarngreipr
{

template<typename realT>
class IntraChainForceFieldGenerator
{
  public:
    typedef realT real_type;
    typedef Bead<real_type> bead_type;

  public:
    virtual ~IntraChainForceFieldGenerator() = default;

    //!@brief generate parameter values and write out to ostream.
    //@return connection_information. for scaling or ignoring Global interaction
    virtual void generate(toml::Table& out,
            const std::vector<std::unique_ptr<bead_type>>& chain) const = 0;

    //!@brief if chain contains invalid bead, return false.
    virtual bool check_beads_kind(
            const std::vector<std::unique_ptr<bead_type>>& chain) const = 0;
};

template<typename realT>
class InterChainForceFieldGenerator
{
  public:
    typedef realT real_type;
    typedef Bead<real_type> bead_type;
    typedef std::unique_ptr<bead_type> bead_ptr;

  public:
    virtual ~InterChainForceFieldGenerator() = default;

    //!@brief generate parameter values and write out to ostream.
    //@return connection_information. for scaling or ignoring Global interaction
    virtual void generate(toml::Table& out,
        const std::vector<std::vector<bead_ptr>>& chain) const = 0;

    //!@brief if chain contains invalid bead, return false.
    virtual bool check_beads_kind(
        const std::vector<std::vector<bead_type>>& chain) const = 0;
};

} // mjolnir
#endif// JARNGREIPR_FORCEFIELD_GENERATOR
<commit_msg>remove invalid comments<commit_after>#ifndef JARNGREIPR_FORCEFIELD_GENERATOR
#define JARNGREIPR_FORCEFIELD_GENERATOR
#include <jarngreipr/model/Bead.hpp>
#include <extlib/toml/toml.hpp>

namespace jarngreipr
{

template<typename realT>
class IntraChainForceFieldGenerator
{
  public:
    typedef realT real_type;
    typedef Bead<real_type> bead_type;

  public:
    virtual ~IntraChainForceFieldGenerator() = default;

    //!@brief generate parameter values and write out to ostream.
    virtual void generate(toml::Table& out,
            const std::vector<std::unique_ptr<bead_type>>& chain) const = 0;

    //!@brief if chain contains invalid bead, return false.
    virtual bool check_beads_kind(
            const std::vector<std::unique_ptr<bead_type>>& chain) const = 0;
};

template<typename realT>
class InterChainForceFieldGenerator
{
  public:
    typedef realT real_type;
    typedef Bead<real_type> bead_type;
    typedef std::unique_ptr<bead_type> bead_ptr;

  public:
    virtual ~InterChainForceFieldGenerator() = default;

    //!@brief generate parameter values and write out to ostream.
    virtual void generate(toml::Table& out,
        const std::vector<std::vector<bead_ptr>>& chain) const = 0;

    //!@brief if chain contains invalid bead, return false.
    virtual bool check_beads_kind(
        const std::vector<std::vector<bead_type>>& chain) const = 0;
};

} // mjolnir
#endif// JARNGREIPR_FORCEFIELD_GENERATOR
<|endoftext|>


<commit_before>#include "Utility/String.h"

#include <string>
#include <vector>
#include <stdexcept>
#include <algorithm>
#include <cctype>
#include <chrono>
#include <iomanip>
#include <sstream>
#include <cmath>

std::vector<std::string> String::split(const std::string& s, const std::string& delim, const size_t count) noexcept
{
    if(delim.empty())
    {
        return split(remove_extra_whitespace(s), " ", count);
    }

    if(s.empty())
    {
        return {};
    }

    std::vector<std::string> result;
    size_t start_index = 0;
    size_t end_index = 0;
    size_t split_count = 0;
    while(end_index < s.size() && split_count < count)
    {
        end_index = s.find(delim, start_index);
        result.push_back(s.substr(start_index, end_index - start_index));
        start_index = std::min(end_index, s.size()) + delim.size();
        ++split_count;
    }

    if(start_index <= s.size())
    {
        result.push_back(s.substr(start_index));
    }

    return result;
}

bool String::starts_with(const std::string& s, const std::string& beginning) noexcept
{
    return std::mismatch(beginning.begin(), beginning.end(), s.begin(), s.end()).first == beginning.end();
}

std::string String::trim_outer_whitespace(const std::string& s) noexcept
{
    constexpr auto whitespace = " \t\n\r";
    const auto text_start = s.find_first_not_of(whitespace);
    if(text_start == std::string::npos)
    {
        return {};
    }

    const auto text_end = s.find_last_not_of(whitespace);
    return s.substr(text_start, text_end - text_start + 1);
}

std::string String::remove_extra_whitespace(const std::string& s) noexcept
{
    std::string result;
    std::copy_if(s.begin(), s.end(), std::back_inserter(result),
                 [&result](auto c)
                 {
                     return ! isspace(c) || ( ! result.empty() && ! std::isspace(result.back()));
                 });

    return trim_outer_whitespace(result);
}

std::string String::strip_comments(const std::string& str, const std::string& comment) noexcept
{
    return trim_outer_whitespace(str.substr(0, str.find(comment)));
}

std::string String::strip_block_comment(const std::string& str, const std::string& start, const std::string& end)
{
    const auto start_comment_index = str.find(start);
    const auto end_comment_index = str.find(end);

    if(start_comment_index == std::string::npos && end_comment_index == std::string::npos)
    {
        return trim_outer_whitespace(str);
    }

    if(start_comment_index == std::string::npos || end_comment_index == std::string::npos)
    {
        throw std::invalid_argument("\"" + str + "\" is missing a comment delimiter: " + start + end);
    }

    if(start_comment_index >= end_comment_index)
    {
        throw std::invalid_argument("\"" + str + "\" contains bad comment delimiters: " + start + end);
    }

    try
    {
        const auto first_part = str.substr(0, start_comment_index);
        const auto last_part = str.substr(end_comment_index + end.size());
        return strip_block_comment(trim_outer_whitespace(first_part) + " " + trim_outer_whitespace(last_part), start, end);
    }
    catch(const std::invalid_argument& e)
    {
        throw std::invalid_argument(e.what() + std::string("\nOriginal line: ") + str);
    }
}

std::string String::strip_nested_block_comments(const std::string& str, const std::string& start, const std::string& end)
{
    if(contains(start, end) || contains(end, start))
    {
        throw std::invalid_argument("Delimiters cannot share substrings: " + start + "," + end + ".");
    }

    const auto error_message = "Invalid nesting of delimiters " + start + "," + end + ": " + str;
    std::string result;
    auto depth = 0;
    size_t index = 0;
    while(index < str.size())
    {
        auto start_index = str.find(start, index);
        auto end_index = str.find(end, index);
        if(start_index < end_index)
        {
            if(depth == 0)
            {
                result += str.substr(index, start_index - index);
            }
            ++depth;
            index = start_index + start.size();
        }
        else if(end_index < start_index)
        {
            if(depth == 0)
            {
                throw std::invalid_argument(error_message);
            }
            --depth;
            index = end_index + end.size();
        }
        else // start_index == end_index == std::string::npos
        {
            result += str.substr(index);
            break;
        }
    }

    if(depth != 0)
    {
        throw std::invalid_argument(error_message);
    }

    return result;
}

std::string String::remove_pgn_comments(const std::string& line)
{
    const auto index = line.find_first_of(";({");
    const auto delimiter = index < std::string::npos ? line[index] : '\0';

    switch(delimiter)
    {
        case ';' : return remove_pgn_comments(strip_comments(line, ";"));
        case '(' : return remove_pgn_comments(strip_nested_block_comments(line, "(", ")"));
        case '{' : return remove_pgn_comments(strip_block_comment(line, "{", "}"));
        default  : return remove_extra_whitespace(line);
    }
}

std::string String::extract_delimited_text(const std::string& str, const std::string& start, const std::string& end)
{
    const auto start_split = split(str, start, 1);
    if(start_split.size() != 2)
    {
        throw std::invalid_argument("Starting delimiter not found in \"" + str + "\": " + start + " " + end);
    }
    const auto start_of_inside = start_split[1];
    const auto inside_split = split(start_of_inside, end, 1);
    if(inside_split.size() != 2)
    {
        throw std::invalid_argument("Ending delimiter not found in \"" + str + "\": " + start + " " + end);
    }
    return inside_split[0];
}

char String::tolower(const char letter) noexcept
{
    return char(std::tolower(letter));
}

char String::toupper(const char letter) noexcept
{
    return char(std::toupper(letter));
}

std::string String::lowercase(std::string s) noexcept
{
    std::transform(s.begin(), s.end(), s.begin(), String::tolower);
    return s;
}

std::string String::round_to_decimals(const double x, const size_t decimal_places) noexcept
{
    auto result = std::ostringstream();
    result << std::fixed << std::setprecision(int(decimal_places)) << x;
    return result.str();
}

std::string String::date_and_time_format(const std::chrono::system_clock::time_point& point_in_time,
                                         const std::string& format) noexcept
{
    const auto time_c = std::chrono::system_clock::to_time_t(point_in_time);
    std::tm time_out;
#ifdef _WIN32
    localtime_s(&time_out, &time_c);
#elif defined(__linux__)
    localtime_r(&time_c, &time_out);
#endif
    auto ss = std::ostringstream{};
    ss << std::put_time(&time_out, format.c_str());
    return ss.str();
}

std::string String::add_to_file_name(const std::string& original_file_name, const std::string& addition) noexcept
{
    const auto dot_index = std::min(original_file_name.find_last_of('.'), original_file_name.size());
    return original_file_name.substr(0, dot_index) + addition + original_file_name.substr(dot_index);
}
<commit_msg>Simplify extract_delimited_text()<commit_after>#include "Utility/String.h"

#include <string>
#include <vector>
#include <stdexcept>
#include <algorithm>
#include <cctype>
#include <chrono>
#include <iomanip>
#include <sstream>
#include <cmath>

std::vector<std::string> String::split(const std::string& s, const std::string& delim, const size_t count) noexcept
{
    if(delim.empty())
    {
        return split(remove_extra_whitespace(s), " ", count);
    }

    if(s.empty())
    {
        return {};
    }

    std::vector<std::string> result;
    size_t start_index = 0;
    size_t end_index = 0;
    size_t split_count = 0;
    while(end_index < s.size() && split_count < count)
    {
        end_index = s.find(delim, start_index);
        result.push_back(s.substr(start_index, end_index - start_index));
        start_index = std::min(end_index, s.size()) + delim.size();
        ++split_count;
    }

    if(start_index <= s.size())
    {
        result.push_back(s.substr(start_index));
    }

    return result;
}

bool String::starts_with(const std::string& s, const std::string& beginning) noexcept
{
    return std::mismatch(beginning.begin(), beginning.end(), s.begin(), s.end()).first == beginning.end();
}

std::string String::trim_outer_whitespace(const std::string& s) noexcept
{
    constexpr auto whitespace = " \t\n\r";
    const auto text_start = s.find_first_not_of(whitespace);
    if(text_start == std::string::npos)
    {
        return {};
    }

    const auto text_end = s.find_last_not_of(whitespace);
    return s.substr(text_start, text_end - text_start + 1);
}

std::string String::remove_extra_whitespace(const std::string& s) noexcept
{
    std::string result;
    std::copy_if(s.begin(), s.end(), std::back_inserter(result),
                 [&result](auto c)
                 {
                     return ! isspace(c) || ( ! result.empty() && ! std::isspace(result.back()));
                 });

    return trim_outer_whitespace(result);
}

std::string String::strip_comments(const std::string& str, const std::string& comment) noexcept
{
    return trim_outer_whitespace(str.substr(0, str.find(comment)));
}

std::string String::strip_block_comment(const std::string& str, const std::string& start, const std::string& end)
{
    const auto start_comment_index = str.find(start);
    const auto end_comment_index = str.find(end);

    if(start_comment_index == std::string::npos && end_comment_index == std::string::npos)
    {
        return trim_outer_whitespace(str);
    }

    if(start_comment_index == std::string::npos || end_comment_index == std::string::npos)
    {
        throw std::invalid_argument("\"" + str + "\" is missing a comment delimiter: " + start + end);
    }

    if(start_comment_index >= end_comment_index)
    {
        throw std::invalid_argument("\"" + str + "\" contains bad comment delimiters: " + start + end);
    }

    try
    {
        const auto first_part = str.substr(0, start_comment_index);
        const auto last_part = str.substr(end_comment_index + end.size());
        return strip_block_comment(trim_outer_whitespace(first_part) + " " + trim_outer_whitespace(last_part), start, end);
    }
    catch(const std::invalid_argument& e)
    {
        throw std::invalid_argument(e.what() + std::string("\nOriginal line: ") + str);
    }
}

std::string String::strip_nested_block_comments(const std::string& str, const std::string& start, const std::string& end)
{
    if(contains(start, end) || contains(end, start))
    {
        throw std::invalid_argument("Delimiters cannot share substrings: " + start + "," + end + ".");
    }

    const auto error_message = "Invalid nesting of delimiters " + start + "," + end + ": " + str;
    std::string result;
    auto depth = 0;
    size_t index = 0;
    while(index < str.size())
    {
        auto start_index = str.find(start, index);
        auto end_index = str.find(end, index);
        if(start_index < end_index)
        {
            if(depth == 0)
            {
                result += str.substr(index, start_index - index);
            }
            ++depth;
            index = start_index + start.size();
        }
        else if(end_index < start_index)
        {
            if(depth == 0)
            {
                throw std::invalid_argument(error_message);
            }
            --depth;
            index = end_index + end.size();
        }
        else // start_index == end_index == std::string::npos
        {
            result += str.substr(index);
            break;
        }
    }

    if(depth != 0)
    {
        throw std::invalid_argument(error_message);
    }

    return result;
}

std::string String::remove_pgn_comments(const std::string& line)
{
    const auto index = line.find_first_of(";({");
    const auto delimiter = index < std::string::npos ? line[index] : '\0';

    switch(delimiter)
    {
        case ';' : return remove_pgn_comments(strip_comments(line, ";"));
        case '(' : return remove_pgn_comments(strip_nested_block_comments(line, "(", ")"));
        case '{' : return remove_pgn_comments(strip_block_comment(line, "{", "}"));
        default  : return remove_extra_whitespace(line);
    }
}

std::string String::extract_delimited_text(const std::string& str, const std::string& start, const std::string& end)
{
    const auto first_delimiter_index = str.find(start);
    if(first_delimiter_index == std::string::npos)
    {
        throw std::invalid_argument("Starting delimiter not found in \"" + str + "\": " + start + " " + end);
    }
    const auto text_start_index = first_delimiter_index + start.size();

    const auto second_delimiter_index = str.find(end, text_start_index);
    if(second_delimiter_index == std::string::npos)
    {
        throw std::invalid_argument("Ending delimiter not found in \"" + str + "\": " + start + " " + end);
    }
    const auto text_length = second_delimiter_index - text_start_index;

    return str.substr(text_start_index, text_length);
}

char String::tolower(const char letter) noexcept
{
    return char(std::tolower(letter));
}

char String::toupper(const char letter) noexcept
{
    return char(std::toupper(letter));
}

std::string String::lowercase(std::string s) noexcept
{
    std::transform(s.begin(), s.end(), s.begin(), String::tolower);
    return s;
}

std::string String::round_to_decimals(const double x, const size_t decimal_places) noexcept
{
    auto result = std::ostringstream();
    result << std::fixed << std::setprecision(int(decimal_places)) << x;
    return result.str();
}

std::string String::date_and_time_format(const std::chrono::system_clock::time_point& point_in_time,
                                         const std::string& format) noexcept
{
    const auto time_c = std::chrono::system_clock::to_time_t(point_in_time);
    std::tm time_out;
#ifdef _WIN32
    localtime_s(&time_out, &time_c);
#elif defined(__linux__)
    localtime_r(&time_c, &time_out);
#endif
    auto ss = std::ostringstream{};
    ss << std::put_time(&time_out, format.c_str());
    return ss.str();
}

std::string String::add_to_file_name(const std::string& original_file_name, const std::string& addition) noexcept
{
    const auto dot_index = std::min(original_file_name.find_last_of('.'), original_file_name.size());
    return original_file_name.substr(0, dot_index) + addition + original_file_name.substr(dot_index);
}
<|endoftext|>


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

#include "mirtk/IntensityCrossCorrelation.h"

#include "mirtk/Math.h"
#include "mirtk/ObjectFactory.h"

namespace mirtk {

// Register energy term with object factory during static initialization
mirtkAutoRegisterEnergyTermMacro(IntensityCrossCorrelation);

// =============================================================================
// Construction/Destruction
// =============================================================================

// -----------------------------------------------------------------------------
IntensityCrossCorrelation
::IntensityCrossCorrelation(const char *name)
:
  ImageSimilarity(name)
{
}

// -----------------------------------------------------------------------------
IntensityCrossCorrelation
::IntensityCrossCorrelation(const IntensityCrossCorrelation &other)
:
  ImageSimilarity(other)
{
}

// -----------------------------------------------------------------------------
IntensityCrossCorrelation::~IntensityCrossCorrelation()
{
}

// =============================================================================
// Evaluation
// =============================================================================

// -----------------------------------------------------------------------------
double IntensityCrossCorrelation::Evaluate()
{
  VoxelType *tgt = Target()->GetPointerToVoxels();
  VoxelType *src = Source()->GetPointerToVoxels();

  double x = .0, y = .0, xy = .0, x2 = .0, y2 = .0;
  int    n =  0;
  for (int idx = 0; idx < NumberOfVoxels(); ++idx) {
    if (IsForeground(idx)) {
      x  += *tgt;
      y  += *src;
      xy += (*tgt) * (*src);
      x2 += (*tgt) * (*tgt);
      y2 += (*tgt) * (*tgt);
      ++n;
    }
  }

  if (n == 0) return .0;
  return (xy - (x * y) / n) / (sqrt(x2 - x * x / n) * sqrt(y2 - y *y / n));
}

// -----------------------------------------------------------------------------
bool IntensityCrossCorrelation
::NonParametricGradient(const RegisteredImage *image, GradientImageType *gradient)
{
  cerr << "IntensityCrossCorrelation::NonParametricGradient: Not implemented" << endl;
  exit(1);

  // Apply chain rule to obtain gradient w.r.t y = T(x)
  MultiplyByImageGradient(image, gradient);
  return true;
}

} // namespace mirtk
<commit_msg>fix: Cross correlation evaluation [Registration]<commit_after>/*
 * Medical Image Registration ToolKit (MIRTK)
 *
 * Copyright 2013-2015 Imperial College London
 * Copyright 2013-2015 Andreas Schuh
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "mirtk/IntensityCrossCorrelation.h"

#include "mirtk/Math.h"
#include "mirtk/ObjectFactory.h"

namespace mirtk {

// Register energy term with object factory during static initialization
mirtkAutoRegisterEnergyTermMacro(IntensityCrossCorrelation);

// =============================================================================
// Construction/Destruction
// =============================================================================

// -----------------------------------------------------------------------------
IntensityCrossCorrelation
::IntensityCrossCorrelation(const char *name)
:
  ImageSimilarity(name)
{
}

// -----------------------------------------------------------------------------
IntensityCrossCorrelation
::IntensityCrossCorrelation(const IntensityCrossCorrelation &other)
:
  ImageSimilarity(other)
{
}

// -----------------------------------------------------------------------------
IntensityCrossCorrelation::~IntensityCrossCorrelation()
{
}

// =============================================================================
// Evaluation
// =============================================================================

// -----------------------------------------------------------------------------
double IntensityCrossCorrelation::Evaluate()
{
  VoxelType *tgt = Target()->Data();
  VoxelType *src = Source()->Data();

  double x = .0, y = .0, xy = .0, x2 = .0, y2 = .0;
  int    n =  0;
  for (int idx = 0; idx < NumberOfVoxels(); ++idx, ++tgt, ++src) {
    if (IsForeground(idx)) {
      x  += *tgt;
      y  += *src;
      xy += (*tgt) * (*src);
      x2 += (*tgt) * (*tgt);
      y2 += (*tgt) * (*tgt);
      ++n;
    }
  }

  if (n == 0) return .0;
  return (xy - (x * y) / n) / (sqrt(x2 - x * x / n) * sqrt(y2 - y *y / n));
}

// -----------------------------------------------------------------------------
bool IntensityCrossCorrelation
::NonParametricGradient(const RegisteredImage *image, GradientImageType *gradient)
{
  cerr << "IntensityCrossCorrelation::NonParametricGradient: Not implemented" << endl;
  exit(1);

  // Apply chain rule to obtain gradient w.r.t y = T(x)
  MultiplyByImageGradient(image, gradient);
  return true;
}

} // namespace mirtk
<|endoftext|>


<commit_before>// This file is part of Poseidon.
// Copyleft 2020, LH_Mouse. All wrongs reserved.

#ifndef POSEIDON_SOCKET_SOCKET_ADDRESS_HPP_
#  error Please include <poseidon/socket/socket/address.hpp> instead.
#endif

namespace poseidon {
namespace details_socket_address {

union storage
  {
    ::sockaddr_storage stor;
    ::sockaddr addr;
    ::sockaddr_in addr4;
    ::sockaddr_in6 addr6;

    // This union is implicit convertible to `void*`.
    constexpr operator
    const void*()
    const noexcept
      { return &(this->addr);  }

    operator
    void*()
    noexcept
      { return &(this->addr);  }

    // This union is implicit convertible to `sockaddr*`.
    constexpr operator
    const ::sockaddr*()
    const noexcept
      { return &(this->addr);  }

    operator
    ::sockaddr*()
    noexcept
      { return &(this->addr);  }

    // This union is implicit convertible to an IPv4 address.
    constexpr operator
    const ::sockaddr_in*()
    const noexcept
      { return &(this->addr4);  }

    operator
    ::sockaddr_in*()
    noexcept
      { return &(this->addr4);  }

    // This union is implicit convertible to an IPv6 address.
    constexpr operator
    const ::sockaddr_in6*()
    const noexcept
      { return &(this->addr6);  }

    operator
    ::sockaddr_in6*()
    noexcept
      { return &(this->addr6);  }
  };

}  // namespace details_socket_address
}  // namespace poseidon
<commit_msg>details/socket_address: Fix typo<commit_after>// This file is part of Poseidon.
// Copyleft 2020, LH_Mouse. All wrongs reserved.

#ifndef POSEIDON_SOCKET_SOCKET_ADDRESS_HPP_
#  error Please include <poseidon/socket/socket_address.hpp> instead.
#endif

namespace poseidon {
namespace details_socket_address {

union storage
  {
    ::sockaddr_storage stor;
    ::sockaddr addr;
    ::sockaddr_in addr4;
    ::sockaddr_in6 addr6;

    // This union is implicit convertible to `void*`.
    constexpr operator
    const void*()
    const noexcept
      { return &(this->addr);  }

    operator
    void*()
    noexcept
      { return &(this->addr);  }

    // This union is implicit convertible to `sockaddr*`.
    constexpr operator
    const ::sockaddr*()
    const noexcept
      { return &(this->addr);  }

    operator
    ::sockaddr*()
    noexcept
      { return &(this->addr);  }

    // This union is implicit convertible to an IPv4 address.
    constexpr operator
    const ::sockaddr_in*()
    const noexcept
      { return &(this->addr4);  }

    operator
    ::sockaddr_in*()
    noexcept
      { return &(this->addr4);  }

    // This union is implicit convertible to an IPv6 address.
    constexpr operator
    const ::sockaddr_in6*()
    const noexcept
      { return &(this->addr6);  }

    operator
    ::sockaddr_in6*()
    noexcept
      { return &(this->addr6);  }
  };

}  // namespace details_socket_address
}  // namespace poseidon
<|endoftext|>