<commit_before>/**
  * Touhou Community Reliant Automatic Patcher
  * Main DLL
  *
  * ----
  *
  * Logging functions.
  */

#include "thcrap.h"
#include <io.h>
#include <fcntl.h>
#include <ThreadPool.h>

// -------
// Globals
// -------
static HANDLE log_file = INVALID_HANDLE_VALUE;
static bool console_open = false;
static ThreadPool *log_queue = NULL;
// For checking nested thcrap instances that access the same log file.
// We only want to print an error message for the first instance.
static HANDLE log_filemapping = INVALID_HANDLE_VALUE;
static const char LOG[] = "logs/thcrap_log.txt";
static const char LOG_ROTATED[] = "logs/thcrap_log.%d.txt";
static const int ROTATIONS = 5; // Number of backups to keep
static void (*log_print_hook)(const char*) = NULL;
static void(*log_nprint_hook)(const char*, size_t) = NULL;
static HWND mbox_owner_hwnd = NULL; // Set by log_mbox_set_owner
// -----------------------

struct lasterror_t {
	char str[DECIMAL_DIGITS_BOUND(DWORD) + 1];
};

THREAD_LOCAL(lasterror_t, lasterror_tls, nullptr, nullptr);

const char* lasterror_str_for(DWORD err)
{
	switch(err) {
	case ERROR_SHARING_VIOLATION:
		return "File in use";
	case ERROR_MOD_NOT_FOUND:
		return "File not found";
	default: // -Wswitch...
		break;
	}
	auto str = lasterror_tls_get();
	if(!str) {
		static lasterror_t lasterror_static;
		str = &lasterror_static;
	}
	snprintf(str->str, sizeof(str->str), "%lu", err);
	return str->str;
}

const char* lasterror_str()
{
	return lasterror_str_for(GetLastError());
}

void log_set_hook(void(*print_hook)(const char*), void(*nprint_hook)(const char*,size_t)){
	log_print_hook = print_hook;
	log_nprint_hook = nprint_hook;
}

// Rotation
// --------
void log_fn_for_rotation(char *fn, int rotnum)
{
	if(rotnum == 0) {
		strcpy(fn, LOG);
	} else {
		sprintf(fn, LOG_ROTATED, rotnum);
	}
}

void log_rotate(void)
{
	size_t rot_fn_len = MAX(sizeof(LOG_ROTATED), sizeof(LOG));
	VLA(char, rot_from, rot_fn_len);
	VLA(char, rot_to, rot_fn_len);

	for(int rotation = ROTATIONS; rotation > 0; rotation--) {
		log_fn_for_rotation(rot_from, rotation - 1);
		log_fn_for_rotation(rot_to, rotation);
		MoveFileExU(rot_from, rot_to, MOVEFILE_REPLACE_EXISTING);
	}

	VLA_FREE(rot_from);
	VLA_FREE(rot_to);
}
// --------

void log_print(const char *str)
{
	if (log_queue) {
		log_queue->enqueue([str = strdup(str)]() {
			DWORD byteRet;
			if (console_open) {
				WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), str, strlen(str), &byteRet, NULL);
			}
			if (log_file) {
				WriteFile(log_file, str, strlen(str), &byteRet, NULL);
			}
			if (log_print_hook) {
				log_print_hook(str);
			}
			free(str);
		});
	}
}

void log_print_fast(const char* str, size_t n) {
	if (log_queue) {
		log_queue->enqueue([str = strndup(str, n), n]() {
			DWORD byteRet;
			if (console_open) {
				WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), str, n, &byteRet, NULL);
			}
			if (log_file != INVALID_HANDLE_VALUE) {
				WriteFile(log_file, str, n, &byteRet, NULL);
			}
			if (log_print_hook) {
				log_print_hook(str);
			}
			free(str);
		});
	}
}

void log_nprint(const char *str, size_t n)
{
	if (log_queue) {
		log_queue->enqueue([str = strndup(str, n), n]() {
			DWORD byteRet;
			if (console_open) {
				WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), str, n, &byteRet, NULL);
			}
			if (log_file != INVALID_HANDLE_VALUE) {
				WriteFile(log_file, str, n, &byteRet, NULL);
			}
			if (log_nprint_hook) {
				log_nprint_hook(str, n);
			}
			free(str);
		});
	}
}

void log_vprintf(const char *format, va_list va)
{
	va_list va2;
	va_copy(va2, va);
	const int total_size = vsnprintf(NULL, 0, format, va2);
	va_end(va2);
	if (total_size > 0) {
		VLA(char, str, total_size + 1);
		vsprintf(str, format, va);
		log_print_fast(str, total_size);
		VLA_FREE(str);
	}
}

void log_printf(const char *format, ...)
{
	va_list va;
	va_start(va, format);
	log_vprintf(format, va);
	va_end(va);
}

/**
  * Message box functions.
  */

struct EnumStatus
{
	HWND hwnd;
	int w;
	int h;
};

static BOOL CALLBACK enumWindowProc(HWND hwnd, LPARAM lParam)
{
	EnumStatus *status = (EnumStatus*)lParam;

	if (!IsWindowVisible(hwnd)) {
		return TRUE;
	}

	DWORD pid;
	GetWindowThreadProcessId(hwnd, &pid);
	if (pid != GetCurrentProcessId()) {
		return TRUE;
	}

	RECT rect;
	GetWindowRect(hwnd, &rect);
	int w = rect.right - rect.left;
	int h = rect.bottom - rect.top;
	if (w * h > status->w * status->h) {
		status->hwnd = hwnd;
	}

	return TRUE;
}

static HWND guess_mbox_owner()
{
	// If an owner have been set, easy - just return it.
	if (mbox_owner_hwnd) {
		return mbox_owner_hwnd;
	}

	// Time to guess. If the current thread has an active window, it's probably a good window to steal.
	HWND hwnd = GetActiveWindow();
	if (hwnd) {
		return hwnd;
	}

	// It's getting harder. Look at all the top-level visible windows of our processes, and take the biggest one.
	EnumStatus status;
	status.hwnd = nullptr;
	status.w = 10; // Ignore windows smaller than 10x10
	status.h = 10;
	EnumWindows(enumWindowProc, (LPARAM)&status);
	if (status.hwnd) {
		return status.hwnd;
	}

	// Let's hope our process is allowed to take the focus.
	return nullptr;
}

int log_mbox(const char *caption, const UINT type, const char *text)
{
	log_printf(
		"---------------------------\n"
		"%s\n"
		"---------------------------\n"
		, text
	);
	return MessageBox(guess_mbox_owner(), text, (caption ? caption : PROJECT_NAME), type);
}

int log_vmboxf(const char *caption, const UINT type, const char *format, va_list va)
{
	int ret = 0;
	if(format) {
		va_list va2;
		va_copy(va2, va);
		const int total_size = vsnprintf(NULL, 0, format, va2);
		va_end(va2);
		if (total_size > 0) {
			VLA(char, formatted_str, total_size + 1);
			vsprintf(formatted_str, format, va);
			ret = log_mbox(caption, type, formatted_str);
			VLA_FREE(formatted_str);
		}
	}
	return ret;
}

int log_mboxf(const char *caption, const UINT type, const char *format, ...)
{
	va_list va;
	va_start(va, format);
	int ret = log_vmboxf(caption, type, format, va);
	va_end(va);
	return ret;
}

void log_mbox_set_owner(HWND hwnd)
{
	mbox_owner_hwnd = hwnd;
}

static void OpenConsole(void)
{
	if(console_open) {
		return;
	}
	AllocConsole();

	// To match the behavior of the native Windows console, Wine additionally
	// needs read rights because its WriteConsole() implementation calls
	// GetConsoleMode(), and setvbuf() because… I don't know?

	/// This breaks all normal, unlogged printf() calls to stdout!
	// _setmode(_fileno(stdout), _O_U16TEXT);

	console_open = true;
}

/// Per-module loggers
/// ------------------
std::nullptr_t logger_t::verrorf(const char *format, va_list va) const
{
	va_list va2;
	va_copy(va2, va);
	const int total_size = vsnprintf(NULL, 0, format, va2);
	va_end(va2);
	if (total_size > 0) {
		VLA(char, formatted_str, total_size + 1 + prefix.length());
		memcpy(formatted_str, prefix.data(), prefix.length());
		vsprintf(formatted_str + prefix.length(), format, va);
		log_mbox(err_caption, MB_OK | MB_ICONERROR, formatted_str);
		VLA_FREE(formatted_str);
	}
	return nullptr;
}

std::nullptr_t logger_t::errorf(const char *format, ...) const
{
	va_list va;
	va_start(va, format);
	auto ret = verrorf(format, va);
	va_end(va);
	return ret;
}
/// ------------------

void log_init(int console)
{
	CreateDirectoryU("logs", NULL);
	log_rotate();

	// Using CreateFile, _open_osfhandle and _fdopen instead of plain fopen because we need the flag FILE_SHARE_DELETE for log rotation
	log_file = CreateFileU(LOG, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
	log_queue = new ThreadPool(1);
#ifdef _DEBUG
	OpenConsole();
#else
	if(log_file) {

		constexpr std::string_view DashUChar = u8"―";

		const size_t line_len = (strlen(PROJECT_NAME) + strlen(" logfile")) * DashUChar.length();
		VLA(char, line, line_len + 1);
		line[line_len] = '\0';

		for (size_t i = 0; i < line_len; i += DashUChar.length()) {
			memcpy(&line[i], DashUChar.data(), DashUChar.length());
		}

		log_printf("%s\n", line);
		log_printf("%s logfile\n", PROJECT_NAME);
		log_printf("Branch: %s\n", PROJECT_BRANCH);
		log_printf("Version: %s\n", PROJECT_VERSION_STRING);
		log_printf("Build time: "  __DATE__ " " __TIME__ "\n");
#if defined(BUILDER_NAME_W)
		{
			const wchar_t *builder = BUILDER_NAME_W;
			UTF8_DEC(builder);
			UTF8_CONV(builder);
			log_printf("Built by: %s\n", builder_utf8);
			UTF8_FREE(builder);
		}
#elif defined(BUILDER_NAME)
		log_printf("Built by: %s\n", BUILDER_NAME);
#endif
		log_printf("Command line: %s\n", GetCommandLineU());
		log_printf("%s\n\n", line);
		FlushFileBuffers(log_file);
		VLA_FREE(line);
	}
	if (console) {
		OpenConsole();
	}
#endif
	size_t cur_dir_len = GetCurrentDirectoryU(0, nullptr);
	size_t full_fn_len = cur_dir_len + sizeof(LOG);
	VLA(char, full_fn, full_fn_len);
	defer(VLA_FREE(full_fn));
	GetCurrentDirectoryU(cur_dir_len, full_fn);
	full_fn[cur_dir_len - 1] = '/';
	full_fn[cur_dir_len] = '\0';
	str_slash_normalize(full_fn); // Necessary!
	memcpy(full_fn + cur_dir_len, LOG, sizeof(LOG));

	log_filemapping = CreateFileMappingU(
		INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0, 1, full_fn
	);
	if(log_file == INVALID_HANDLE_VALUE && GetLastError() != ERROR_ALREADY_EXISTS) {
		auto ret = log_mboxf(nullptr, MB_OKCANCEL | MB_ICONHAND,
			"Error creating %s: %s\n"
			"\n"
			"Logging will be unavailable. "
			"Further writes to this directory are likely to fail as well. "
			"Moving %s to a different directory will probably fix this.\n"
			"\n"
			"Continue?",
			full_fn, strerror(errno), PROJECT_NAME_SHORT
		);
		if(ret == IDCANCEL) {
			auto pExitProcess = ((void (TH_STDCALL*)(UINT))detour_top(
				"kernel32.dll", "ExitProcess", (FARPROC)thcrap_ExitProcess
			));
			pExitProcess(-1);
		}
	}
}

void log_exit(void)
{
	// Run the destructor to ensure all remaining log messages were printed
	delete log_queue;

	if(console_open)
		FreeConsole();
	if(log_file) {
		CloseHandle(log_filemapping);
		CloseHandle(log_file);
		log_file = INVALID_HANDLE_VALUE;
	}
}
<commit_msg>thcrap: fix logging in Wine<commit_after>/**
  * Touhou Community Reliant Automatic Patcher
  * Main DLL
  *
  * ----
  *
  * Logging functions.
  */

#include "thcrap.h"
#include <io.h>
#include <fcntl.h>
#include <ThreadPool.h>

// -------
// Globals
// -------
static HANDLE log_file = INVALID_HANDLE_VALUE;
static bool console_open = false;
static ThreadPool *log_queue = NULL;
// For checking nested thcrap instances that access the same log file.
// We only want to print an error message for the first instance.
static HANDLE log_filemapping = INVALID_HANDLE_VALUE;
static const char LOG[] = "logs/thcrap_log.txt";
static const char LOG_ROTATED[] = "logs/thcrap_log.%d.txt";
static const int ROTATIONS = 5; // Number of backups to keep
static void (*log_print_hook)(const char*) = NULL;
static void(*log_nprint_hook)(const char*, size_t) = NULL;
static HWND mbox_owner_hwnd = NULL; // Set by log_mbox_set_owner
// -----------------------

struct lasterror_t {
	char str[DECIMAL_DIGITS_BOUND(DWORD) + 1];
};

THREAD_LOCAL(lasterror_t, lasterror_tls, nullptr, nullptr);

const char* lasterror_str_for(DWORD err)
{
	switch(err) {
	case ERROR_SHARING_VIOLATION:
		return "File in use";
	case ERROR_MOD_NOT_FOUND:
		return "File not found";
	default: // -Wswitch...
		break;
	}
	auto str = lasterror_tls_get();
	if(!str) {
		static lasterror_t lasterror_static;
		str = &lasterror_static;
	}
	snprintf(str->str, sizeof(str->str), "%lu", err);
	return str->str;
}

const char* lasterror_str()
{
	return lasterror_str_for(GetLastError());
}

void log_set_hook(void(*print_hook)(const char*), void(*nprint_hook)(const char*,size_t)){
	log_print_hook = print_hook;
	log_nprint_hook = nprint_hook;
}

// Rotation
// --------
void log_fn_for_rotation(char *fn, int rotnum)
{
	if(rotnum == 0) {
		strcpy(fn, LOG);
	} else {
		sprintf(fn, LOG_ROTATED, rotnum);
	}
}

void log_rotate(void)
{
	size_t rot_fn_len = MAX(sizeof(LOG_ROTATED), sizeof(LOG));
	VLA(char, rot_from, rot_fn_len);
	VLA(char, rot_to, rot_fn_len);

	for(int rotation = ROTATIONS; rotation > 0; rotation--) {
		log_fn_for_rotation(rot_from, rotation - 1);
		log_fn_for_rotation(rot_to, rotation);
		MoveFileExU(rot_from, rot_to, MOVEFILE_REPLACE_EXISTING);
	}

	VLA_FREE(rot_from);
	VLA_FREE(rot_to);
}
// --------

void log_print(const char *str)
{
	if (log_queue) {
		log_queue->enqueue([str = strdup(str)]() {
			DWORD byteRet;
			if (console_open) {
				WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), str, strlen(str), &byteRet, NULL);
			}
			if (log_file) {
				WriteFile(log_file, str, strlen(str), &byteRet, NULL);
			}
			if (log_print_hook) {
				log_print_hook(str);
			}
			free(str);
		});
	}
}

void log_print_fast(const char* str, size_t n) {
	if (log_queue) {
		log_queue->enqueue([str = strndup(str, n), n]() {
			DWORD byteRet;
			if (console_open) {
				WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), str, n, &byteRet, NULL);
			}
			if (log_file != INVALID_HANDLE_VALUE) {
				WriteFile(log_file, str, n, &byteRet, NULL);
			}
			if (log_print_hook) {
				log_print_hook(str);
			}
			free(str);
		});
	}
}

void log_nprint(const char *str, size_t n)
{
	if (log_queue) {
		log_queue->enqueue([str = strndup(str, n), n]() {
			DWORD byteRet;
			if (console_open) {
				WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), str, n, &byteRet, NULL);
			}
			if (log_file != INVALID_HANDLE_VALUE) {
				WriteFile(log_file, str, n, &byteRet, NULL);
			}
			if (log_nprint_hook) {
				log_nprint_hook(str, n);
			}
			free(str);
		});
	}
}

void log_vprintf(const char *format, va_list va)
{
	va_list va2;
	va_copy(va2, va);
	const int total_size = vsnprintf(NULL, 0, format, va2);
	va_end(va2);
	if (total_size > 0) {
		VLA(char, str, total_size + 1);
		vsprintf(str, format, va);
		log_print_fast(str, total_size);
		VLA_FREE(str);
	}
}

void log_printf(const char *format, ...)
{
	va_list va;
	va_start(va, format);
	log_vprintf(format, va);
	va_end(va);
}

/**
  * Message box functions.
  */

struct EnumStatus
{
	HWND hwnd;
	int w;
	int h;
};

static BOOL CALLBACK enumWindowProc(HWND hwnd, LPARAM lParam)
{
	EnumStatus *status = (EnumStatus*)lParam;

	if (!IsWindowVisible(hwnd)) {
		return TRUE;
	}

	DWORD pid;
	GetWindowThreadProcessId(hwnd, &pid);
	if (pid != GetCurrentProcessId()) {
		return TRUE;
	}

	RECT rect;
	GetWindowRect(hwnd, &rect);
	int w = rect.right - rect.left;
	int h = rect.bottom - rect.top;
	if (w * h > status->w * status->h) {
		status->hwnd = hwnd;
	}

	return TRUE;
}

static HWND guess_mbox_owner()
{
	// If an owner have been set, easy - just return it.
	if (mbox_owner_hwnd) {
		return mbox_owner_hwnd;
	}

	// Time to guess. If the current thread has an active window, it's probably a good window to steal.
	HWND hwnd = GetActiveWindow();
	if (hwnd) {
		return hwnd;
	}

	// It's getting harder. Look at all the top-level visible windows of our processes, and take the biggest one.
	EnumStatus status;
	status.hwnd = nullptr;
	status.w = 10; // Ignore windows smaller than 10x10
	status.h = 10;
	EnumWindows(enumWindowProc, (LPARAM)&status);
	if (status.hwnd) {
		return status.hwnd;
	}

	// Let's hope our process is allowed to take the focus.
	return nullptr;
}

int log_mbox(const char *caption, const UINT type, const char *text)
{
	log_printf(
		"---------------------------\n"
		"%s\n"
		"---------------------------\n"
		, text
	);
	return MessageBox(guess_mbox_owner(), text, (caption ? caption : PROJECT_NAME), type);
}

int log_vmboxf(const char *caption, const UINT type, const char *format, va_list va)
{
	int ret = 0;
	if(format) {
		va_list va2;
		va_copy(va2, va);
		const int total_size = vsnprintf(NULL, 0, format, va2);
		va_end(va2);
		if (total_size > 0) {
			VLA(char, formatted_str, total_size + 1);
			vsprintf(formatted_str, format, va);
			ret = log_mbox(caption, type, formatted_str);
			VLA_FREE(formatted_str);
		}
	}
	return ret;
}

int log_mboxf(const char *caption, const UINT type, const char *format, ...)
{
	va_list va;
	va_start(va, format);
	int ret = log_vmboxf(caption, type, format, va);
	va_end(va);
	return ret;
}

void log_mbox_set_owner(HWND hwnd)
{
	mbox_owner_hwnd = hwnd;
}

static void OpenConsole(void)
{
	if(console_open) {
		return;
	}
	AllocConsole();

	// To match the behavior of the native Windows console, Wine additionally
	// needs read rights because its WriteConsole() implementation calls
	// GetConsoleMode(), and setvbuf() because… I don't know?
	freopen("CONOUT$", "w+b", stdout);
	setvbuf(stdout, NULL, _IONBF, 0);

	/// This breaks all normal, unlogged printf() calls to stdout!
	// _setmode(_fileno(stdout), _O_U16TEXT);

	console_open = true;
}

/// Per-module loggers
/// ------------------
std::nullptr_t logger_t::verrorf(const char *format, va_list va) const
{
	va_list va2;
	va_copy(va2, va);
	const int total_size = vsnprintf(NULL, 0, format, va2);
	va_end(va2);
	if (total_size > 0) {
		VLA(char, formatted_str, total_size + 1 + prefix.length());
		memcpy(formatted_str, prefix.data(), prefix.length());
		vsprintf(formatted_str + prefix.length(), format, va);
		log_mbox(err_caption, MB_OK | MB_ICONERROR, formatted_str);
		VLA_FREE(formatted_str);
	}
	return nullptr;
}

std::nullptr_t logger_t::errorf(const char *format, ...) const
{
	va_list va;
	va_start(va, format);
	auto ret = verrorf(format, va);
	va_end(va);
	return ret;
}
/// ------------------

void log_init(int console)
{
	CreateDirectoryU("logs", NULL);
	log_rotate();

	// Using CreateFile, _open_osfhandle and _fdopen instead of plain fopen because we need the flag FILE_SHARE_DELETE for log rotation
	log_file = CreateFileU(LOG, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
	log_queue = new ThreadPool(1);
#ifdef _DEBUG
	OpenConsole();
#else
	if(log_file) {

		constexpr std::string_view DashUChar = u8"―";

		const size_t line_len = (strlen(PROJECT_NAME) + strlen(" logfile")) * DashUChar.length();
		VLA(char, line, line_len + 1);
		line[line_len] = '\0';

		for (size_t i = 0; i < line_len; i += DashUChar.length()) {
			memcpy(&line[i], DashUChar.data(), DashUChar.length());
		}

		log_printf("%s\n", line);
		log_printf("%s logfile\n", PROJECT_NAME);
		log_printf("Branch: %s\n", PROJECT_BRANCH);
		log_printf("Version: %s\n", PROJECT_VERSION_STRING);
		log_printf("Build time: "  __DATE__ " " __TIME__ "\n");
#if defined(BUILDER_NAME_W)
		{
			const wchar_t *builder = BUILDER_NAME_W;
			UTF8_DEC(builder);
			UTF8_CONV(builder);
			log_printf("Built by: %s\n", builder_utf8);
			UTF8_FREE(builder);
		}
#elif defined(BUILDER_NAME)
		log_printf("Built by: %s\n", BUILDER_NAME);
#endif
		log_printf("Command line: %s\n", GetCommandLineU());
		log_printf("%s\n\n", line);
		FlushFileBuffers(log_file);
		VLA_FREE(line);
	}
	if (console) {
		OpenConsole();
	}
#endif
	size_t cur_dir_len = GetCurrentDirectoryU(0, nullptr);
	size_t full_fn_len = cur_dir_len + sizeof(LOG);
	VLA(char, full_fn, full_fn_len);
	defer(VLA_FREE(full_fn));
	GetCurrentDirectoryU(cur_dir_len, full_fn);
	full_fn[cur_dir_len - 1] = '/';
	full_fn[cur_dir_len] = '\0';
	str_slash_normalize(full_fn); // Necessary!
	memcpy(full_fn + cur_dir_len, LOG, sizeof(LOG));

	log_filemapping = CreateFileMappingU(
		INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0, 1, full_fn
	);
	if(log_file == INVALID_HANDLE_VALUE && GetLastError() != ERROR_ALREADY_EXISTS) {
		auto ret = log_mboxf(nullptr, MB_OKCANCEL | MB_ICONHAND,
			"Error creating %s: %s\n"
			"\n"
			"Logging will be unavailable. "
			"Further writes to this directory are likely to fail as well. "
			"Moving %s to a different directory will probably fix this.\n"
			"\n"
			"Continue?",
			full_fn, strerror(errno), PROJECT_NAME_SHORT
		);
		if(ret == IDCANCEL) {
			auto pExitProcess = ((void (TH_STDCALL*)(UINT))detour_top(
				"kernel32.dll", "ExitProcess", (FARPROC)thcrap_ExitProcess
			));
			pExitProcess(-1);
		}
	}
}

void log_exit(void)
{
	// Run the destructor to ensure all remaining log messages were printed
	delete log_queue;

	if(console_open)
		FreeConsole();
	if(log_file) {
		CloseHandle(log_filemapping);
		CloseHandle(log_file);
		log_file = INVALID_HANDLE_VALUE;
	}
}
<|endoftext|>


<commit_before>#include "paint_area.hpp"

#include <cppurses/cppurses.hpp>
#include <signals/slot.hpp>

#include <cctype>
#include <codecvt>
#include <cstddef>
#include <cstdint>
#include <iostream>
#include <iterator>
#include <locale>
#include <string>
#include <utility>

using namespace cppurses;

namespace {

void insert_newline(Coordinates first, Coordinates second, std::ostream& os) {
    if (first.y == second.y) {
        return;
    }
    std::string newlines(second.y - first.y, '\n');
    os << newlines;
}

void insert_space(Coordinates first, Coordinates second, std::ostream& os) {
    std::size_t spaces_n{second.x};
    if (first.y == second.y) {
        spaces_n -= first.x + 1;
    }
    std::string spaces(spaces_n, ' ');
    os << spaces;
}

}  // namespace

namespace demos {
namespace glyph_paint {

Paint_area::Paint_area() {
    enable_border(*this);
    disable_walls(this->border);
    disable_corners(this->border);
    this->border.east_enabled = true;
    this->focus_policy = Focus_policy::Strong;
}

void Paint_area::set_glyph(Glyph glyph) {
    current_glyph_ = std::move(glyph);
    glyph_changed(current_glyph_);
    if (erase_enabled_) {
        this->disable_erase();
        erase_disabled();
    }
}

void Paint_area::set_symbol(const Glyph& symbol) {
    if (erase_enabled_) {
        this->disable_erase();
        erase_disabled();
    }
    current_glyph_.set_symbol(symbol.str());
    glyph_changed(current_glyph_);
}

void Paint_area::set_foreground_color(Color c) {
    current_glyph_.brush().set_foreground(c);
    if (!erase_enabled_) {
        glyph_changed(current_glyph_);
    }
}

void Paint_area::set_background_color(Color c) {
    current_glyph_.brush().set_background(c);
    if (!erase_enabled_) {
        glyph_changed(current_glyph_);
    }
}

void Paint_area::set_attribute(Attribute attr) {
    current_glyph_.brush().add_attributes(attr);
    if (!erase_enabled_) {
        glyph_changed(current_glyph_);
    }
}

void Paint_area::remove_attribute(Attribute attr) {
    current_glyph_.brush().remove_attribute(attr);
    if (!erase_enabled_) {
        glyph_changed(current_glyph_);
    }
}

void Paint_area::enable_erase() {
    erase_enabled_ = true;
    glyph_changed(" ");
}

void Paint_area::disable_erase() {
    erase_enabled_ = false;
    glyph_changed(current_glyph_);
}

void Paint_area::enable_grid() {
    this->background_tile = Glyph{"┼", foreground(Color::Dark_gray)};
    this->update();
}

void Paint_area::disable_grid() {
    this->background_tile = " ";
    this->update();
}

void Paint_area::clear() {
    glyphs_painted_.clear();
    this->update();
}

Glyph Paint_area::glyph() const {
    return current_glyph_;
}

void Paint_area::toggle_clone() {
    clone_enabled_ = !clone_enabled_;
}

void Paint_area::write(std::ostream& os) {
    Coordinates previous_nl{0, 0};
    Coordinates previous_s{0, static_cast<std::size_t>(-1)};
    for (const auto& cg_pair : glyphs_painted_) {
        insert_newline(previous_nl, cg_pair.first, os);
        insert_space(previous_s, cg_pair.first, os);
        os << cg_pair.second.str();
        previous_nl = cg_pair.first;
        previous_s = cg_pair.first;
    }
}

void Paint_area::read(std::istream& is) {
    this->clear();
    Coordinates current{0, 0};
    is >> std::noskipws;
    std::string file_text{std::istream_iterator<char>{is},
                          std::istream_iterator<char>()};
    Glyph_string file_glyphs{file_text};
    for (const Glyph& glyph : file_glyphs) {
        if (glyph != ' ' && glyph != '\n' && glyph != '\r') {
            glyphs_painted_[current] = glyph;
        }
        ++current.x;
        if (glyph == '\n') {
            ++current.y;
            current.x = 0;
        }
    }
}

bool Paint_area::paint_event() {
    Painter p{this};
    for (const auto& gc_pair : glyphs_painted_) {
        if (gc_pair.first.x < this->width() &&
            gc_pair.first.y < this->height()) {
            p.put(gc_pair.second, gc_pair.first);
        }
    }
    return Widget::paint_event();
}

bool Paint_area::mouse_press_event(Mouse_button button,
                                   std::size_t global_x,
                                   std::size_t global_y,
                                   std::size_t local_x,
                                   std::size_t local_y,
                                   std::uint8_t device_id) {
    this->place_glyph(local_x, local_y);
    return Widget::mouse_press_event(button, global_x, global_y, local_x,
                                     local_y, device_id);
}

bool Paint_area::key_press_event(Key key, char symbol) {
    if (!this->cursor_visible()) {
        return Widget::key_press_event(key, symbol);
    }
    if (this->width() == 0 || this->height() == 0) {
        return Widget::key_press_event(key, symbol);
    }
    std::size_t new_x{this->cursor_x() + 1};
    std::size_t new_y{this->cursor_y() + 1};
    switch (key) {
        case Key::Arrow_right:
            if (new_x == this->width()) {
                new_x = 0;
            }
            this->move_cursor_x(new_x);
            break;
        case Key::Arrow_left:
            this->move_cursor_x(this->cursor_x() - 1);
            break;
        case Key::Arrow_down:
            if (new_y == this->height()) {
                new_y = 0;
            }
            this->move_cursor_y(new_y);
            break;
        case Key::Arrow_up:
            this->move_cursor_y(this->cursor_y() - 1);
            break;
        case Key::Enter:
            this->place_glyph(this->cursor_x(), this->cursor_y());
            break;
        default:
            if (!std::iscntrl(symbol)) {
                this->set_symbol(symbol);
                this->place_glyph(this->cursor_x(), this->cursor_y());
                this->update();
            }
            break;
    }
    return Widget::key_press_event(key, symbol);
}

void Paint_area::place_glyph(std::size_t x, std::size_t y) {
    if (clone_enabled_) {
        if (glyphs_painted_.count(Coordinates{x, y}) == 1) {
            this->set_glyph(glyphs_painted_[Coordinates{x, y}]);
            this->toggle_clone();
        }
    } else if (erase_enabled_) {
        this->remove_glyph(Coordinates{x, y});
    } else {
        glyphs_painted_[Coordinates{x, y}] = current_glyph_;
        this->update();
    }
}

void Paint_area::remove_glyph(Coordinates coords) {
    glyphs_painted_.erase(coords);
    this->update();
}

namespace slot {

sig::Slot<void(Glyph)> set_glyph(Paint_area& pa) {
    sig::Slot<void(Glyph)> slot{[&pa](Glyph g) { pa.set_glyph(std::move(g)); }};
    slot.track(pa.destroyed);
    return slot;
}

sig::Slot<void()> set_glyph(Paint_area& pa, const Glyph& glyph) {
    sig::Slot<void()> slot{[&pa, glyph] { pa.set_glyph(glyph); }};
    slot.track(pa.destroyed);
    return slot;
}

sig::Slot<void(Glyph)> set_symbol(Paint_area& pa) {
    sig::Slot<void(Glyph)> slot{
        [&pa](Glyph symbol) { pa.set_symbol(std::move(symbol)); }};
    slot.track(pa.destroyed);
    return slot;
}

sig::Slot<void()> set_symbol(Paint_area& pa, const Glyph& symbol) {
    sig::Slot<void()> slot{[&pa, symbol] { pa.set_symbol(symbol); }};
    slot.track(pa.destroyed);
    return slot;
}

sig::Slot<void(Color)> set_foreground_color(Paint_area& pa) {
    sig::Slot<void(Color)> slot{[&pa](Color c) { pa.set_foreground_color(c); }};
    slot.track(pa.destroyed);
    return slot;
}

sig::Slot<void()> set_foreground_color(Paint_area& pa, Color c) {
    sig::Slot<void()> slot{[&pa, c] { pa.set_foreground_color(c); }};
    slot.track(pa.destroyed);
    return slot;
}

sig::Slot<void(Color)> set_background_color(Paint_area& pa) {
    sig::Slot<void(Color)> slot{[&pa](Color c) { pa.set_background_color(c); }};
    slot.track(pa.destroyed);
    return slot;
}

sig::Slot<void()> set_background_color(Paint_area& pa, Color c) {
    sig::Slot<void()> slot{[&pa, c] { pa.set_background_color(c); }};
    slot.track(pa.destroyed);
    return slot;
}

sig::Slot<void(Attribute)> set_attribute(Paint_area& pa) {
    sig::Slot<void(Attribute)> slot{
        [&pa](Attribute attr) { pa.set_attribute(attr); }};
    slot.track(pa.destroyed);
    return slot;
}

sig::Slot<void()> set_attribute(Paint_area& pa, Attribute attr) {
    sig::Slot<void()> slot{[&pa, attr] { pa.set_attribute(attr); }};
    slot.track(pa.destroyed);
    return slot;
}

sig::Slot<void(Attribute)> remove_attribute(Paint_area& pa) {
    sig::Slot<void(Attribute)> slot{
        [&pa](Attribute attr) { pa.remove_attribute(attr); }};
    slot.track(pa.destroyed);
    return slot;
}

sig::Slot<void()> remove_attribute(Paint_area& pa, Attribute attr) {
    sig::Slot<void()> slot{[&pa, attr] { pa.remove_attribute(attr); }};
    slot.track(pa.destroyed);
    return slot;
}

sig::Slot<void()> toggle_clone(Paint_area& pa) {
    sig::Slot<void()> slot{[&pa] { pa.toggle_clone(); }};
    slot.track(pa.destroyed);
    return slot;
}

sig::Slot<void()> clear(Paint_area& pa) {
    sig::Slot<void()> slot{[&pa] { pa.clear(); }};
    slot.track(pa.destroyed);
    return slot;
}

sig::Slot<void()> enable_erase(Paint_area& pa) {
    sig::Slot<void()> slot{[&pa] { pa.enable_erase(); }};
    slot.track(pa.destroyed);
    return slot;
}

sig::Slot<void()> disable_erase(Paint_area& pa) {
    sig::Slot<void()> slot{[&pa] { pa.disable_erase(); }};
    slot.track(pa.destroyed);
    return slot;
}

sig::Slot<void()> enable_grid(Paint_area& pa) {
    sig::Slot<void()> slot{[&pa] { pa.enable_grid(); }};
    slot.track(pa.destroyed);
    return slot;
}

sig::Slot<void()> disable_grid(Paint_area& pa) {
    sig::Slot<void()> slot{[&pa] { pa.disable_grid(); }};
    slot.track(pa.destroyed);
    return slot;
}

sig::Slot<void(std::ostream&)> write(Paint_area& pa) {
    sig::Slot<void(std::ostream&)> slot{
        [&pa](std::ostream& os) { pa.write(os); }};
    slot.track(pa.destroyed);
    return slot;
}

sig::Slot<void(std::istream&)> read(Paint_area& pa) {
    sig::Slot<void(std::istream&)> slot{
        [&pa](std::istream& is) { pa.read(is); }};
    slot.track(pa.destroyed);
    return slot;
}

}  // namespace slot
}  // namespace glyph_paint
}  // namespace demos
<commit_msg>Paint_area keypress allows for changing glyph when cursor is not visible.<commit_after>#include "paint_area.hpp"

#include <cppurses/cppurses.hpp>
#include <signals/slot.hpp>

#include <cctype>
#include <codecvt>
#include <cstddef>
#include <cstdint>
#include <iostream>
#include <iterator>
#include <locale>
#include <string>
#include <utility>

using namespace cppurses;

namespace {

void insert_newline(Coordinates first, Coordinates second, std::ostream& os) {
    if (first.y == second.y) {
        return;
    }
    std::string newlines(second.y - first.y, '\n');
    os << newlines;
}

void insert_space(Coordinates first, Coordinates second, std::ostream& os) {
    std::size_t spaces_n{second.x};
    if (first.y == second.y) {
        spaces_n -= first.x + 1;
    }
    std::string spaces(spaces_n, ' ');
    os << spaces;
}

}  // namespace

namespace demos {
namespace glyph_paint {

Paint_area::Paint_area() {
    enable_border(*this);
    disable_walls(this->border);
    disable_corners(this->border);
    this->border.east_enabled = true;
    this->focus_policy = Focus_policy::Strong;
}

void Paint_area::set_glyph(Glyph glyph) {
    current_glyph_ = std::move(glyph);
    glyph_changed(current_glyph_);
    if (erase_enabled_) {
        this->disable_erase();
        erase_disabled();
    }
}

void Paint_area::set_symbol(const Glyph& symbol) {
    if (erase_enabled_) {
        this->disable_erase();
        erase_disabled();
    }
    current_glyph_.set_symbol(symbol.str());
    glyph_changed(current_glyph_);
}

void Paint_area::set_foreground_color(Color c) {
    current_glyph_.brush().set_foreground(c);
    if (!erase_enabled_) {
        glyph_changed(current_glyph_);
    }
}

void Paint_area::set_background_color(Color c) {
    current_glyph_.brush().set_background(c);
    if (!erase_enabled_) {
        glyph_changed(current_glyph_);
    }
}

void Paint_area::set_attribute(Attribute attr) {
    current_glyph_.brush().add_attributes(attr);
    if (!erase_enabled_) {
        glyph_changed(current_glyph_);
    }
}

void Paint_area::remove_attribute(Attribute attr) {
    current_glyph_.brush().remove_attribute(attr);
    if (!erase_enabled_) {
        glyph_changed(current_glyph_);
    }
}

void Paint_area::enable_erase() {
    erase_enabled_ = true;
    glyph_changed(" ");
}

void Paint_area::disable_erase() {
    erase_enabled_ = false;
    glyph_changed(current_glyph_);
}

void Paint_area::enable_grid() {
    this->background_tile = Glyph{"┼", foreground(Color::Dark_gray)};
    this->update();
}

void Paint_area::disable_grid() {
    this->background_tile = " ";
    this->update();
}

void Paint_area::clear() {
    glyphs_painted_.clear();
    this->update();
}

Glyph Paint_area::glyph() const {
    return current_glyph_;
}

void Paint_area::toggle_clone() {
    clone_enabled_ = !clone_enabled_;
}

void Paint_area::write(std::ostream& os) {
    Coordinates previous_nl{0, 0};
    Coordinates previous_s{0, static_cast<std::size_t>(-1)};
    for (const auto& cg_pair : glyphs_painted_) {
        insert_newline(previous_nl, cg_pair.first, os);
        insert_space(previous_s, cg_pair.first, os);
        os << cg_pair.second.str();
        previous_nl = cg_pair.first;
        previous_s = cg_pair.first;
    }
}

void Paint_area::read(std::istream& is) {
    this->clear();
    Coordinates current{0, 0};
    is >> std::noskipws;
    std::string file_text{std::istream_iterator<char>{is},
                          std::istream_iterator<char>()};
    Glyph_string file_glyphs{file_text};
    for (const Glyph& glyph : file_glyphs) {
        if (glyph != ' ' && glyph != '\n' && glyph != '\r') {
            glyphs_painted_[current] = glyph;
        }
        ++current.x;
        if (glyph == '\n') {
            ++current.y;
            current.x = 0;
        }
    }
}

bool Paint_area::paint_event() {
    Painter p{this};
    for (const auto& gc_pair : glyphs_painted_) {
        if (gc_pair.first.x < this->width() &&
            gc_pair.first.y < this->height()) {
            p.put(gc_pair.second, gc_pair.first);
        }
    }
    return Widget::paint_event();
}

bool Paint_area::mouse_press_event(Mouse_button button,
                                   std::size_t global_x,
                                   std::size_t global_y,
                                   std::size_t local_x,
                                   std::size_t local_y,
                                   std::uint8_t device_id) {
    this->place_glyph(local_x, local_y);
    return Widget::mouse_press_event(button, global_x, global_y, local_x,
                                     local_y, device_id);
}

bool Paint_area::key_press_event(Key key, char symbol) {
    if (!this->cursor_visible()) {
        if (!std::iscntrl(symbol)) {
            this->set_symbol(symbol);
        }
        return Widget::key_press_event(key, symbol);
    }
    if (this->width() == 0 || this->height() == 0) {
        return Widget::key_press_event(key, symbol);
    }
    std::size_t new_x{this->cursor_x() + 1};
    std::size_t new_y{this->cursor_y() + 1};
    switch (key) {
        case Key::Arrow_right:
            if (new_x == this->width()) {
                new_x = 0;
            }
            this->move_cursor_x(new_x);
            break;
        case Key::Arrow_left:
            this->move_cursor_x(this->cursor_x() - 1);
            break;
        case Key::Arrow_down:
            if (new_y == this->height()) {
                new_y = 0;
            }
            this->move_cursor_y(new_y);
            break;
        case Key::Arrow_up:
            this->move_cursor_y(this->cursor_y() - 1);
            break;
        case Key::Enter:
            this->place_glyph(this->cursor_x(), this->cursor_y());
            break;
        default:
            if (!std::iscntrl(symbol)) {
                this->set_symbol(symbol);
                this->place_glyph(this->cursor_x(), this->cursor_y());
                this->update();
            }
            break;
    }
    return Widget::key_press_event(key, symbol);
}

void Paint_area::place_glyph(std::size_t x, std::size_t y) {
    if (clone_enabled_) {
        if (glyphs_painted_.count(Coordinates{x, y}) == 1) {
            this->set_glyph(glyphs_painted_[Coordinates{x, y}]);
            this->toggle_clone();
        }
    } else if (erase_enabled_) {
        this->remove_glyph(Coordinates{x, y});
    } else {
        glyphs_painted_[Coordinates{x, y}] = current_glyph_;
        this->update();
    }
}

void Paint_area::remove_glyph(Coordinates coords) {
    glyphs_painted_.erase(coords);
    this->update();
}

namespace slot {

sig::Slot<void(Glyph)> set_glyph(Paint_area& pa) {
    sig::Slot<void(Glyph)> slot{[&pa](Glyph g) { pa.set_glyph(std::move(g)); }};
    slot.track(pa.destroyed);
    return slot;
}

sig::Slot<void()> set_glyph(Paint_area& pa, const Glyph& glyph) {
    sig::Slot<void()> slot{[&pa, glyph] { pa.set_glyph(glyph); }};
    slot.track(pa.destroyed);
    return slot;
}

sig::Slot<void(Glyph)> set_symbol(Paint_area& pa) {
    sig::Slot<void(Glyph)> slot{
        [&pa](Glyph symbol) { pa.set_symbol(std::move(symbol)); }};
    slot.track(pa.destroyed);
    return slot;
}

sig::Slot<void()> set_symbol(Paint_area& pa, const Glyph& symbol) {
    sig::Slot<void()> slot{[&pa, symbol] { pa.set_symbol(symbol); }};
    slot.track(pa.destroyed);
    return slot;
}

sig::Slot<void(Color)> set_foreground_color(Paint_area& pa) {
    sig::Slot<void(Color)> slot{[&pa](Color c) { pa.set_foreground_color(c); }};
    slot.track(pa.destroyed);
    return slot;
}

sig::Slot<void()> set_foreground_color(Paint_area& pa, Color c) {
    sig::Slot<void()> slot{[&pa, c] { pa.set_foreground_color(c); }};
    slot.track(pa.destroyed);
    return slot;
}

sig::Slot<void(Color)> set_background_color(Paint_area& pa) {
    sig::Slot<void(Color)> slot{[&pa](Color c) { pa.set_background_color(c); }};
    slot.track(pa.destroyed);
    return slot;
}

sig::Slot<void()> set_background_color(Paint_area& pa, Color c) {
    sig::Slot<void()> slot{[&pa, c] { pa.set_background_color(c); }};
    slot.track(pa.destroyed);
    return slot;
}

sig::Slot<void(Attribute)> set_attribute(Paint_area& pa) {
    sig::Slot<void(Attribute)> slot{
        [&pa](Attribute attr) { pa.set_attribute(attr); }};
    slot.track(pa.destroyed);
    return slot;
}

sig::Slot<void()> set_attribute(Paint_area& pa, Attribute attr) {
    sig::Slot<void()> slot{[&pa, attr] { pa.set_attribute(attr); }};
    slot.track(pa.destroyed);
    return slot;
}

sig::Slot<void(Attribute)> remove_attribute(Paint_area& pa) {
    sig::Slot<void(Attribute)> slot{
        [&pa](Attribute attr) { pa.remove_attribute(attr); }};
    slot.track(pa.destroyed);
    return slot;
}

sig::Slot<void()> remove_attribute(Paint_area& pa, Attribute attr) {
    sig::Slot<void()> slot{[&pa, attr] { pa.remove_attribute(attr); }};
    slot.track(pa.destroyed);
    return slot;
}

sig::Slot<void()> toggle_clone(Paint_area& pa) {
    sig::Slot<void()> slot{[&pa] { pa.toggle_clone(); }};
    slot.track(pa.destroyed);
    return slot;
}

sig::Slot<void()> clear(Paint_area& pa) {
    sig::Slot<void()> slot{[&pa] { pa.clear(); }};
    slot.track(pa.destroyed);
    return slot;
}

sig::Slot<void()> enable_erase(Paint_area& pa) {
    sig::Slot<void()> slot{[&pa] { pa.enable_erase(); }};
    slot.track(pa.destroyed);
    return slot;
}

sig::Slot<void()> disable_erase(Paint_area& pa) {
    sig::Slot<void()> slot{[&pa] { pa.disable_erase(); }};
    slot.track(pa.destroyed);
    return slot;
}

sig::Slot<void()> enable_grid(Paint_area& pa) {
    sig::Slot<void()> slot{[&pa] { pa.enable_grid(); }};
    slot.track(pa.destroyed);
    return slot;
}

sig::Slot<void()> disable_grid(Paint_area& pa) {
    sig::Slot<void()> slot{[&pa] { pa.disable_grid(); }};
    slot.track(pa.destroyed);
    return slot;
}

sig::Slot<void(std::ostream&)> write(Paint_area& pa) {
    sig::Slot<void(std::ostream&)> slot{
        [&pa](std::ostream& os) { pa.write(os); }};
    slot.track(pa.destroyed);
    return slot;
}

sig::Slot<void(std::istream&)> read(Paint_area& pa) {
    sig::Slot<void(std::istream&)> slot{
        [&pa](std::istream& is) { pa.read(is); }};
    slot.track(pa.destroyed);
    return slot;
}

}  // namespace slot
}  // namespace glyph_paint
}  // namespace demos
<|endoftext|>


<commit_before>#include <gflags/gflags.h>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>

#include "util/diff.h"
#include "util/file_io.h"

int main(int argc, char** argv) {
  google::ParseCommandLineFlags(&argc, &argv, true);
  if (argc != 3) {
    std::cout << "usage: " << argv[0] << " file1 file2\n";
    return 1;
  }

  const std::vector<std::string> lhs = util::ReadFileLines(argv[1]);
  const std::vector<std::string> rhs = util::ReadFileLines(argv[2]);
  const auto difference = util::DiffSeqs(lhs, rhs);
  for (const auto& mod : difference) {
    if (mod.is_addition()) {
      std::cout << "[" << mod.addition().insert_pos - lhs.begin() << "]\t + "
                << *mod.addition().data << "\n";
    }
    if (mod.is_deletion()) {
      std::cout << "[" << mod.deletion().data - lhs.begin() << "]\t - "
                << *mod.deletion().data << "\n";
    }
  }
  return 0;
}
<commit_msg>fix diff_tool headers<commit_after>#include <gflags/gflags.h>
#include <iostream>
#include <string>
#include <vector>

#include "util/diff.h"
#include "util/file_io.h"

int main(int argc, char** argv) {
  google::ParseCommandLineFlags(&argc, &argv, true);
  if (argc != 3) {
    std::cout << "usage: " << argv[0] << " file1 file2\n";
    return 1;
  }

  const std::vector<std::string> lhs = util::ReadFileLines(argv[1]);
  const std::vector<std::string> rhs = util::ReadFileLines(argv[2]);
  const auto difference = util::DiffSeqs(lhs, rhs);
  for (const auto& mod : difference) {
    if (mod.is_addition()) {
      std::cout << "[" << mod.addition().insert_pos - lhs.begin() << "]\t + "
                << *mod.addition().data << "\n";
    }
    if (mod.is_deletion()) {
      std::cout << "[" << mod.deletion().data - lhs.begin() << "]\t - "
                << *mod.deletion().data << "\n";
    }
  }
  return 0;
}
<|endoftext|>


<commit_before><commit_msg>Add alert box suppression check box to linux js dialogs.<commit_after><|endoftext|>


<commit_before>/*

    Copyright Eli Dupree and Isaac Dupree, 2011, 2012

    This file is part of Lasercake.

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

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

    You should have received a copy of the GNU General Public License
    along with Lasercake.  If not, see <http://www.gnu.org/licenses/>.

*/

#ifndef LASERCAKE_TILE_ITERATION_HPP__
#define LASERCAKE_TILE_ITERATION_HPP__

#include <boost/logic/tribool.hpp>

#include "world.hpp"

using boost::tribool;
using boost::indeterminate;

struct boring_visitor {
  // return 'true' = definitely want to see everything within here,
  // 'false' = don't want to see anything within here,
  // 'indeterminate' = keep asking in more detail
  //    ('indeterminate' all the way down *will* call collidable_tile()).
  tribool look_here(power_of_two_bounding_cube<3, tile_coordinate> const&) {
    return true;
  }
  // return 'true' = keep going, 'false' = exit the search
  // giving tile_location an idx member should make just providing the tile_loc fine
  bool collidable_tile(tile_location const&) {
    return true;
  }
  // octant() is only called once, at the beginning of the search.
  octant_number octant()const { return 0; }
};

/*
slow_tile_location
tile_with_neighbors
tile_location could/should have an idx member.

ah the whiles could use idx and idx could be xored in the very inner place
to get the actual idx. i think that is most reasonable. and xyz will be pre-xored.
*/

// For your convenience:
inline bool overlaps(tile_bounding_box const& a, power_of_two_bounding_cube<3, tile_coordinate> const& b) {
  return
       a.min(X) < (b.min(X)+b.size(X)) && b.min(X) < (a.min(X)+a.size(X))
    && a.min(Y) < (b.min(Y)+b.size(Y)) && b.min(Y) < (a.min(Y)+a.size(Y))
    && a.min(Z) < (b.min(Z)+b.size(Z)) && b.min(Z) < (a.min(Z)+a.size(Z));
}
inline bool subsumes(tile_bounding_box const& a, power_of_two_bounding_cube<3, tile_coordinate> const& b) {
  return
       a.min(X) <= b.min(X) && (b.min(X)+b.size(X)) <= (a.min(X)+a.size(X))
    && a.min(Y) <= b.min(Y) && (b.min(Y)+b.size(Y)) <= (a.min(Y)+a.size(Y))
    && a.min(Z) <= b.min(Z) && (b.min(Z)+b.size(Z)) <= (a.min(Z)+a.size(Z));
}

inline tile_bounding_box cube_bbox_to_tile_bounding_box(power_of_two_bounding_cube<3, tile_coordinate> const& b) {
  return tile_bounding_box(b.min(), b.size());
}

template<typename Visitor>
void world::visit_collidable_tiles(Visitor&& visitor) {
  using namespace the_decomposition_of_the_world_into_blocks_impl;
  size_t COUNT = 0;

  const octant_number octant = visitor.octant();
  const int octant_xor = ~octant & 7;

  worldblock_trie* trie_node = &worldblock_trie_;
  int trie_sub_idx = 0; // use (trie_sub_idx ^ ~octant) to get the actual idx

  // worldblock-bits in the trie are right-shifted from tile_coordinates.
  // Luckily this means the top bit never varies, so we won't need to set
  // the nonexistent (1<<32) bit in this bitmap.
  tile_coordinate entirely_valid_as_of_worldblock_bit = 0;

  // array [0..8) of 3-bit quantities saying
  // which sibling is the next one.
  // "the end" is indicated by pointing to itself. or last_sub_node ?
  //int first_sub_node;
  //uint32_t trie_iteration_order = ;
  typedef power_of_two_bounding_cube<3, tile_coordinate> bounding_cube;
  //std::cerr << "BEGIN\n";
  while(true) {
    //std::cerr << std::hex << "NODE " << size_t(trie_node) << std::dec << std::endl;
    const int trie_bit = trie_node->bounding_box().size_exponent_in_each_dimension();
    assert(size_t(trie_bit) < sizeof(tile_coordinate)*8);
    bool trie_node_uninteresting_to_look_within = false;
    // Anything in the trie has something collidable inside it, by definition.
    if(entirely_valid_as_of_worldblock_bit == 0) {
      const bounding_cube::loc_type min = {{
        trie_node->bounding_box().min(X) << worldblock_dimension_exp,
        trie_node->bounding_box().min(Y) << worldblock_dimension_exp,
        trie_node->bounding_box().min(Z) << worldblock_dimension_exp
      }};
      const bounding_cube bbox(min, trie_bit + worldblock_dimension_exp);
      const tribool is_here_interesting = visitor.look_here(bbox);
      if(!is_here_interesting) { trie_node_uninteresting_to_look_within = true; }
      if(is_here_interesting) { entirely_valid_as_of_worldblock_bit |= (tile_coordinate(1)<<trie_bit); }
    }
    if(!trie_node_uninteresting_to_look_within) {
      if(worldblock* wb = trie_node->leaf()) {
        if(wb->non_interior_bitmap_large_scale_) {
          ++COUNT;
          worldblock_dimension_type entirely_valid_as_of_tile_coordinate_bit = (!!entirely_valid_as_of_worldblock_bit) << worldblock_dimension_exp;
          #if 0
          //this is redundant with trie check
          if(entirely_valid_as_of_tile_coordinate_bit == 0) {
            const int bit = 4;
            const tribool is_here_interesting = visitor.look_here(bounding_cube(wb->global_position_, bit));
            if(!is_here_interesting) { continue; }
            if(is_here_interesting) { entirely_valid_as_of_tile_coordinate_bit |= (1<<bit); }
          }
          #endif
          //if(entirely_valid_as_of_bit) {results.reserve(results.size() + wb->count_of_non_interior_tiles_here_);}
          size_t idx = 0;
          size_t ll_scale_i = octant_xor << 3;
          const worldblock_dimension_type x_xor = (worldblock_dimension-1) * !LASERCAKE_OCTANT_X_POSITIVE(octant);
          const worldblock_dimension_type y_xor = (worldblock_dimension-1) * !LASERCAKE_OCTANT_Y_POSITIVE(octant);
          const worldblock_dimension_type z_xor = (worldblock_dimension-1) * !LASERCAKE_OCTANT_Z_POSITIVE(octant);
          const worldblock_dimension_type idx_xor = x_xor*worldblock_x_factor + y_xor*worldblock_y_factor + z_xor*worldblock_z_factor;
          vector3<tile_coordinate> global_loc(
            wb->global_position_.x ^ x_xor,
            wb->global_position_.y ^ y_xor,
            wb->global_position_.z ^ z_xor
          );
          do { do { do {
            if(wb->non_interior_bitmap_large_scale_ & (uint64_t(0xff) << ll_scale_i)) {
              if(entirely_valid_as_of_tile_coordinate_bit == 0) { // && more than one of those bits was set
                const int bit = 3;
                const tribool is_here_interesting = visitor.look_here(bounding_cube(global_loc & (~0 << bit), bit));
                if(!is_here_interesting) { goto continue_3; }
                if(is_here_interesting) { entirely_valid_as_of_tile_coordinate_bit |= (1<<bit); }
              }
              {
                size_t large_scale_i = ll_scale_i ^ octant_xor;
                do { do { do {
                  if(wb->non_interior_bitmap_small_scale_[large_scale_i]) {
                    if(entirely_valid_as_of_tile_coordinate_bit == 0) {
                      const int bit = 2;
                      const tribool is_here_interesting = visitor.look_here(bounding_cube(global_loc & (~0 << bit), bit));
                      if(!is_here_interesting) { goto continue_2; }
                      if(is_here_interesting) { entirely_valid_as_of_tile_coordinate_bit |= (1<<bit); }
                    }
                    {
                      size_t ss_scale_i = octant_xor << 3;
                      do { do { do {
                        if(wb->non_interior_bitmap_small_scale_[large_scale_i] & (uint64_t(0xff) << ss_scale_i)) {
                          if(entirely_valid_as_of_tile_coordinate_bit == 0) {
                            const int bit = 1;
                            const tribool is_here_interesting = visitor.look_here(bounding_cube(global_loc & (~0 << bit), bit));
                            if(!is_here_interesting) { goto continue_1; }
                            if(is_here_interesting) { entirely_valid_as_of_tile_coordinate_bit |= (1<<bit); }
                          }
                          {
                            size_t small_scale_i = ss_scale_i ^ octant_xor;
                            do { do { do {
                              if(wb->non_interior_bitmap_small_scale_[large_scale_i] & (uint64_t(1) << small_scale_i)) { // !t.is_interior()) {
                                if(entirely_valid_as_of_tile_coordinate_bit == 0) {
                                  const tribool is_here_interesting = visitor.look_here(bounding_cube(global_loc, 0));
                                  if(!is_here_interesting) { goto continue_0; }
                                }
                                {
                                  const tile_location tloc(global_loc, idx ^ idx_xor, wb);
                                  assert_if_ASSERT_EVERYTHING(!tloc.stuff_at().is_interior());
                                  if(!visitor.collidable_tile(tloc)) {
                                    //std::cerr << "ONE~" << COUNT << ":count.\n";
                                    return;
                                  }
                                }
                                continue_0:;
                              }
                            global_loc.z ^= (1<<0); idx ^= (1<<0); small_scale_i ^= (1<<0); } while(idx & (1<<0));
                            global_loc.y ^= (1<<0); idx ^= (1<<4); small_scale_i ^= (1<<1); } while(idx & (1<<4));
                            global_loc.x ^= (1<<0); idx ^= (1<<8); small_scale_i ^= (1<<2); } while(idx & (1<<8));
                            entirely_valid_as_of_tile_coordinate_bit &= ~(1<<1);
                          }
                          continue_1:;
                        }
                      global_loc.z ^= (1<<1); idx ^= (1<<1); ss_scale_i ^= (1<<3); } while(idx & (1<<1));
                      global_loc.y ^= (1<<1); idx ^= (1<<5); ss_scale_i ^= (1<<4); } while(idx & (1<<5));
                      global_loc.x ^= (1<<1); idx ^= (1<<9); ss_scale_i ^= (1<<5); } while(idx & (1<<9));
                      entirely_valid_as_of_tile_coordinate_bit &= ~(1<<2);
                    }
                    continue_2:;
                  }
                global_loc.z ^= (1<<2); idx ^= (1<<2);  large_scale_i ^= (1<<0); } while(idx & (1<<2));
                global_loc.y ^= (1<<2); idx ^= (1<<6);  large_scale_i ^= (1<<1); } while(idx & (1<<6));
                global_loc.x ^= (1<<2); idx ^= (1<<10); large_scale_i ^= (1<<2);} while(idx & (1<<10));
                entirely_valid_as_of_tile_coordinate_bit &= ~(1<<3);
              }
              continue_3:;
            }
          global_loc.z ^= (1<<3); idx ^= (1<<3);  ll_scale_i ^= (1<<3); } while(idx & (1<<3));
          global_loc.y ^= (1<<3); idx ^= (1<<7);  ll_scale_i ^= (1<<4); } while(idx & (1<<7));
          global_loc.x ^= (1<<3); idx ^= (1<<11); ll_scale_i ^= (1<<5); } while(idx & (1<<11));
          //entirely_valid_as_of_tile_coordinate_bit &= ~(1<<4);
        }
      }

      if(worldblock_trie::sub_nodes_type* sub_nodes = trie_node->sub_nodes()) {
        trie_sub_idx = 0;
        trie_node = &(*sub_nodes)[octant_xor];
        continue;
      }
    }

    //sibling_or_up:
    entirely_valid_as_of_worldblock_bit &= ~(tile_coordinate(1)<<trie_bit);
    //huh, using ++ seems to create a zyx iteration order here, which is
    //a bit undesirable because z is already the shortest dimension currently, TODO
    if(!trie_node->siblings()) {
      //std::cerr << "TWO~" << COUNT << ":count.\n";
      return;
    }
    ++trie_sub_idx;
    while(trie_sub_idx == 8) {
      trie_node = trie_node->parent();
      if(trie_node == nullptr || !trie_node->siblings()) {
        //std::cerr << "THREE~" << COUNT << ":count.\n";
        return;
      }
      const int new_trie_bit = trie_node->bounding_box().size_exponent_in_each_dimension();
      entirely_valid_as_of_worldblock_bit &= ~(tile_coordinate(1)<<new_trie_bit);
      trie_sub_idx = (trie_node - &(*trie_node->siblings())[0]) ^ octant_xor;
      assert(trie_sub_idx >= 0);
      assert(trie_sub_idx < 8);
      ++trie_sub_idx;
    }
    trie_node = &(*trie_node->siblings())[trie_sub_idx ^ octant_xor];
  }
}

#endif
<commit_msg>Fix integer overflow bug.<commit_after>/*

    Copyright Eli Dupree and Isaac Dupree, 2011, 2012

    This file is part of Lasercake.

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

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

    You should have received a copy of the GNU General Public License
    along with Lasercake.  If not, see <http://www.gnu.org/licenses/>.

*/

#ifndef LASERCAKE_TILE_ITERATION_HPP__
#define LASERCAKE_TILE_ITERATION_HPP__

#include <boost/logic/tribool.hpp>

#include "world.hpp"

using boost::tribool;
using boost::indeterminate;

struct boring_visitor {
  // return 'true' = definitely want to see everything within here,
  // 'false' = don't want to see anything within here,
  // 'indeterminate' = keep asking in more detail
  //    ('indeterminate' all the way down *will* call collidable_tile()).
  tribool look_here(power_of_two_bounding_cube<3, tile_coordinate> const&) {
    return true;
  }
  // return 'true' = keep going, 'false' = exit the search
  // giving tile_location an idx member should make just providing the tile_loc fine
  bool collidable_tile(tile_location const&) {
    return true;
  }
  // octant() is only called once, at the beginning of the search.
  octant_number octant()const { return 0; }
};

/*
slow_tile_location
tile_with_neighbors
tile_location could/should have an idx member.

ah the whiles could use idx and idx could be xored in the very inner place
to get the actual idx. i think that is most reasonable. and xyz will be pre-xored.
*/

// For your convenience:
inline bool overlaps(tile_bounding_box const& a, power_of_two_bounding_cube<3, tile_coordinate> const& b) {
  return
       a.min(X) <= b.max(X) && b.min(X) <= a.max(X)
    && a.min(Y) <= b.max(Y) && b.min(Y) <= a.max(Y)
    && a.min(Z) <= b.max(Z) && b.min(Z) <= a.max(Z);
}
inline bool subsumes(tile_bounding_box const& a, power_of_two_bounding_cube<3, tile_coordinate> const& b) {
  return
       a.min(X) <= b.min(X) && b.max(X) <= a.max(X)
    && a.min(Y) <= b.min(Y) && b.max(Y) <= a.max(Y)
    && a.min(Z) <= b.min(Z) && b.max(Z) <= a.max(Z);
}

inline tile_bounding_box cube_bbox_to_tile_bounding_box(power_of_two_bounding_cube<3, tile_coordinate> const& b) {
  return tile_bounding_box(b.min(), b.size());
}

template<typename Visitor>
void world::visit_collidable_tiles(Visitor&& visitor) {
  using namespace the_decomposition_of_the_world_into_blocks_impl;
  size_t COUNT = 0;

  const octant_number octant = visitor.octant();
  const int octant_xor = ~octant & 7;

  worldblock_trie* trie_node = &worldblock_trie_;
  int trie_sub_idx = 0; // use (trie_sub_idx ^ ~octant) to get the actual idx

  // worldblock-bits in the trie are right-shifted from tile_coordinates.
  // Luckily this means the top bit never varies, so we won't need to set
  // the nonexistent (1<<32) bit in this bitmap.
  tile_coordinate entirely_valid_as_of_worldblock_bit = 0;

  // array [0..8) of 3-bit quantities saying
  // which sibling is the next one.
  // "the end" is indicated by pointing to itself. or last_sub_node ?
  //int first_sub_node;
  //uint32_t trie_iteration_order = ;
  typedef power_of_two_bounding_cube<3, tile_coordinate> bounding_cube;
  //std::cerr << "BEGIN\n";
  while(true) {
    //std::cerr << std::hex << "NODE " << size_t(trie_node) << std::dec << std::endl;
    const int trie_bit = trie_node->bounding_box().size_exponent_in_each_dimension();
    assert(size_t(trie_bit) < sizeof(tile_coordinate)*8);
    bool trie_node_uninteresting_to_look_within = false;
    // Anything in the trie has something collidable inside it, by definition.
    if(entirely_valid_as_of_worldblock_bit == 0) {
      const bounding_cube::loc_type min = {{
        trie_node->bounding_box().min(X) << worldblock_dimension_exp,
        trie_node->bounding_box().min(Y) << worldblock_dimension_exp,
        trie_node->bounding_box().min(Z) << worldblock_dimension_exp
      }};
      const bounding_cube bbox(min, trie_bit + worldblock_dimension_exp);
      const tribool is_here_interesting = visitor.look_here(bbox);
      if(!is_here_interesting) { trie_node_uninteresting_to_look_within = true; }
      if(is_here_interesting) { entirely_valid_as_of_worldblock_bit |= (tile_coordinate(1)<<trie_bit); }
    }
    if(!trie_node_uninteresting_to_look_within) {
      if(worldblock* wb = trie_node->leaf()) {
        if(wb->non_interior_bitmap_large_scale_) {
          ++COUNT;
          worldblock_dimension_type entirely_valid_as_of_tile_coordinate_bit = (!!entirely_valid_as_of_worldblock_bit) << worldblock_dimension_exp;
          #if 0
          //this is redundant with trie check
          if(entirely_valid_as_of_tile_coordinate_bit == 0) {
            const int bit = 4;
            const tribool is_here_interesting = visitor.look_here(bounding_cube(wb->global_position_, bit));
            if(!is_here_interesting) { continue; }
            if(is_here_interesting) { entirely_valid_as_of_tile_coordinate_bit |= (1<<bit); }
          }
          #endif
          //if(entirely_valid_as_of_bit) {results.reserve(results.size() + wb->count_of_non_interior_tiles_here_);}
          size_t idx = 0;
          size_t ll_scale_i = octant_xor << 3;
          const worldblock_dimension_type x_xor = (worldblock_dimension-1) * !LASERCAKE_OCTANT_X_POSITIVE(octant);
          const worldblock_dimension_type y_xor = (worldblock_dimension-1) * !LASERCAKE_OCTANT_Y_POSITIVE(octant);
          const worldblock_dimension_type z_xor = (worldblock_dimension-1) * !LASERCAKE_OCTANT_Z_POSITIVE(octant);
          const worldblock_dimension_type idx_xor = x_xor*worldblock_x_factor + y_xor*worldblock_y_factor + z_xor*worldblock_z_factor;
          vector3<tile_coordinate> global_loc(
            wb->global_position_.x ^ x_xor,
            wb->global_position_.y ^ y_xor,
            wb->global_position_.z ^ z_xor
          );
          do { do { do {
            if(wb->non_interior_bitmap_large_scale_ & (uint64_t(0xff) << ll_scale_i)) {
              if(entirely_valid_as_of_tile_coordinate_bit == 0) { // && more than one of those bits was set
                const int bit = 3;
                const tribool is_here_interesting = visitor.look_here(bounding_cube(global_loc & (~0 << bit), bit));
                if(!is_here_interesting) { goto continue_3; }
                if(is_here_interesting) { entirely_valid_as_of_tile_coordinate_bit |= (1<<bit); }
              }
              {
                size_t large_scale_i = ll_scale_i ^ octant_xor;
                do { do { do {
                  if(wb->non_interior_bitmap_small_scale_[large_scale_i]) {
                    if(entirely_valid_as_of_tile_coordinate_bit == 0) {
                      const int bit = 2;
                      const tribool is_here_interesting = visitor.look_here(bounding_cube(global_loc & (~0 << bit), bit));
                      if(!is_here_interesting) { goto continue_2; }
                      if(is_here_interesting) { entirely_valid_as_of_tile_coordinate_bit |= (1<<bit); }
                    }
                    {
                      size_t ss_scale_i = octant_xor << 3;
                      do { do { do {
                        if(wb->non_interior_bitmap_small_scale_[large_scale_i] & (uint64_t(0xff) << ss_scale_i)) {
                          if(entirely_valid_as_of_tile_coordinate_bit == 0) {
                            const int bit = 1;
                            const tribool is_here_interesting = visitor.look_here(bounding_cube(global_loc & (~0 << bit), bit));
                            if(!is_here_interesting) { goto continue_1; }
                            if(is_here_interesting) { entirely_valid_as_of_tile_coordinate_bit |= (1<<bit); }
                          }
                          {
                            size_t small_scale_i = ss_scale_i ^ octant_xor;
                            do { do { do {
                              if(wb->non_interior_bitmap_small_scale_[large_scale_i] & (uint64_t(1) << small_scale_i)) { // !t.is_interior()) {
                                if(entirely_valid_as_of_tile_coordinate_bit == 0) {
                                  const tribool is_here_interesting = visitor.look_here(bounding_cube(global_loc, 0));
                                  if(!is_here_interesting) { goto continue_0; }
                                }
                                {
                                  const tile_location tloc(global_loc, idx ^ idx_xor, wb);
                                  assert_if_ASSERT_EVERYTHING(!tloc.stuff_at().is_interior());
                                  if(!visitor.collidable_tile(tloc)) {
                                    //std::cerr << "ONE~" << COUNT << ":count.\n";
                                    return;
                                  }
                                }
                                continue_0:;
                              }
                            global_loc.z ^= (1<<0); idx ^= (1<<0); small_scale_i ^= (1<<0); } while(idx & (1<<0));
                            global_loc.y ^= (1<<0); idx ^= (1<<4); small_scale_i ^= (1<<1); } while(idx & (1<<4));
                            global_loc.x ^= (1<<0); idx ^= (1<<8); small_scale_i ^= (1<<2); } while(idx & (1<<8));
                            entirely_valid_as_of_tile_coordinate_bit &= ~(1<<1);
                          }
                          continue_1:;
                        }
                      global_loc.z ^= (1<<1); idx ^= (1<<1); ss_scale_i ^= (1<<3); } while(idx & (1<<1));
                      global_loc.y ^= (1<<1); idx ^= (1<<5); ss_scale_i ^= (1<<4); } while(idx & (1<<5));
                      global_loc.x ^= (1<<1); idx ^= (1<<9); ss_scale_i ^= (1<<5); } while(idx & (1<<9));
                      entirely_valid_as_of_tile_coordinate_bit &= ~(1<<2);
                    }
                    continue_2:;
                  }
                global_loc.z ^= (1<<2); idx ^= (1<<2);  large_scale_i ^= (1<<0); } while(idx & (1<<2));
                global_loc.y ^= (1<<2); idx ^= (1<<6);  large_scale_i ^= (1<<1); } while(idx & (1<<6));
                global_loc.x ^= (1<<2); idx ^= (1<<10); large_scale_i ^= (1<<2);} while(idx & (1<<10));
                entirely_valid_as_of_tile_coordinate_bit &= ~(1<<3);
              }
              continue_3:;
            }
          global_loc.z ^= (1<<3); idx ^= (1<<3);  ll_scale_i ^= (1<<3); } while(idx & (1<<3));
          global_loc.y ^= (1<<3); idx ^= (1<<7);  ll_scale_i ^= (1<<4); } while(idx & (1<<7));
          global_loc.x ^= (1<<3); idx ^= (1<<11); ll_scale_i ^= (1<<5); } while(idx & (1<<11));
          //entirely_valid_as_of_tile_coordinate_bit &= ~(1<<4);
        }
      }

      if(worldblock_trie::sub_nodes_type* sub_nodes = trie_node->sub_nodes()) {
        trie_sub_idx = 0;
        trie_node = &(*sub_nodes)[octant_xor];
        continue;
      }
    }

    //sibling_or_up:
    entirely_valid_as_of_worldblock_bit &= ~(tile_coordinate(1)<<trie_bit);
    //huh, using ++ seems to create a zyx iteration order here, which is
    //a bit undesirable because z is already the shortest dimension currently, TODO
    if(!trie_node->siblings()) {
      //std::cerr << "TWO~" << COUNT << ":count.\n";
      return;
    }
    ++trie_sub_idx;
    while(trie_sub_idx == 8) {
      trie_node = trie_node->parent();
      if(trie_node == nullptr || !trie_node->siblings()) {
        //std::cerr << "THREE~" << COUNT << ":count.\n";
        return;
      }
      const int new_trie_bit = trie_node->bounding_box().size_exponent_in_each_dimension();
      entirely_valid_as_of_worldblock_bit &= ~(tile_coordinate(1)<<new_trie_bit);
      trie_sub_idx = (trie_node - &(*trie_node->siblings())[0]) ^ octant_xor;
      assert(trie_sub_idx >= 0);
      assert(trie_sub_idx < 8);
      ++trie_sub_idx;
    }
    trie_node = &(*trie_node->siblings())[trie_sub_idx ^ octant_xor];
  }
}

#endif
<|endoftext|>


<commit_before>// Virvo - Virtual Reality Volume Rendering
// Copyright (C) 2010 University of Cologne
// Contact: Jurgen P. Schulze, jschulze@ucsd.edu
//
// This file is part of Virvo.
//
// Virvo 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 (see license.txt); if not, write to the
// Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

#ifdef HAVE_CONFIG_H
#include "vvconfig.h"
#endif

#if HAVE_NORM

#include <iostream>
#include <cstring>

#include "vvmulticast.h"

using namespace std;

int main(int argc, char** argv)
{
  // don't forget arguments
  if(argc < 2)
  {
    cout << "Start with -sender text or -receiver" << endl;
    return 0;
  }

  // Sender
  if(strcmp("-sender", argv[1])== 0)
  {
    cout << "Sender-Mode" << endl;
    vvMulticast* foo = new vvMulticast("224.1.2.3", 50096, vvMulticast::VV_SENDER);

    string footext = string(argv[2]);
    footext.resize(200, ' ');

    foo->write(reinterpret_cast<const unsigned char*>(footext.c_str()), 500, 3.0);

    return 0;
  }

  // Receiver, start with -receiver
  if(strcmp("-receiver", argv[1])== 0)
  {
    cout << "Receiver-Mode" << endl;
    vvMulticast* bar = new vvMulticast("224.1.2.3", 50096, vvMulticast::VV_RECEIVER);
    unsigned char* bartext;
    bar->read(200, bartext);
    std::cout << "Received: " << reinterpret_cast<char*>(bartext) << std::endl;
    return 0;
  }

  cout << "Nothing done..." << endl;
  return 1;
}

#endif

/*

Build-Notes:

build with libraries: virvo, norm, Protokit

Attention!
If Protokit and Norm are build seperately, then use libProto.a instead of libProtokit.a! (both libs are build automatically)
If Protokit is build together with norm (included subdirectory) then use libProtokit.a (only this lib is build)
(Same thing for windows and .dll's)
The reason for this issue is, that norm-developers use an older/different version of Protokit and are too lazy to fix this.
Norm is generally build with the old version instead.

// g++ vvmulticasttest.cpp -I/raid/home/sdelisav/deskvox/virvo/virvo -I/raid/home/sdelisav/Desktop/norm-1.4b3/common -L /raid/home/sdelisav/Desktop/norm-1.4b3/unix/ -I /raid/home/sdelisav/deskvox/qtcreator-build/virvo/ -L /raid/home/sdelisav/deskvox/qtcreator-build/virvo/virvo/ -l virvo -l norm -L /raid/home/sdelisav/Desktop/norm-1.4b3/protolib/unix/ -l Protokit -pthread -DHAVE_NORM

*/

<commit_msg>prevent crash when parameter forgotten in normtest<commit_after>// Virvo - Virtual Reality Volume Rendering
// Copyright (C) 2010 University of Cologne
// Contact: Jurgen P. Schulze, jschulze@ucsd.edu
//
// This file is part of Virvo.
//
// Virvo 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 (see license.txt); if not, write to the
// Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

#ifdef HAVE_CONFIG_H
#include "vvconfig.h"
#endif

#if HAVE_NORM

#include <iostream>
#include <cstring>

#include "vvmulticast.h"

using namespace std;

int main(int argc, char** argv)
{
  // don't forget arguments
  if(argc < 2)
  {
    cout << "Start with -sender text or -receiver" << endl;
    return 0;
  }

  // Sender
  if(strcmp("-sender", argv[1])== 0)
  {
    cout << "Sender-Mode" << endl;
    vvMulticast* foo = new vvMulticast("224.1.2.3", 50096, vvMulticast::VV_SENDER);

    if(NULL == argv[2])
    {
      cout << "Please type in a text to send and try again!" << endl;
      return 1;
    }
    string footext = string(argv[2]);
    footext.resize(200, ' ');

    foo->write(reinterpret_cast<const unsigned char*>(footext.c_str()), 500, 3.0);

    return 0;
  }

  // Receiver, start with -receiver
  if(strcmp("-receiver", argv[1])== 0)
  {
    cout << "Receiver-Mode" << endl;
    vvMulticast* bar = new vvMulticast("224.1.2.3", 50096, vvMulticast::VV_RECEIVER);
    unsigned char* bartext;
    bar->read(200, bartext);
    std::cout << "Received: " << reinterpret_cast<char*>(bartext) << std::endl;
    return 0;
  }

  cout << "Nothing done..." << endl;
  return 1;
}

#endif

/*

Build-Notes:

build with libraries: virvo, norm, Protokit

Attention!
If Protokit and Norm are build seperately, then use libProto.a instead of libProtokit.a! (both libs are build automatically)
If Protokit is build together with norm (included subdirectory) then use libProtokit.a (only this lib is build)
(Same thing for windows and .dll's)
The reason for this issue is, that norm-developers use an older/different version of Protokit and are too lazy to fix this.
Norm is generally build with the old version instead.

// g++ vvmulticasttest.cpp -I/raid/home/sdelisav/deskvox/virvo/virvo -I/raid/home/sdelisav/Desktop/norm-1.4b3/common -L /raid/home/sdelisav/Desktop/norm-1.4b3/unix/ -I /raid/home/sdelisav/deskvox/qtcreator-build/virvo/ -L /raid/home/sdelisav/deskvox/qtcreator-build/virvo/virvo/ -l virvo -l norm -L /raid/home/sdelisav/Desktop/norm-1.4b3/protolib/unix/ -l Protokit -pthread -DHAVE_NORM

*/

<|endoftext|>


<commit_before>#include "voxblox/simulation/sphere_simulator.h"

#include <cmath>
#include <memory>
#include <random>

#include <algorithm>
#include <mutex>
#include <queue>
#include <thread>

#include <glog/logging.h>

namespace voxblox {
namespace sphere_sim {

void createSphere(const double mean, const double variance,
                  const double radius_m, const size_t num_points,
                  Pointcloud* points_3D) {
  CHECK_NOTNULL(points_3D)->clear();

  typedef std::random_device RandomDevice;
  typedef std::mt19937 Mt19937Distribution;
  typedef std::normal_distribution<double> NormalDistribution;

  // Distributions
  RandomDevice random_device;
  Mt19937Distribution mt_distribution(random_device());
  NormalDistribution normal_distribution(mean, variance);

  int n = num_points - 2;      // 1 for top and bottom point
  int s = round(sqrt(n - 1));  // sphere slices
  double step = 2 * radius_m / (static_cast<double>(s) + 1);

  {
    // top point
    Point point;
    point.x() = 0.0;
    point.y() = 0.0;
    point.z() = radius_m;
    points_3D->push_back(point);
  }

  double SumA = 0;
  for (int it = 1; it <= s; ++it) {
    double z = radius_m - static_cast<double>(it) * step;
    SumA += 2 * M_PI * sqrt(radius_m * radius_m - z * z);
  }

  for (int it = 1; it <= s; ++it) {
    double zi = radius_m - static_cast<double>(it) * step;
    double ri = sqrt(radius_m * radius_m - zi * zi);
    double Ai = 2 * M_PI * ri;
    int ni = round(n * Ai / SumA);
    double stepi = 2 * M_PI / static_cast<double>(ni);

    for (int it2 = 0; it2 < ni; ++it2) {
      double a;
      if (it % 2 == 0)
        a = static_cast<double>(it2) * stepi;
      else
        a = static_cast<double>((it2 + 0.5)) * stepi;

      double x, y, z;

      x = ri * cos(a) + normal_distribution(mt_distribution);
      y = ri * sin(a) + normal_distribution(mt_distribution);
      z = zi + normal_distribution(mt_distribution);

      Point point;
      point.x() = x;
      point.y() = y;
      point.z() = z;
      points_3D->push_back(point);
    }
  }

  {
    Point point;
    point.x() = 0.0;
    point.y() = 0.0;
    point.z() = -radius_m;
    points_3D->push_back(point);
  }

  LOG(INFO) << "Created sphere with " << points_3D->size() << " points.";
}

}  // namespace sphere_sim
}  // namespace voxblox
<commit_msg>rm output<commit_after>#include "voxblox/simulation/sphere_simulator.h"

#include <cmath>
#include <memory>
#include <random>

#include <algorithm>
#include <mutex>
#include <queue>
#include <thread>

#include <glog/logging.h>

namespace voxblox {
namespace sphere_sim {

void createSphere(const double mean, const double variance,
                  const double radius_m, const size_t num_points,
                  Pointcloud* points_3D) {
  CHECK_NOTNULL(points_3D)->clear();

  typedef std::random_device RandomDevice;
  typedef std::mt19937 Mt19937Distribution;
  typedef std::normal_distribution<double> NormalDistribution;

  // Distributions
  RandomDevice random_device;
  Mt19937Distribution mt_distribution(random_device());
  NormalDistribution normal_distribution(mean, variance);

  int n = num_points - 2;      // 1 for top and bottom point
  int s = round(sqrt(n - 1));  // sphere slices
  double step = 2 * radius_m / (static_cast<double>(s) + 1);

  {
    // top point
    Point point;
    point.x() = 0.0;
    point.y() = 0.0;
    point.z() = radius_m;
    points_3D->push_back(point);
  }

  double SumA = 0;
  for (int it = 1; it <= s; ++it) {
    double z = radius_m - static_cast<double>(it) * step;
    SumA += 2 * M_PI * sqrt(radius_m * radius_m - z * z);
  }

  for (int it = 1; it <= s; ++it) {
    double zi = radius_m - static_cast<double>(it) * step;
    double ri = sqrt(radius_m * radius_m - zi * zi);
    double Ai = 2 * M_PI * ri;
    int ni = round(n * Ai / SumA);
    double stepi = 2 * M_PI / static_cast<double>(ni);

    for (int it2 = 0; it2 < ni; ++it2) {
      double a;
      if (it % 2 == 0)
        a = static_cast<double>(it2) * stepi;
      else
        a = static_cast<double>((it2 + 0.5)) * stepi;

      double x, y, z;

      x = ri * cos(a) + normal_distribution(mt_distribution);
      y = ri * sin(a) + normal_distribution(mt_distribution);
      z = zi + normal_distribution(mt_distribution);

      Point point;
      point.x() = x;
      point.y() = y;
      point.z() = z;
      points_3D->push_back(point);
    }
  }

  {
    Point point;
    point.x() = 0.0;
    point.y() = 0.0;
    point.z() = -radius_m;
    points_3D->push_back(point);
  }
}

}  // namespace sphere_sim
}  // namespace voxblox
<|endoftext|>


<commit_before>#pragma once
//=====================================================================//
/*!	@file
	@brief	MAX7219 ドライバー @n
			LED Display Driver (VCC: 4V to 5.5V)
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2017, 2021 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include <cstdint>

namespace chip {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  MAX7219 テンプレートクラス
		@param[in]	SPI		SPI クラス（出力のみ）
		@param[in]	SELECT	デバイス選択
		@param[in]	CHAIN	デージーチェーン数（通常１）
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <class SPI, class SELECT, uint8_t CHAIN = 1>
	class MAX7219 {

		SPI&		spi_;

		uint8_t		fb_[8 * CHAIN];

		enum class COMMAND : uint8_t {
			NO_OP        = 0x00,
			DIGIT_0      = 0x01,
			DIGIT_1      = 0x02,
			DIGIT_2      = 0x03,
			DIGIT_3      = 0x04,
			DIGIT_4      = 0x05,
			DIGIT_5      = 0x06,
			DIGIT_6      = 0x07,
			DIGIT_7      = 0x08,
			DECODE_MODE  = 0x09,
			INTENSITY    = 0x0A,
			SCAN_LIMIT   = 0x0B,
			SHUTDOWN     = 0x0C,
			DISPLAY_TEST = 0x0F,
		};

		// MAX7212 MSB first, 2 bytes
		void out_(COMMAND cmd, uint8_t dat) noexcept
		{
			SELECT::P = 0;
			uint8_t tmp[2];
			tmp[0] = static_cast<uint8_t>(cmd);
			tmp[1] = dat;
			for(uint8_t i = 0; i < CHAIN; ++i) {
				spi_.send(tmp, 2);
			}
			SELECT::P = 1;  // load
		}

		void outp_(COMMAND cmd, const uint8_t* ptr) noexcept
		{
			SELECT::P = 0;
			uint8_t tmp[2];
			tmp[0] = static_cast<uint8_t>(cmd);
			for(uint8_t i = 0; i < CHAIN; ++i) {
				tmp[1] = *ptr++;
				spi_.send(tmp, 2);
			}
			SELECT::P = 1;  // load
		}

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief	コンストラクター
			@param[in]	spi	SPI クラスを参照で渡す
		 */
		//-----------------------------------------------------------------//
		MAX7219(SPI& spi) noexcept : spi_(spi), fb_{0} { }

		//-----------------------------------------------------------------//
		/*!
			@brief	開始
			@return エラーなら「false」を返す
		 */
		//-----------------------------------------------------------------//
		bool start() noexcept
		{
			SELECT::DIR = 1;  // output;
			SELECT::PU  = 0;  // pull-up disable
			SELECT::P = 1;    // LOAD = H

			out_(COMMAND::NO_OP, 0x00);  // ダミー（NOP)
			out_(COMMAND::DISPLAY_TEST, 0x00);  // TEST off
			out_(COMMAND::SHUTDOWN, 0x01);  // ノーマル・モード
			out_(COMMAND::DECODE_MODE, 0x00);  // デコード・モード
			out_(COMMAND::SCAN_LIMIT, 7);  // 表示桁設定

			set_intensity(0);  // 輝度（最低）

			service();

			return true;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief 輝度の設定
			@param[in]	inten	輝度値（最小：０、最大：１５）
			@return エラー（初期化不良）なら「false」
		 */
		//-----------------------------------------------------------------//
		bool set_intensity(uint8_t inten) noexcept
		{
			out_(COMMAND::INTENSITY, inten);
			return true;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief サービス
		 */
		//-----------------------------------------------------------------//
		void service() noexcept
		{
			auto cmd = COMMAND::DIGIT_0;
			uint8_t idx = 0;
			for(uint8_t j = 0; j < 8; ++j) {
				outp_(cmd, &fb_[idx]);
				idx += CHAIN;
				cmd = static_cast<COMMAND>(static_cast<uint8_t>(cmd) + 1);
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief 値の設定
			@param[in]	idx	インデックス（０～７）
			@param[in]	dat	データ
		 */
		//-----------------------------------------------------------------//
		void set(uint8_t idx, uint8_t dat) noexcept
		{
			if(idx >= (8 * CHAIN)) return;
			fb_[idx] = dat;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief キャラクターの設定
			@param[in]	idx	インデックス（０～７）
			@param[in]	cha	キャラクターコード
			@param[in]	dp	小数点
		 */
		//-----------------------------------------------------------------//
		void set_cha(uint8_t idx, char cha, bool dp = false) noexcept {
			uint8_t d = 0;
			switch(cha) {
			case ' ':
				break;
			case '-':
				d = 0b0000001;
				break;
			case '_':
				d = 0b0001000;
				break;
			case '~':
				d = 0b1000000;
				break;
			case '0':
				d = 0b1111110;
				break;
			case '1':
				d = 0b0110000;
				break;
			case '2':
				d = 0b1101101;
				break;
			case '3':
				d = 0b1111001;
				break;
			case '4':
				d = 0b0110011;
				break;
			case '5':
				d = 0b1011011;
				break;
			case '6':
				d = 0b1011111;
				break;
			case '7':
				d = 0b1110000;
				break;
			case '8':
				d = 0b1111111;
				break;
			case '9':
				d = 0b1111011;
				break;
			case 'A':
			case 'a':
				d = 0b1110111;
				break;
			case 'B':
			case 'b':
				d = 0b0011111;
				break;
			case 'C':
				d = 0b1001110;
				break;
			case 'c':
				d = 0b0001101;
				break;
			case 'D':
			case 'd':
				d = 0b0111101;
				break;
			case 'E':
			case 'e':
				d = 0b1001111;
				break;
			case 'F':
			case 'f':
				d = 0b1000111;
				break;
			case 'G':
			case 'g':
				d = 0b1011110;
				break;
			case 'H':
			case 'h':
				d = 0b0010111;
				break;
			case 'I':
			case 'i':
				d = 0b0000100;
				break;
			case 'J':
			case 'j':
				d = 0b0111100;
				break;
			case 'K':
			case 'k':
				d = 0b1010111;
				break;
			case 'L':
			case 'l':
				d = 0b0001110;
				break;
			case 'M':
			case 'm':
				d = 0b1110110;
				break;
			case 'N':
			case 'n':
				d = 0b0010101;
				break;
			case 'O':
			case 'o':
				d = 0b0011101;
				break;
			case 'P':
			case 'p':
				d = 0b1100111;
				break;
			case 'Q':
			case 'q':
				d = 0b1101111;
				break;
			case 'R':
			case 'r':
				d = 0b0000101;
				break;
			case 'S':
			case 's':
				d = 0b0011011;
				break;
			case 'T':
			case 't':
				d = 0b0001111;
				break;
			case 'U':
			case 'u':
				d = 0b0011100;
				break;
			case 'V':
			case 'v':
				d = 0b0111110;
				break;
			case 'W':
			case 'w':
				d = 0b0111111;
				break;
			case 'X':
			case 'x':
				d = 0b0110111;
				break;
			case 'Y':
			case 'y':
				d = 0b0111011;
				break;
			case 'Z':
			case 'z':
				d = 0b1101100;
				break;
			default:
				break;
			}
			if(dp) d |= 0x80;
			set(idx, d);
		}

		//-----------------------------------------------------------------//
		/*!
			@brief フレームバッファの参照
			@return フレームバッファ
		 */
		//-----------------------------------------------------------------//
		uint8_t& at(uint8_t idx) noexcept { return fb_[idx]; }
	};
}
<commit_msg>Update: cleanup address for module, add operator<commit_after>#pragma once
//=========================================================================//
/*!	@file
	@brief	MAX7219 ドライバー @n
			LED Display Driver (VCC: 4V to 5.5V) @n
			※輝度を大きく設定すると、消費電流が大きくなるので注意が必要。 @n
			※初期化前は、レジスター値が不定なので、大きな消費電流が流れる恐れがある @n
			※デージーチェイン接続した場合のバッファ配置に注意
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2017, 2021 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=========================================================================//
#include <cstdint>

namespace chip {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  MAX7219 テンプレートクラス
		@param[in]	SPI		SPI クラス（出力のみ）
		@param[in]	SELECT	デバイス選択
		@param[in]	CHAIN	デージーチェーン数（通常１）
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <class SPI, class SELECT, uint8_t CHAIN = 1>
	class MAX7219 {

		SPI&		spi_;

		uint8_t		fb_[8 * CHAIN];

		enum class COMMAND : uint8_t {
			NO_OP        = 0x00,
			DIGIT_0      = 0x01,
			DIGIT_1      = 0x02,
			DIGIT_2      = 0x03,
			DIGIT_3      = 0x04,
			DIGIT_4      = 0x05,
			DIGIT_5      = 0x06,
			DIGIT_6      = 0x07,
			DIGIT_7      = 0x08,
			DECODE_MODE  = 0x09,
			INTENSITY    = 0x0A,
			SCAN_LIMIT   = 0x0B,
			SHUTDOWN     = 0x0C,
			DISPLAY_TEST = 0x0F,
		};

		// MAX7212 MSB first, 2 bytes
		void out_(COMMAND cmd, uint8_t dat) noexcept
		{
			SELECT::P = 0;
			uint8_t tmp[2];
			tmp[0] = static_cast<uint8_t>(cmd);
			tmp[1] = dat;
			for(uint8_t i = 0; i < CHAIN; ++i) {
				spi_.send(tmp, 2);
			}
			SELECT::P = 1;  // load
		}

		void out_digit_(COMMAND cmd, uint8_t idx) noexcept
		{
			SELECT::P = 0;
			uint8_t tmp[2];
			tmp[0] = static_cast<uint8_t>(cmd);
			for(uint8_t i = 0; i < CHAIN; ++i) {
				tmp[1] = fb_[8 * (CHAIN - i - 1) + idx];
				spi_.send(tmp, 2);
			}
			SELECT::P = 1;  // load
		}

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief	コンストラクター
			@param[in]	spi	SPI クラスを参照で渡す
		 */
		//-----------------------------------------------------------------//
		MAX7219(SPI& spi) noexcept : spi_(spi), fb_{ 0 } { }

		//-----------------------------------------------------------------//
		/*!
			@brief	開始
			@return エラーなら「false」を返す
		 */
		//-----------------------------------------------------------------//
		bool start() noexcept
		{
			SELECT::DIR = 1;  // output;
			SELECT::PU  = 0;  // pull-up disable
			SELECT::P = 1;    // LOAD = H

			out_(COMMAND::NO_OP, 0x00);  // ダミー（NOP)
			out_(COMMAND::DISPLAY_TEST, 0x00);  // TEST off
			out_(COMMAND::SHUTDOWN, 0x01);  // ノーマル・モード
			out_(COMMAND::DECODE_MODE, 0x00);  // デコード・モード
			out_(COMMAND::SCAN_LIMIT, 7);  // 表示桁設定

			set_intensity(0);  // 輝度（最低）

			service();

			return true;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief 輝度の設定
			@param[in]	inten	輝度値（最小：０、最大：１５）
			@return エラー（初期化不良）なら「false」
		 */
		//-----------------------------------------------------------------//
		bool set_intensity(uint8_t inten) noexcept
		{
			out_(COMMAND::INTENSITY, inten);
			return true;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief サービス @n
				   フレームバッファを転送
		 */
		//-----------------------------------------------------------------//
		void service() noexcept
		{
			auto cmd = COMMAND::DIGIT_0;
			for(uint8_t i = 0; i < 8; ++i) {
				out_digit_(cmd, i);
				cmd = static_cast<COMMAND>(static_cast<uint8_t>(cmd) + 1);
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief 値の設定
			@param[in]	idx	インデックス
			@param[in]	val	値
		 */
		//-----------------------------------------------------------------//
		void set(uint8_t idx, uint8_t val) noexcept
		{
			if(idx >= (CHAIN * 8)) return;

			fb_[idx] = val;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief 値の取得
			@param[in]	idx	インデックス
			@return 値
		 */
		//-----------------------------------------------------------------//
		uint8_t get(uint8_t idx) const noexcept
		{
			if(idx >= (CHAIN * 8)) return 0;

			return fb_[idx];
		}

		//-----------------------------------------------------------------//
		/*!
			@brief キャラクターの設定
			@param[in]	idx	インデックス
			@param[in]	cha	キャラクターコード
			@param[in]	dp	小数点
		 */
		//-----------------------------------------------------------------//
		void set_cha(uint8_t idx, char cha, bool dp = false) noexcept {
			uint8_t d = 0;
			switch(cha) {
			case ' ':
				break;
			case '-':
				d = 0b0000001;
				break;
			case '_':
				d = 0b0001000;
				break;
			case '~':
				d = 0b1000000;
				break;
			case '0':
				d = 0b1111110;
				break;
			case '1':
				d = 0b0110000;
				break;
			case '2':
				d = 0b1101101;
				break;
			case '3':
				d = 0b1111001;
				break;
			case '4':
				d = 0b0110011;
				break;
			case '5':
				d = 0b1011011;
				break;
			case '6':
				d = 0b1011111;
				break;
			case '7':
				d = 0b1110000;
				break;
			case '8':
				d = 0b1111111;
				break;
			case '9':
				d = 0b1111011;
				break;
			case 'A':
			case 'a':
				d = 0b1110111;
				break;
			case 'B':
			case 'b':
				d = 0b0011111;
				break;
			case 'C':
				d = 0b1001110;
				break;
			case 'c':
				d = 0b0001101;
				break;
			case 'D':
			case 'd':
				d = 0b0111101;
				break;
			case 'E':
			case 'e':
				d = 0b1001111;
				break;
			case 'F':
			case 'f':
				d = 0b1000111;
				break;
			case 'G':
			case 'g':
				d = 0b1011110;
				break;
			case 'H':
			case 'h':
				d = 0b0010111;
				break;
			case 'I':
			case 'i':
				d = 0b0000100;
				break;
			case 'J':
			case 'j':
				d = 0b0111100;
				break;
			case 'K':
			case 'k':
				d = 0b1010111;
				break;
			case 'L':
			case 'l':
				d = 0b0001110;
				break;
			case 'M':
			case 'm':
				d = 0b1110110;
				break;
			case 'N':
			case 'n':
				d = 0b0010101;
				break;
			case 'O':
			case 'o':
				d = 0b0011101;
				break;
			case 'P':
			case 'p':
				d = 0b1100111;
				break;
			case 'Q':
			case 'q':
				d = 0b1101111;
				break;
			case 'R':
			case 'r':
				d = 0b0000101;
				break;
			case 'S':
			case 's':
				d = 0b0011011;
				break;
			case 'T':
			case 't':
				d = 0b0001111;
				break;
			case 'U':
			case 'u':
				d = 0b0011100;
				break;
			case 'V':
			case 'v':
				d = 0b0111110;
				break;
			case 'W':
			case 'w':
				d = 0b0111111;
				break;
			case 'X':
			case 'x':
				d = 0b0110111;
				break;
			case 'Y':
			case 'y':
				d = 0b0111011;
				break;
			case 'Z':
			case 'z':
				d = 0b1101100;
				break;
			default:
				break;
			}
			if(dp) d |= 0x80;
			set(idx, d);
		}

		//-----------------------------------------------------------------//
		/*!
			@brief シフト、バッファ先頭
			@param[in]  fill    埋めるデータ
			@return シフトによりあふれたデータ
		 */
		//-----------------------------------------------------------------//
		uint8_t shift_top(uint8_t fill = 0) noexcept
		{
			uint8_t full = fb_[0];
			std::memmove(&fb_[1], &fb_[0], CHAIN * 8 - 1);
			fb_[0] = fill;
			return full;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief シフト、バッファ終端
			@param[in]  fill    埋めるデータ
			@return シフトによりあふれたデータ
		 */
		//-----------------------------------------------------------------//
		uint8_t shift_end(uint8_t fill = 0) noexcept
		{
			uint8_t full = fb_[CHAIN * 8 - 1];
			std::memmove(&fb_[0], &fb_[1], CHAIN * 8 - 1);
			fb_[CHAIN * 8 - 1] = fill;
			return full;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief [] オペレーター
			@return 参照値
		 */
		//-----------------------------------------------------------------//
		uint8_t& operator [] (uint8_t idx)
		{
			if(idx >= (CHAIN * 8)) {
				idx %= CHAIN * 8;
			}
			return fb_[idx];
		}
	};
}
<|endoftext|>


<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "views/view.h"

#include <atlcomcli.h>
//  Necessary to define oleacc GUID's used in window_win.cc.
#include <initguid.h>
#include <oleacc.h>

#include "base/string_util.h"
#include "ui/base/dragdrop/drag_drop_types.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/path.h"
#include "views/accessibility/native_view_accessibility_win.h"
#include "views/border.h"
#include "views/views_delegate.h"
#include "views/widget/root_view.h"
#include "views/widget/widget.h"

namespace views {

gfx::NativeViewAccessible View::GetNativeViewAccessible() {
  if (!native_view_accessibility_win_.get())
    native_view_accessibility_win_ =
        NativeViewAccessibilityWin::Create(this);
  return native_view_accessibility_win_.get();
}

int View::GetHorizontalDragThreshold() {
  static int threshold = -1;
  if (threshold == -1)
    threshold = GetSystemMetrics(SM_CXDRAG) / 2;
  return threshold;
}

int View::GetVerticalDragThreshold() {
  static int threshold = -1;
  if (threshold == -1)
    threshold = GetSystemMetrics(SM_CYDRAG) / 2;
  return threshold;
}

}  // namespace views
<commit_msg>views: Remove a bunch of unneeded includes from view_win.cc<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "views/view.h"

// Necessary to define oleacc GUID's.
#include <initguid.h>
#include <oleacc.h>
#include <windows.h>

#include "views/accessibility/native_view_accessibility_win.h"

namespace views {

gfx::NativeViewAccessible View::GetNativeViewAccessible() {
  if (!native_view_accessibility_win_.get())
    native_view_accessibility_win_ = NativeViewAccessibilityWin::Create(this);
  return native_view_accessibility_win_.get();
}

int View::GetHorizontalDragThreshold() {
  static int threshold = -1;
  if (threshold == -1)
    threshold = GetSystemMetrics(SM_CXDRAG) / 2;
  return threshold;
}

int View::GetVerticalDragThreshold() {
  static int threshold = -1;
  if (threshold == -1)
    threshold = GetSystemMetrics(SM_CYDRAG) / 2;
  return threshold;
}

}  // namespace views
<|endoftext|>